diff options
90 files changed, 1118 insertions, 990 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 98ac0d7..c6d5fee 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -199,15 +199,16 @@ tcp_early_retrans - INTEGER Default: 2 tcp_ecn - INTEGER - Enable Explicit Congestion Notification (ECN) in TCP. ECN is only - used when both ends of the TCP flow support it. It is useful to - avoid losses due to congestion (when the bottleneck router supports - ECN). + Control use of Explicit Congestion Notification (ECN) by TCP. + ECN is used only when both ends of the TCP connection indicate + support for it. This feature is useful in avoiding losses due + to congestion by allowing supporting routers to signal + congestion before having to drop packets. Possible values are: - 0 disable ECN - 1 ECN enabled - 2 Only server-side ECN enabled. If the other end does - not support ECN, behavior is like with ECN disabled. + 0 Disable ECN. Neither initiate nor accept ECN. + 1 Always request ECN on outgoing connection attempts. + 2 Enable ECN when requested by incomming connections + but do not request ECN on outgoing connections. Default: 2 tcp_fack - BOOLEAN @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 7 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = -rc7 NAME = Terrified Chipmunk # *DOCUMENTATION* diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 90275f0..49ca86e 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -652,6 +652,15 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size mov pc, lr ENDPROC(__setup_mmu) +@ Enable unaligned access on v6, to allow better code generation +@ for the decompressor C code: +__armv6_mmu_cache_on: + mrc p15, 0, r0, c1, c0, 0 @ read SCTLR + bic r0, r0, #2 @ A (no unaligned access fault) + orr r0, r0, #1 << 22 @ U (v6 unaligned access model) + mcr p15, 0, r0, c1, c0, 0 @ write SCTLR + b __armv4_mmu_cache_on + __arm926ejs_mmu_cache_on: #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH mov r0, #4 @ put dcache in WT mode @@ -694,6 +703,9 @@ __armv7_mmu_cache_on: bic r0, r0, #1 << 28 @ clear SCTLR.TRE orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement orr r0, r0, #0x003c @ write buffer + bic r0, r0, #2 @ A (no unaligned access fault) + orr r0, r0, #1 << 22 @ U (v6 unaligned access model) + @ (needed for ARM1176) #ifdef CONFIG_MMU #ifdef CONFIG_CPU_ENDIAN_BE8 orr r0, r0, #1 << 25 @ big-endian page tables @@ -914,7 +926,7 @@ proc_types: .word 0x0007b000 @ ARMv6 .word 0x000ff000 - W(b) __armv4_mmu_cache_on + W(b) __armv6_mmu_cache_on W(b) __armv4_mmu_cache_off W(b) __armv6_mmu_cache_flush diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 86b8b48..09c5233 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -89,7 +89,7 @@ ENTRY(cpu_v6_dcache_clean_area) mov pc, lr /* - * cpu_arm926_switch_mm(pgd_phys, tsk) + * cpu_v6_switch_mm(pgd_phys, tsk) * * Set the translation table base pointer to be pgd_phys * diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index a53f8ec..290dc6a 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -79,7 +79,7 @@ static struct resource data_resource = { .name = "Kernel data", }; void __init add_memory_region(phys_t start, phys_t size, long type) { int x = boot_mem_map.nr_map; - struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1; + int i; /* Sanity check */ if (start + size < start) { @@ -88,15 +88,29 @@ void __init add_memory_region(phys_t start, phys_t size, long type) } /* - * Try to merge with previous entry if any. This is far less than - * perfect but is sufficient for most real world cases. + * Try to merge with existing entry, if any. */ - if (x && prev->addr + prev->size == start && prev->type == type) { - prev->size += size; + for (i = 0; i < boot_mem_map.nr_map; i++) { + struct boot_mem_map_entry *entry = boot_mem_map.map + i; + unsigned long top; + + if (entry->type != type) + continue; + + if (start + size < entry->addr) + continue; /* no overlap */ + + if (entry->addr + entry->size < start) + continue; /* no overlap */ + + top = max(entry->addr + entry->size, start + size); + entry->addr = min(entry->addr, start); + entry->size = top - entry->addr; + return; } - if (x == BOOT_MEM_MAP_MAX) { + if (boot_mem_map.nr_map == BOOT_MEM_MAP_MAX) { pr_err("Ooops! Too many entries in the memory map!\n"); return; } diff --git a/arch/mips/lib/mips-atomic.c b/arch/mips/lib/mips-atomic.c index e091430..cd160be 100644 --- a/arch/mips/lib/mips-atomic.c +++ b/arch/mips/lib/mips-atomic.c @@ -56,7 +56,7 @@ __asm__( " .set pop \n" " .endm \n"); -void arch_local_irq_disable(void) +notrace void arch_local_irq_disable(void) { preempt_disable(); __asm__ __volatile__( @@ -93,7 +93,7 @@ __asm__( " .set pop \n" " .endm \n"); -unsigned long arch_local_irq_save(void) +notrace unsigned long arch_local_irq_save(void) { unsigned long flags; preempt_disable(); @@ -135,7 +135,7 @@ __asm__( " .set pop \n" " .endm \n"); -void arch_local_irq_restore(unsigned long flags) +notrace void arch_local_irq_restore(unsigned long flags) { unsigned long __tmp1; @@ -159,7 +159,7 @@ void arch_local_irq_restore(unsigned long flags) EXPORT_SYMBOL(arch_local_irq_restore); -void __arch_local_irq_restore(unsigned long flags) +notrace void __arch_local_irq_restore(unsigned long flags) { unsigned long __tmp1; diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c index 797cd18..d16c8de 100644 --- a/arch/powerpc/platforms/pseries/eeh_pe.c +++ b/arch/powerpc/platforms/pseries/eeh_pe.c @@ -449,7 +449,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) if (list_empty(&pe->edevs)) { cnt = 0; list_for_each_entry(child, &pe->child_list, child) { - if (!(pe->type & EEH_PE_INVALID)) { + if (!(child->type & EEH_PE_INVALID)) { cnt++; break; } diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index d19f497..e5b0847 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -220,7 +220,8 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) /* Get the top level device in the PE */ edev = of_node_to_eeh_dev(dn); - edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); + if (edev->pe) + edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); dn = eeh_dev_to_of_node(edev); if (!dn) return NULL; diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index 89b30f3..ff7bb8a 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -1961,6 +1961,7 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) { res = loader_verify(lb, dev, rec); if (res) break; + rec = ihex_next_binrec(rec); } release_firmware(fw); if (!res) diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index be88728..592f597 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -250,7 +250,7 @@ tei_debug(struct FsmInst *fi, char *fmt, ...) static int get_free_id(struct manager *mgr) { - u64 ids = 0; + DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 }; int i; struct layer2 *l2; @@ -261,11 +261,11 @@ get_free_id(struct manager *mgr) __func__); return -EBUSY; } - test_and_set_bit(l2->ch.nr, (u_long *)&ids); + __set_bit(l2->ch.nr, ids); } - for (i = 1; i < 64; i++) - if (!test_bit(i, (u_long *)&ids)) - return i; + i = find_next_zero_bit(ids, 64, 1); + if (i < 64) + return i; printk(KERN_WARNING "%s: more as 63 layer2 for one device\n", __func__); return -EBUSY; @@ -274,7 +274,7 @@ get_free_id(struct manager *mgr) static int get_free_tei(struct manager *mgr) { - u64 ids = 0; + DECLARE_BITMAP(ids, 64) = { [0 ... BITS_TO_LONGS(64) - 1] = 0 }; int i; struct layer2 *l2; @@ -288,11 +288,11 @@ get_free_tei(struct manager *mgr) continue; i -= 64; - test_and_set_bit(i, (u_long *)&ids); + __set_bit(i, ids); } - for (i = 0; i < 64; i++) - if (!test_bit(i, (u_long *)&ids)) - return i + 64; + i = find_first_zero_bit(ids, 64); + if (i < 64) + return i + 64; printk(KERN_WARNING "%s: more as 63 dynamic tei for one device\n", __func__); return -1; diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index 262dfa5..b551ca3 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -300,15 +300,15 @@ static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 { u32 m_div, clk_sel; - dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk, - intp->quartz); - if (intp == NULL) return STV0900_INVALID_HANDLE; if (intp->errs) return STV0900_I2C_ERROR; + dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk, + intp->quartz); + clk_sel = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6); m_div = ((clk_sel * mclk) / intp->quartz) - 1; stv0900_write_bits(intp, F0900_M_DIV, m_div); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 109bc9b..05f8950 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -53,8 +53,7 @@ MODULE_LICENSE("GPL"); /* ADV7604 system clock frequency */ #define ADV7604_fsc (28636360) -#define DIGITAL_INPUT ((state->prim_mode == ADV7604_PRIM_MODE_HDMI_COMP) || \ - (state->prim_mode == ADV7604_PRIM_MODE_HDMI_GR)) +#define DIGITAL_INPUT (state->mode == ADV7604_MODE_HDMI) /* ********************************************************************** @@ -68,7 +67,7 @@ struct adv7604_state { struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler hdl; - enum adv7604_prim_mode prim_mode; + enum adv7604_mode mode; struct v4l2_dv_timings timings; u8 edid[256]; unsigned edid_blocks; @@ -77,6 +76,7 @@ struct adv7604_state { struct workqueue_struct *work_queues; struct delayed_work delayed_work_enable_hotplug; bool connector_hdmi; + bool restart_stdi_once; /* i2c clients */ struct i2c_client *i2c_avlink; @@ -106,7 +106,6 @@ static const struct v4l2_dv_timings adv7604_timings[] = { V4L2_DV_BT_CEA_720X576P50, V4L2_DV_BT_CEA_1280X720P24, V4L2_DV_BT_CEA_1280X720P25, - V4L2_DV_BT_CEA_1280X720P30, V4L2_DV_BT_CEA_1280X720P50, V4L2_DV_BT_CEA_1280X720P60, V4L2_DV_BT_CEA_1920X1080P24, @@ -115,6 +114,7 @@ static const struct v4l2_dv_timings adv7604_timings[] = { V4L2_DV_BT_CEA_1920X1080P50, V4L2_DV_BT_CEA_1920X1080P60, + /* sorted by DMT ID */ V4L2_DV_BT_DMT_640X350P85, V4L2_DV_BT_DMT_640X400P85, V4L2_DV_BT_DMT_720X400P85, @@ -164,6 +164,89 @@ static const struct v4l2_dv_timings adv7604_timings[] = { { }, }; +struct adv7604_video_standards { + struct v4l2_dv_timings timings; + u8 vid_std; + u8 v_freq; +}; + +/* sorted by number of lines */ +static const struct adv7604_video_standards adv7604_prim_mode_comp[] = { + /* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */ + { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, + { V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 }, + { V4L2_DV_BT_CEA_1280X720P60, 0x19, 0x00 }, + { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 }, + { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 }, + { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 }, + { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 }, + { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 }, + /* TODO add 1920x1080P60_RB (CVT timing) */ + { }, +}; + +/* sorted by number of lines */ +static const struct adv7604_video_standards adv7604_prim_mode_gr[] = { + { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, + { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, + { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, + { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 }, + { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 }, + { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 }, + { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 }, + { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 }, + { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 }, + { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 }, + { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 }, + { V4L2_DV_BT_DMT_1360X768P60, 0x12, 0x00 }, + { V4L2_DV_BT_DMT_1366X768P60, 0x13, 0x00 }, + { V4L2_DV_BT_DMT_1400X1050P60, 0x14, 0x00 }, + { V4L2_DV_BT_DMT_1400X1050P75, 0x15, 0x00 }, + { V4L2_DV_BT_DMT_1600X1200P60, 0x16, 0x00 }, /* TODO not tested */ + /* TODO add 1600X1200P60_RB (not a DMT timing) */ + { V4L2_DV_BT_DMT_1680X1050P60, 0x18, 0x00 }, + { V4L2_DV_BT_DMT_1920X1200P60_RB, 0x19, 0x00 }, /* TODO not tested */ + { }, +}; + +/* sorted by number of lines */ +static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = { + { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, + { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, + { V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 }, + { V4L2_DV_BT_CEA_1280X720P60, 0x13, 0x00 }, + { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 }, + { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 }, + { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 }, + { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 }, + { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 }, + { }, +}; + +/* sorted by number of lines */ +static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = { + { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, + { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, + { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, + { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 }, + { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 }, + { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 }, + { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 }, + { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 }, + { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 }, + { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 }, + { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 }, + { }, +}; + /* ----------------------------------------------------------------------- */ static inline struct adv7604_state *to_state(struct v4l2_subdev *sd) @@ -672,64 +755,144 @@ static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) ((io_read(sd, 0x6f) & 0x10) >> 4)); } -static void configure_free_run(struct v4l2_subdev *sd, const struct v4l2_bt_timings *timings) +static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, + u8 prim_mode, + const struct adv7604_video_standards *predef_vid_timings, + const struct v4l2_dv_timings *timings) +{ + struct adv7604_state *state = to_state(sd); + int i; + + for (i = 0; predef_vid_timings[i].timings.bt.width; i++) { + if (!v4l_match_dv_timings(timings, &predef_vid_timings[i].timings, + DIGITAL_INPUT ? 250000 : 1000000)) + continue; + io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */ + io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) + + prim_mode); /* v_freq and prim mode */ + return 0; + } + + return -1; +} + +static int configure_predefined_video_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) { + struct adv7604_state *state = to_state(sd); + int err; + + v4l2_dbg(1, debug, sd, "%s", __func__); + + /* reset to default values */ + io_write(sd, 0x16, 0x43); + io_write(sd, 0x17, 0x5a); + /* disable embedded syncs for auto graphics mode */ + cp_write_and_or(sd, 0x81, 0xef, 0x00); + cp_write(sd, 0x8f, 0x00); + cp_write(sd, 0x90, 0x00); + cp_write(sd, 0xa2, 0x00); + cp_write(sd, 0xa3, 0x00); + cp_write(sd, 0xa4, 0x00); + cp_write(sd, 0xa5, 0x00); + cp_write(sd, 0xa6, 0x00); + cp_write(sd, 0xa7, 0x00); + cp_write(sd, 0xab, 0x00); + cp_write(sd, 0xac, 0x00); + + switch (state->mode) { + case ADV7604_MODE_COMP: + case ADV7604_MODE_GR: + err = find_and_set_predefined_video_timings(sd, + 0x01, adv7604_prim_mode_comp, timings); + if (err) + err = find_and_set_predefined_video_timings(sd, + 0x02, adv7604_prim_mode_gr, timings); + break; + case ADV7604_MODE_HDMI: + err = find_and_set_predefined_video_timings(sd, + 0x05, adv7604_prim_mode_hdmi_comp, timings); + if (err) + err = find_and_set_predefined_video_timings(sd, + 0x06, adv7604_prim_mode_hdmi_gr, timings); + break; + default: + v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", + __func__, state->mode); + err = -1; + break; + } + + + return err; +} + +static void configure_custom_video_timings(struct v4l2_subdev *sd, + const struct v4l2_bt_timings *bt) +{ + struct adv7604_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 width = htotal(timings); - u32 height = vtotal(timings); - u16 ch1_fr_ll = (((u32)timings->pixelclock / 100) > 0) ? - ((width * (ADV7604_fsc / 100)) / ((u32)timings->pixelclock / 100)) : 0; + u32 width = htotal(bt); + u32 height = vtotal(bt); + u16 cp_start_sav = bt->hsync + bt->hbackporch - 4; + u16 cp_start_eav = width - bt->hfrontporch; + u16 cp_start_vbi = height - bt->vfrontporch; + u16 cp_end_vbi = bt->vsync + bt->vbackporch; + u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ? + ((width * (ADV7604_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0; + const u8 pll[2] = { + 0xc0 | ((width >> 8) & 0x1f), + width & 0xff + }; v4l2_dbg(2, debug, sd, "%s\n", __func__); - cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); /* CH1_FR_LL */ - cp_write(sd, 0x90, ch1_fr_ll & 0xff); /* CH1_FR_LL */ - cp_write(sd, 0xab, (height >> 4) & 0xff); /* CP_LCOUNT_MAX */ - cp_write(sd, 0xac, (height & 0x0f) << 4); /* CP_LCOUNT_MAX */ - /* TODO support interlaced */ - cp_write(sd, 0x91, 0x10); /* INTERLACED */ - - /* Should only be set in auto-graphics mode [REF_02 p. 91-92] */ - if ((io_read(sd, 0x00) == 0x07) && (io_read(sd, 0x01) == 0x02)) { - u16 cp_start_sav, cp_start_eav, cp_start_vbi, cp_end_vbi; - const u8 pll[2] = { - (0xc0 | ((width >> 8) & 0x1f)), - (width & 0xff) - }; + switch (state->mode) { + case ADV7604_MODE_COMP: + case ADV7604_MODE_GR: + /* auto graphics */ + io_write(sd, 0x00, 0x07); /* video std */ + io_write(sd, 0x01, 0x02); /* prim mode */ + /* enable embedded syncs for auto graphics mode */ + cp_write_and_or(sd, 0x81, 0xef, 0x10); + /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ /* IO-map reg. 0x16 and 0x17 should be written in sequence */ if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) { v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); - return; + break; } /* active video - horizontal timing */ - cp_start_sav = timings->hsync + timings->hbackporch - 4; - cp_start_eav = width - timings->hfrontporch; cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff); - cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | ((cp_start_eav >> 8) & 0x0f)); + cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | + ((cp_start_eav >> 8) & 0x0f)); cp_write(sd, 0xa4, cp_start_eav & 0xff); /* active video - vertical timing */ - cp_start_vbi = height - timings->vfrontporch; - cp_end_vbi = timings->vsync + timings->vbackporch; cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff); - cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | ((cp_end_vbi >> 8) & 0xf)); + cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | + ((cp_end_vbi >> 8) & 0xf)); cp_write(sd, 0xa7, cp_end_vbi & 0xff); - } else { - /* reset to default values */ - io_write(sd, 0x16, 0x43); - io_write(sd, 0x17, 0x5a); - cp_write(sd, 0xa2, 0x00); - cp_write(sd, 0xa3, 0x00); - cp_write(sd, 0xa4, 0x00); - cp_write(sd, 0xa5, 0x00); - cp_write(sd, 0xa6, 0x00); - cp_write(sd, 0xa7, 0x00); + break; + case ADV7604_MODE_HDMI: + /* set default prim_mode/vid_std for HDMI + accoring to [REF_03, c. 4.2] */ + io_write(sd, 0x00, 0x02); /* video std */ + io_write(sd, 0x01, 0x06); /* prim mode */ + break; + default: + v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", + __func__, state->mode); + break; } -} + cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); + cp_write(sd, 0x90, ch1_fr_ll & 0xff); + cp_write(sd, 0xab, (height >> 4) & 0xff); + cp_write(sd, 0xac, (height & 0x0f) << 4); +} static void set_rgb_quantization_range(struct v4l2_subdev *sd) { @@ -738,12 +901,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) switch (state->rgb_quantization_range) { case V4L2_DV_RGB_RANGE_AUTO: /* automatic */ - if ((hdmi_read(sd, 0x05) & 0x80) || - (state->prim_mode == ADV7604_PRIM_MODE_COMP) || - (state->prim_mode == ADV7604_PRIM_MODE_RGB)) { - /* receiving HDMI or analog signal */ - io_write_and_or(sd, 0x02, 0x0f, 0xf0); - } else { + if (DIGITAL_INPUT && !(hdmi_read(sd, 0x05) & 0x80)) { /* receiving DVI-D signal */ /* ADV7604 selects RGB limited range regardless of @@ -756,6 +914,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) /* RGB full range (0-255) */ io_write_and_or(sd, 0x02, 0x0f, 0x10); } + } else { + /* receiving HDMI or analog signal, set automode */ + io_write_and_or(sd, 0x02, 0x0f, 0xf0); } break; case V4L2_DV_RGB_RANGE_LIMITED: @@ -967,8 +1128,10 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, state->aspect_ratio, timings)) return 0; - v4l2_dbg(2, debug, sd, "%s: No format candidate found for lcf=%d, bl = %d\n", - __func__, stdi->lcf, stdi->bl); + v4l2_dbg(2, debug, sd, + "%s: No format candidate found for lcvs = %d, lcf=%d, bl = %d, %chsync, %cvsync\n", + __func__, stdi->lcvs, stdi->lcf, stdi->bl, + stdi->hs_pol, stdi->vs_pol); return -1; } @@ -1123,7 +1286,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, adv7604_fill_optional_dv_timings_fields(sd, timings); } else { /* find format - * Since LCVS values are inaccurate (REF_03, page 275-276), + * Since LCVS values are inaccurate [REF_03, p. 275-276], * stdi2dv_timings() is called with lcvs +-1 if the first attempt fails. */ if (!stdi2dv_timings(sd, &stdi, timings)) @@ -1135,9 +1298,31 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, stdi.lcvs -= 2; v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs); if (stdi2dv_timings(sd, &stdi, timings)) { + /* + * The STDI block may measure wrong values, especially + * for lcvs and lcf. If the driver can not find any + * valid timing, the STDI block is restarted to measure + * the video timings again. The function will return an + * error, but the restart of STDI will generate a new + * STDI interrupt and the format detection process will + * restart. + */ + if (state->restart_stdi_once) { + v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__); + /* TODO restart STDI for Sync Channel 2 */ + /* enter one-shot mode */ + cp_write_and_or(sd, 0x86, 0xf9, 0x00); + /* trigger STDI restart */ + cp_write_and_or(sd, 0x86, 0xf9, 0x04); + /* reset to continuous mode */ + cp_write_and_or(sd, 0x86, 0xf9, 0x02); + state->restart_stdi_once = false; + return -ENOLINK; + } v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__); return -ERANGE; } + state->restart_stdi_once = true; } found: @@ -1166,6 +1351,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, { struct adv7604_state *state = to_state(sd); struct v4l2_bt_timings *bt; + int err; if (!timings) return -EINVAL; @@ -1178,12 +1364,20 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, __func__, (u32)bt->pixelclock); return -ERANGE; } + adv7604_fill_optional_dv_timings_fields(sd, timings); state->timings = *timings; - /* freerun */ - configure_free_run(sd, bt); + cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10); + + /* Use prim_mode and vid_std when available */ + err = configure_predefined_video_timings(sd, timings); + if (err) { + /* custom settings when the video format + does not have prim_mode/vid_std */ + configure_custom_video_timings(sd, bt); + } set_rgb_quantization_range(sd); @@ -1203,24 +1397,25 @@ static int adv7604_g_dv_timings(struct v4l2_subdev *sd, return 0; } -static void enable_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mode) +static void enable_input(struct v4l2_subdev *sd) { - switch (prim_mode) { - case ADV7604_PRIM_MODE_COMP: - case ADV7604_PRIM_MODE_RGB: + struct adv7604_state *state = to_state(sd); + + switch (state->mode) { + case ADV7604_MODE_COMP: + case ADV7604_MODE_GR: /* enable */ io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ break; - case ADV7604_PRIM_MODE_HDMI_COMP: - case ADV7604_PRIM_MODE_HDMI_GR: + case ADV7604_MODE_HDMI: /* enable */ hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */ hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ break; default: - v4l2_err(sd, "%s: reserved primary mode 0x%0x\n", - __func__, prim_mode); + v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", + __func__, state->mode); break; } } @@ -1233,17 +1428,13 @@ static void disable_input(struct v4l2_subdev *sd) hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ } -static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mode) +static void select_input(struct v4l2_subdev *sd) { - switch (prim_mode) { - case ADV7604_PRIM_MODE_COMP: - case ADV7604_PRIM_MODE_RGB: - /* set mode and select free run resolution */ - io_write(sd, 0x00, 0x07); /* video std */ - io_write(sd, 0x01, 0x02); /* prim mode */ - /* enable embedded syncs for auto graphics mode */ - cp_write_and_or(sd, 0x81, 0xef, 0x10); + struct adv7604_state *state = to_state(sd); + switch (state->mode) { + case ADV7604_MODE_COMP: + case ADV7604_MODE_GR: /* reset ADI recommended settings for HDMI: */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */ @@ -1271,16 +1462,7 @@ static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mod cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ break; - case ADV7604_PRIM_MODE_HDMI_COMP: - case ADV7604_PRIM_MODE_HDMI_GR: - /* set mode and select free run resolution */ - /* video std */ - io_write(sd, 0x00, - (prim_mode == ADV7604_PRIM_MODE_HDMI_GR) ? 0x02 : 0x1e); - io_write(sd, 0x01, prim_mode); /* prim mode */ - /* disable embedded syncs for auto graphics mode */ - cp_write_and_or(sd, 0x81, 0xef, 0x00); - + case ADV7604_MODE_HDMI: /* set ADI recommended settings for HDMI: */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */ @@ -1309,7 +1491,8 @@ static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mod break; default: - v4l2_err(sd, "%s: reserved primary mode 0x%0x\n", __func__, prim_mode); + v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", + __func__, state->mode); break; } } @@ -1321,26 +1504,13 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input); - switch (input) { - case 0: - /* TODO select HDMI_COMP or HDMI_GR */ - state->prim_mode = ADV7604_PRIM_MODE_HDMI_COMP; - break; - case 1: - state->prim_mode = ADV7604_PRIM_MODE_RGB; - break; - case 2: - state->prim_mode = ADV7604_PRIM_MODE_COMP; - break; - default: - return -EINVAL; - } + state->mode = input; disable_input(sd); - select_input(sd, state->prim_mode); + select_input(sd); - enable_input(sd, state->prim_mode); + enable_input(sd); return 0; } @@ -1549,8 +1719,9 @@ static int adv7604_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "CP locked: %s\n", no_lock_cp(sd) ? "false" : "true"); v4l2_info(sd, "CP free run: %s\n", (!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off")); - v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x\n", - io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f); + v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x, v_freq = 0x%x\n", + io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f, + (io_read(sd, 0x01) & 0x70) >> 4); v4l2_info(sd, "-----Video Timings-----\n"); if (read_stdi(sd, &stdi)) @@ -1712,9 +1883,9 @@ static int adv7604_core_init(struct v4l2_subdev *sd) cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */ cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */ cp_write(sd, 0xf9, 0x23); /* STDI ch. 1 - LCVS change threshold - - ADI recommended setting [REF_01 c. 2.3.3] */ + ADI recommended setting [REF_01, c. 2.3.3] */ cp_write(sd, 0x45, 0x23); /* STDI ch. 2 - LCVS change threshold - - ADI recommended setting [REF_01 c. 2.3.3] */ + ADI recommended setting [REF_01, c. 2.3.3] */ cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution for digital formats */ @@ -1724,11 +1895,6 @@ static int adv7604_core_init(struct v4l2_subdev *sd) afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4); - state->prim_mode = pdata->prim_mode; - select_input(sd, pdata->prim_mode); - - enable_input(sd, pdata->prim_mode); - /* interrupts */ io_write(sd, 0x40, 0xc2); /* Configure INT1 */ io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ @@ -1883,6 +2049,7 @@ static int adv7604_probe(struct i2c_client *client, v4l2_err(sd, "failed to create all i2c clients\n"); goto err_i2c; } + state->restart_stdi_once = true; /* work queues */ state->work_queues = create_singlethread_workqueue(client->name); diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 13057b9..333ef17 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -263,9 +263,14 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) if (ret & 1) /* Autoexposure */ ret = reg_write(client, mt9v022->reg->max_total_shutter_width, rect.height + mt9v022->y_skip_top + 43); - else - ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, - rect.height + mt9v022->y_skip_top + 43); + /* + * If autoexposure is off, there is no need to set + * MT9V022_TOTAL_SHUTTER_WIDTH here. Autoexposure can be off + * only if the user has set exposure manually, using the + * V4L2_CID_EXPOSURE_AUTO with the value V4L2_EXPOSURE_MANUAL. + * In this case the register MT9V022_TOTAL_SHUTTER_WIDTH + * already contains the correct value. + */ } /* Setup frame format: defaults apart from width and height */ if (!ret) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index bfec9e6..19cbb12 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -965,8 +965,10 @@ static struct platform_device_id gsc_driver_ids[] = { MODULE_DEVICE_TABLE(platform, gsc_driver_ids); static const struct of_device_id exynos_gsc_match[] = { - { .compatible = "samsung,exynos5250-gsc", - .data = &gsc_v_100_drvdata, }, + { + .compatible = "samsung,exynos5-gsc", + .data = &gsc_v_100_drvdata, + }, {}, }; MODULE_DEVICE_TABLE(of, exynos_gsc_match); diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 60181ab..aa9df9d 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1706,7 +1706,7 @@ static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) } static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) + struct v4l2_event_subscription *sub) { if (sub->type != V4L2_EVENT_FRAME_SYNC) return -EINVAL; @@ -1719,7 +1719,7 @@ static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, } static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) + struct v4l2_event_subscription *sub) { return v4l2_event_unsubscribe(fh, sub); } diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index d7ac76b..b8640be 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -1025,7 +1025,7 @@ void omap3isp_stat_dma_isr(struct ispstat *stat) int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) + struct v4l2_event_subscription *sub) { struct ispstat *stat = v4l2_get_subdevdata(subdev); @@ -1037,7 +1037,7 @@ int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) + struct v4l2_event_subscription *sub) { return v4l2_event_unsubscribe(fh, sub); } diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h index a6fe653..9b7c865 100644 --- a/drivers/media/platform/omap3isp/ispstat.h +++ b/drivers/media/platform/omap3isp/ispstat.h @@ -147,10 +147,10 @@ int omap3isp_stat_init(struct ispstat *stat, const char *name, void omap3isp_stat_cleanup(struct ispstat *stat); int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub); + struct v4l2_event_subscription *sub); int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub); + struct v4l2_event_subscription *sub); int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable); int omap3isp_stat_busy(struct ispstat *stat); diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index a0b737fe..75cd309 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -792,7 +792,7 @@ isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) } static int -isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop) +isp_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop) { struct isp_video *video = video_drvdata(file); struct v4l2_subdev *subdev; diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig index 8f090a8..c16b20d8 100644 --- a/drivers/media/platform/s5p-fimc/Kconfig +++ b/drivers/media/platform/s5p-fimc/Kconfig @@ -24,6 +24,7 @@ config VIDEO_S5P_FIMC config VIDEO_S5P_MIPI_CSIS tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver" depends on REGULATOR + select S5P_SETUP_MIPIPHY help This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2 receiver (MIPI-CSIS) devices. diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index 367efd1..3d39d97 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -1736,7 +1736,9 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct fimc_vid_buffer); - vb2_queue_init(q); + ret = vb2_queue_init(q); + if (ret) + goto err_ent; vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0); diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index 70bcf39..9db246b 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -1253,7 +1253,9 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) q->buf_struct_size = sizeof(struct flite_buffer); q->drv_priv = fimc; - vb2_queue_init(q); + ret = vb2_queue_init(q); + if (ret < 0) + return ret; fimc->vd_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0); diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 80ada58..38ea4d1 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -343,53 +343,50 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) static int fimc_register_callback(struct device *dev, void *p) { struct fimc_dev *fimc = dev_get_drvdata(dev); - struct v4l2_subdev *sd = &fimc->vid_cap.subdev; + struct v4l2_subdev *sd; struct fimc_md *fmd = p; - int ret = 0; - - if (!fimc || !fimc->pdev) - return 0; + int ret; - if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS) + if (fimc == NULL || fimc->id >= FIMC_MAX_DEVS) return 0; - fimc->pipeline_ops = &fimc_pipeline_ops; - fmd->fimc[fimc->pdev->id] = fimc; + sd = &fimc->vid_cap.subdev; sd->grp_id = FIMC_GROUP_ID; ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); if (ret) { v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n", fimc->id, ret); + return ret; } - return ret; + fimc->pipeline_ops = &fimc_pipeline_ops; + fmd->fimc[fimc->id] = fimc; + return 0; } static int fimc_lite_register_callback(struct device *dev, void *p) { struct fimc_lite *fimc = dev_get_drvdata(dev); - struct v4l2_subdev *sd = &fimc->subdev; struct fimc_md *fmd = p; int ret; - if (fimc == NULL) + if (fimc == NULL || fimc->index >= FIMC_LITE_MAX_DEVS) return 0; - if (fimc->index >= FIMC_LITE_MAX_DEVS) - return 0; + fimc->subdev.grp_id = FLITE_GROUP_ID; - fimc->pipeline_ops = &fimc_pipeline_ops; - fmd->fimc_lite[fimc->index] = fimc; - sd->grp_id = FLITE_GROUP_ID; - - ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, &fimc->subdev); if (ret) { v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC-LITE.%d (%d)\n", fimc->index, ret); + return ret; } - return ret; + + fimc->pipeline_ops = &fimc_pipeline_ops; + fmd->fimc_lite[fimc->index] = fimc; + return 0; } static int csis_register_callback(struct device *dev, void *p) @@ -407,10 +404,12 @@ static int csis_register_callback(struct device *dev, void *p) v4l2_info(sd, "csis%d sd: %s\n", pdev->id, sd->name); id = pdev->id < 0 ? 0 : pdev->id; - fmd->csis[id].sd = sd; sd->grp_id = CSIS_GROUP_ID; + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); - if (ret) + if (!ret) + fmd->csis[id].sd = sd; + else v4l2_err(&fmd->v4l2_dev, "Failed to register CSIS subdevice: %d\n", ret); return ret; diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 85fd312..a1c87f0 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -935,9 +935,10 @@ static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a) /* Assume a dull encoder, do all the work ourselves. */ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) { + struct v4l2_crop a_writable = *a; struct video_device *vdev = video_devdata(file); struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - struct v4l2_rect *rect = &a->c; + struct v4l2_rect *rect = &a_writable.c; struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT}; struct v4l2_pix_format *pix = &vou_dev->pix; struct sh_vou_geometry geo; diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c index bbe7099..032b8c9 100644 --- a/drivers/media/platform/soc_camera/mx1_camera.c +++ b/drivers/media/platform/soc_camera/mx1_camera.c @@ -470,14 +470,6 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd) pcdev->icd = NULL; } -static int mx1_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_subdev_call(sd, video, s_crop, a); -} - static int mx1_camera_set_bus_param(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); @@ -689,7 +681,6 @@ static struct soc_camera_host_ops mx1_soc_camera_host_ops = { .add = mx1_camera_add_device, .remove = mx1_camera_remove_device, .set_bus_param = mx1_camera_set_bus_param, - .set_crop = mx1_camera_set_crop, .set_fmt = mx1_camera_set_fmt, .try_fmt = mx1_camera_try_fmt, .init_videobuf = mx1_camera_init_videobuf, diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 9fd9d1c..9a55f4c 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -864,8 +864,10 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) bytesperline = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); - if (bytesperline < 0) + if (bytesperline < 0) { + spin_unlock_irqrestore(&pcdev->lock, flags); return bytesperline; + } /* * I didn't manage to properly enable/disable the prp @@ -878,8 +880,10 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, pcdev->discard_size, &pcdev->discard_buffer_dma, GFP_KERNEL); - if (!pcdev->discard_buffer) + if (!pcdev->discard_buffer) { + spin_unlock_irqrestore(&pcdev->lock, flags); return -ENOMEM; + } pcdev->buf_discard[0].discard = true; list_add_tail(&pcdev->buf_discard[0].queue, @@ -1099,9 +1103,10 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) } static int mx2_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) + const struct v4l2_crop *a) { - struct v4l2_rect *rect = &a->c; + struct v4l2_crop a_writable = *a; + struct v4l2_rect *rect = &a_writable.c; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct v4l2_mbus_framefmt mf; int ret; diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 3557ac9..261f6e9 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -799,9 +799,10 @@ static inline void stride_align(__u32 *width) * default g_crop and cropcap from soc_camera.c */ static int mx3_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) + const struct v4l2_crop *a) { - struct v4l2_rect *rect = &a->c; + struct v4l2_crop a_writable = *a; + struct v4l2_rect *rect = &a_writable.c; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index fa08c76..13636a5 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -1215,9 +1215,9 @@ static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev, } static int omap1_cam_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *crop) + const struct v4l2_crop *crop) { - struct v4l2_rect *rect = &crop->c; + const struct v4l2_rect *rect = &crop->c; const struct soc_camera_format_xlate *xlate = icd->current_fmt; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 1e3776d..3434ffe 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1337,9 +1337,9 @@ static int pxa_camera_check_frame(u32 width, u32 height) } static int pxa_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) + const struct v4l2_crop *a) { - struct v4l2_rect *rect = &a->c; + const struct v4l2_rect *rect = &a->c; struct device *dev = icd->parent; struct soc_camera_host *ici = to_soc_camera_host(dev); struct pxa_camera_dev *pcdev = ici->priv; diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 0a24253..2d8861c 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -1182,13 +1182,13 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd) } /* Check if any dimension of r1 is smaller than respective one of r2 */ -static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2) +static bool is_smaller(const struct v4l2_rect *r1, const struct v4l2_rect *r2) { return r1->width < r2->width || r1->height < r2->height; } /* Check if r1 fails to cover r2 */ -static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2) +static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2) { return r1->left > r2->left || r1->top > r2->top || r1->left + r1->width < r2->left + r2->width || @@ -1263,7 +1263,7 @@ static void update_subrect(struct sh_mobile_ceu_cam *cam) * 3. if (2) failed, try to request the maximum image */ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, - const struct v4l2_crop *cam_crop) + struct v4l2_crop *cam_crop) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c; @@ -1519,7 +1519,8 @@ static int client_scale(struct soc_camera_device *icd, static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, const struct v4l2_crop *a) { - struct v4l2_rect *rect = &a->c; + struct v4l2_crop a_writable = *a; + const struct v4l2_rect *rect = &a_writable.c; struct device *dev = icd->parent; struct soc_camera_host *ici = to_soc_camera_host(dev); struct sh_mobile_ceu_dev *pcdev = ici->priv; @@ -1545,7 +1546,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, * 1. - 2. Apply iterative camera S_CROP for new input window, read back * actual camera rectangle. */ - ret = client_s_crop(icd, a, &cam_crop); + ret = client_s_crop(icd, &a_writable, &cam_crop); if (ret < 0) return ret; @@ -1946,7 +1947,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, } static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, - struct v4l2_crop *a) + const struct v4l2_crop *a) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 9859d2a..ba51f65 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -283,14 +283,13 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, /* activate the pid on the device pid filter */ if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->pid_filtering && - adap->props->pid_filter) + adap->pid_filtering && adap->props->pid_filter) { ret = adap->props->pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, (count == 1) ? 1 : 0); - if (ret < 0) - dev_err(&d->udev->dev, "%s: pid_filter() " \ - "failed=%d\n", KBUILD_MODNAME, - ret); + if (ret < 0) + dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n", + KBUILD_MODNAME, ret); + } /* start feeding if it is first pid */ if (adap->feed_count == 1 && count == 1) { diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c index 0431bee..5716662 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c @@ -32,9 +32,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, return -EINVAL; } - ret = mutex_lock_interruptible(&d->usb_mutex); - if (ret < 0) - return ret; + mutex_lock(&d->usb_mutex); dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf); diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index adabba8..093f1ac 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1346,6 +1346,10 @@ static const struct usb_device_id rtl28xxu_id_table[] = { &rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3, &rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) }, + { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102, + &rtl2832u_props, "Dexatek DK mini DVB-T Dongle", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d7, + &rtl2832u_props, "TerraTec Cinergy T Stick+", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table); diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 1b48f20..f4f9bf8 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -98,9 +98,9 @@ static irqreturn_t arizona_underclocked(int irq, void *data) if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) dev_err(arizona->dev, "AIF3 underclocked\n"); - if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) - dev_err(arizona->dev, "AIF3 underclocked\n"); if (val & ARIZONA_AIF2_UNDERCLOCKED_STS) + dev_err(arizona->dev, "AIF2 underclocked\n"); + if (val & ARIZONA_AIF1_UNDERCLOCKED_STS) dev_err(arizona->dev, "AIF1 underclocked\n"); if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) dev_err(arizona->dev, "ISRC2 underclocked\n"); @@ -415,11 +415,19 @@ int __devinit arizona_dev_init(struct arizona *arizona) /* If we have a /RESET GPIO we'll already be reset */ if (!arizona->pdata.reset) { + regcache_mark_dirty(arizona->regmap); + ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); if (ret != 0) { dev_err(dev, "Failed to reset device: %d\n", ret); goto err_reset; } + + ret = regcache_sync(arizona->regmap); + if (ret != 0) { + dev_err(dev, "Failed to sync device: %d\n", ret); + goto err_reset; + } } ret = arizona_wait_for_boot(arizona); @@ -520,7 +528,7 @@ int __devinit arizona_dev_init(struct arizona *arizona) break; case WM5110: ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, - ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); + ARRAY_SIZE(wm5110_devs), NULL, 0, NULL); break; } diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index ef0f2d0..b1b0091 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -178,6 +178,7 @@ int arizona_irq_init(struct arizona *arizona) switch (arizona->rev) { case 0: + case 1: ctrlif_error = false; break; default: diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 4ae6423..a071a86 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -671,7 +671,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) { - child = add_child(TWL6030_MODULE_ID1, "twl6030-pwm", NULL, 0, + child = add_child(SUB_CHIP_ID1, "twl6030-pwm", NULL, 0, false, 0, 0); if (IS_ERR(child)) return PTR_ERR(child); diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index ad733d7..cdd1173 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -672,7 +672,8 @@ int twl4030_sih_setup(struct device *dev, int module, int irq_base) irq = sih_mod + twl4030_irq_base; irq_set_handler_data(irq, agent); agent->irq_name = kasprintf(GFP_KERNEL, "twl4030_%s", sih->name); - status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0, + status = request_threaded_irq(irq, NULL, handle_twl4030_sih, + IRQF_EARLY_RESUME, agent->irq_name ?: sih->name, NULL); dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name, diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 01b9255..14490cc 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -43,6 +43,7 @@ static const struct reg_default wm5102_reva_patch[] = { { 0x479, 0x0A30 }, { 0x47B, 0x0810 }, { 0x47D, 0x0510 }, + { 0x4D1, 0x017F }, { 0x500, 0x000D }, { 0x507, 0x1820 }, { 0x508, 0x1820 }, @@ -52,524 +53,6 @@ static const struct reg_default wm5102_reva_patch[] = { { 0x580, 0x000D }, { 0x587, 0x1820 }, { 0x588, 0x1820 }, - { 0x101, 0x8140 }, - { 0x3000, 0x2225 }, - { 0x3001, 0x3a03 }, - { 0x3002, 0x0225 }, - { 0x3003, 0x0801 }, - { 0x3004, 0x6249 }, - { 0x3005, 0x0c04 }, - { 0x3006, 0x0225 }, - { 0x3007, 0x5901 }, - { 0x3008, 0xe249 }, - { 0x3009, 0x030d }, - { 0x300a, 0x0249 }, - { 0x300b, 0x2c01 }, - { 0x300c, 0xe249 }, - { 0x300d, 0x4342 }, - { 0x300e, 0xe249 }, - { 0x300f, 0x73c0 }, - { 0x3010, 0x4249 }, - { 0x3011, 0x0c00 }, - { 0x3012, 0x0225 }, - { 0x3013, 0x1f01 }, - { 0x3014, 0x0225 }, - { 0x3015, 0x1e01 }, - { 0x3016, 0x0225 }, - { 0x3017, 0xfa00 }, - { 0x3018, 0x0000 }, - { 0x3019, 0xf000 }, - { 0x301a, 0x0000 }, - { 0x301b, 0xf000 }, - { 0x301c, 0x0000 }, - { 0x301d, 0xf000 }, - { 0x301e, 0x0000 }, - { 0x301f, 0xf000 }, - { 0x3020, 0x0000 }, - { 0x3021, 0xf000 }, - { 0x3022, 0x0000 }, - { 0x3023, 0xf000 }, - { 0x3024, 0x0000 }, - { 0x3025, 0xf000 }, - { 0x3026, 0x0000 }, - { 0x3027, 0xf000 }, - { 0x3028, 0x0000 }, - { 0x3029, 0xf000 }, - { 0x302a, 0x0000 }, - { 0x302b, 0xf000 }, - { 0x302c, 0x0000 }, - { 0x302d, 0xf000 }, - { 0x302e, 0x0000 }, - { 0x302f, 0xf000 }, - { 0x3030, 0x0225 }, - { 0x3031, 0x1a01 }, - { 0x3032, 0x0225 }, - { 0x3033, 0x1e00 }, - { 0x3034, 0x0225 }, - { 0x3035, 0x1f00 }, - { 0x3036, 0x6225 }, - { 0x3037, 0xf800 }, - { 0x3038, 0x0000 }, - { 0x3039, 0xf000 }, - { 0x303a, 0x0000 }, - { 0x303b, 0xf000 }, - { 0x303c, 0x0000 }, - { 0x303d, 0xf000 }, - { 0x303e, 0x0000 }, - { 0x303f, 0xf000 }, - { 0x3040, 0x2226 }, - { 0x3041, 0x3a03 }, - { 0x3042, 0x0226 }, - { 0x3043, 0x0801 }, - { 0x3044, 0x6249 }, - { 0x3045, 0x0c06 }, - { 0x3046, 0x0226 }, - { 0x3047, 0x5901 }, - { 0x3048, 0xe249 }, - { 0x3049, 0x030d }, - { 0x304a, 0x0249 }, - { 0x304b, 0x2c01 }, - { 0x304c, 0xe249 }, - { 0x304d, 0x4342 }, - { 0x304e, 0xe249 }, - { 0x304f, 0x73c0 }, - { 0x3050, 0x4249 }, - { 0x3051, 0x0c00 }, - { 0x3052, 0x0226 }, - { 0x3053, 0x1f01 }, - { 0x3054, 0x0226 }, - { 0x3055, 0x1e01 }, - { 0x3056, 0x0226 }, - { 0x3057, 0xfa00 }, - { 0x3058, 0x0000 }, - { 0x3059, 0xf000 }, - { 0x305a, 0x0000 }, - { 0x305b, 0xf000 }, - { 0x305c, 0x0000 }, - { 0x305d, 0xf000 }, - { 0x305e, 0x0000 }, - { 0x305f, 0xf000 }, - { 0x3060, 0x0000 }, - { 0x3061, 0xf000 }, - { 0x3062, 0x0000 }, - { 0x3063, 0xf000 }, - { 0x3064, 0x0000 }, - { 0x3065, 0xf000 }, - { 0x3066, 0x0000 }, - { 0x3067, 0xf000 }, - { 0x3068, 0x0000 }, - { 0x3069, 0xf000 }, - { 0x306a, 0x0000 }, - { 0x306b, 0xf000 }, - { 0x306c, 0x0000 }, - { 0x306d, 0xf000 }, - { 0x306e, 0x0000 }, - { 0x306f, 0xf000 }, - { 0x3070, 0x0226 }, - { 0x3071, 0x1a01 }, - { 0x3072, 0x0226 }, - { 0x3073, 0x1e00 }, - { 0x3074, 0x0226 }, - { 0x3075, 0x1f00 }, - { 0x3076, 0x6226 }, - { 0x3077, 0xf800 }, - { 0x3078, 0x0000 }, - { 0x3079, 0xf000 }, - { 0x307a, 0x0000 }, - { 0x307b, 0xf000 }, - { 0x307c, 0x0000 }, - { 0x307d, 0xf000 }, - { 0x307e, 0x0000 }, - { 0x307f, 0xf000 }, - { 0x3080, 0x2227 }, - { 0x3081, 0x3a03 }, - { 0x3082, 0x0227 }, - { 0x3083, 0x0801 }, - { 0x3084, 0x6255 }, - { 0x3085, 0x0c04 }, - { 0x3086, 0x0227 }, - { 0x3087, 0x5901 }, - { 0x3088, 0xe255 }, - { 0x3089, 0x030d }, - { 0x308a, 0x0255 }, - { 0x308b, 0x2c01 }, - { 0x308c, 0xe255 }, - { 0x308d, 0x4342 }, - { 0x308e, 0xe255 }, - { 0x308f, 0x73c0 }, - { 0x3090, 0x4255 }, - { 0x3091, 0x0c00 }, - { 0x3092, 0x0227 }, - { 0x3093, 0x1f01 }, - { 0x3094, 0x0227 }, - { 0x3095, 0x1e01 }, - { 0x3096, 0x0227 }, - { 0x3097, 0xfa00 }, - { 0x3098, 0x0000 }, - { 0x3099, 0xf000 }, - { 0x309a, 0x0000 }, - { 0x309b, 0xf000 }, - { 0x309c, 0x0000 }, - { 0x309d, 0xf000 }, - { 0x309e, 0x0000 }, - { 0x309f, 0xf000 }, - { 0x30a0, 0x0000 }, - { 0x30a1, 0xf000 }, - { 0x30a2, 0x0000 }, - { 0x30a3, 0xf000 }, - { 0x30a4, 0x0000 }, - { 0x30a5, 0xf000 }, - { 0x30a6, 0x0000 }, - { 0x30a7, 0xf000 }, - { 0x30a8, 0x0000 }, - { 0x30a9, 0xf000 }, - { 0x30aa, 0x0000 }, - { 0x30ab, 0xf000 }, - { 0x30ac, 0x0000 }, - { 0x30ad, 0xf000 }, - { 0x30ae, 0x0000 }, - { 0x30af, 0xf000 }, - { 0x30b0, 0x0227 }, - { 0x30b1, 0x1a01 }, - { 0x30b2, 0x0227 }, - { 0x30b3, 0x1e00 }, - { 0x30b4, 0x0227 }, - { 0x30b5, 0x1f00 }, - { 0x30b6, 0x6227 }, - { 0x30b7, 0xf800 }, - { 0x30b8, 0x0000 }, - { 0x30b9, 0xf000 }, - { 0x30ba, 0x0000 }, - { 0x30bb, 0xf000 }, - { 0x30bc, 0x0000 }, - { 0x30bd, 0xf000 }, - { 0x30be, 0x0000 }, - { 0x30bf, 0xf000 }, - { 0x30c0, 0x2228 }, - { 0x30c1, 0x3a03 }, - { 0x30c2, 0x0228 }, - { 0x30c3, 0x0801 }, - { 0x30c4, 0x6255 }, - { 0x30c5, 0x0c06 }, - { 0x30c6, 0x0228 }, - { 0x30c7, 0x5901 }, - { 0x30c8, 0xe255 }, - { 0x30c9, 0x030d }, - { 0x30ca, 0x0255 }, - { 0x30cb, 0x2c01 }, - { 0x30cc, 0xe255 }, - { 0x30cd, 0x4342 }, - { 0x30ce, 0xe255 }, - { 0x30cf, 0x73c0 }, - { 0x30d0, 0x4255 }, - { 0x30d1, 0x0c00 }, - { 0x30d2, 0x0228 }, - { 0x30d3, 0x1f01 }, - { 0x30d4, 0x0228 }, - { 0x30d5, 0x1e01 }, - { 0x30d6, 0x0228 }, - { 0x30d7, 0xfa00 }, - { 0x30d8, 0x0000 }, - { 0x30d9, 0xf000 }, - { 0x30da, 0x0000 }, - { 0x30db, 0xf000 }, - { 0x30dc, 0x0000 }, - { 0x30dd, 0xf000 }, - { 0x30de, 0x0000 }, - { 0x30df, 0xf000 }, - { 0x30e0, 0x0000 }, - { 0x30e1, 0xf000 }, - { 0x30e2, 0x0000 }, - { 0x30e3, 0xf000 }, - { 0x30e4, 0x0000 }, - { 0x30e5, 0xf000 }, - { 0x30e6, 0x0000 }, - { 0x30e7, 0xf000 }, - { 0x30e8, 0x0000 }, - { 0x30e9, 0xf000 }, - { 0x30ea, 0x0000 }, - { 0x30eb, 0xf000 }, - { 0x30ec, 0x0000 }, - { 0x30ed, 0xf000 }, - { 0x30ee, 0x0000 }, - { 0x30ef, 0xf000 }, - { 0x30f0, 0x0228 }, - { 0x30f1, 0x1a01 }, - { 0x30f2, 0x0228 }, - { 0x30f3, 0x1e00 }, - { 0x30f4, 0x0228 }, - { 0x30f5, 0x1f00 }, - { 0x30f6, 0x6228 }, - { 0x30f7, 0xf800 }, - { 0x30f8, 0x0000 }, - { 0x30f9, 0xf000 }, - { 0x30fa, 0x0000 }, - { 0x30fb, 0xf000 }, - { 0x30fc, 0x0000 }, - { 0x30fd, 0xf000 }, - { 0x30fe, 0x0000 }, - { 0x30ff, 0xf000 }, - { 0x3100, 0x222b }, - { 0x3101, 0x3a03 }, - { 0x3102, 0x222b }, - { 0x3103, 0x5803 }, - { 0x3104, 0xe26f }, - { 0x3105, 0x030d }, - { 0x3106, 0x626f }, - { 0x3107, 0x2c01 }, - { 0x3108, 0xe26f }, - { 0x3109, 0x4342 }, - { 0x310a, 0xe26f }, - { 0x310b, 0x73c0 }, - { 0x310c, 0x026f }, - { 0x310d, 0x0c00 }, - { 0x310e, 0x022b }, - { 0x310f, 0x1f01 }, - { 0x3110, 0x022b }, - { 0x3111, 0x1e01 }, - { 0x3112, 0x022b }, - { 0x3113, 0xfa00 }, - { 0x3114, 0x0000 }, - { 0x3115, 0xf000 }, - { 0x3116, 0x0000 }, - { 0x3117, 0xf000 }, - { 0x3118, 0x0000 }, - { 0x3119, 0xf000 }, - { 0x311a, 0x0000 }, - { 0x311b, 0xf000 }, - { 0x311c, 0x0000 }, - { 0x311d, 0xf000 }, - { 0x311e, 0x0000 }, - { 0x311f, 0xf000 }, - { 0x3120, 0x022b }, - { 0x3121, 0x0a01 }, - { 0x3122, 0x022b }, - { 0x3123, 0x1e00 }, - { 0x3124, 0x022b }, - { 0x3125, 0x1f00 }, - { 0x3126, 0x622b }, - { 0x3127, 0xf800 }, - { 0x3128, 0x0000 }, - { 0x3129, 0xf000 }, - { 0x312a, 0x0000 }, - { 0x312b, 0xf000 }, - { 0x312c, 0x0000 }, - { 0x312d, 0xf000 }, - { 0x312e, 0x0000 }, - { 0x312f, 0xf000 }, - { 0x3130, 0x0000 }, - { 0x3131, 0xf000 }, - { 0x3132, 0x0000 }, - { 0x3133, 0xf000 }, - { 0x3134, 0x0000 }, - { 0x3135, 0xf000 }, - { 0x3136, 0x0000 }, - { 0x3137, 0xf000 }, - { 0x3138, 0x0000 }, - { 0x3139, 0xf000 }, - { 0x313a, 0x0000 }, - { 0x313b, 0xf000 }, - { 0x313c, 0x0000 }, - { 0x313d, 0xf000 }, - { 0x313e, 0x0000 }, - { 0x313f, 0xf000 }, - { 0x3140, 0x0000 }, - { 0x3141, 0xf000 }, - { 0x3142, 0x0000 }, - { 0x3143, 0xf000 }, - { 0x3144, 0x0000 }, - { 0x3145, 0xf000 }, - { 0x3146, 0x0000 }, - { 0x3147, 0xf000 }, - { 0x3148, 0x0000 }, - { 0x3149, 0xf000 }, - { 0x314a, 0x0000 }, - { 0x314b, 0xf000 }, - { 0x314c, 0x0000 }, - { 0x314d, 0xf000 }, - { 0x314e, 0x0000 }, - { 0x314f, 0xf000 }, - { 0x3150, 0x0000 }, - { 0x3151, 0xf000 }, - { 0x3152, 0x0000 }, - { 0x3153, 0xf000 }, - { 0x3154, 0x0000 }, - { 0x3155, 0xf000 }, - { 0x3156, 0x0000 }, - { 0x3157, 0xf000 }, - { 0x3158, 0x0000 }, - { 0x3159, 0xf000 }, - { 0x315a, 0x0000 }, - { 0x315b, 0xf000 }, - { 0x315c, 0x0000 }, - { 0x315d, 0xf000 }, - { 0x315e, 0x0000 }, - { 0x315f, 0xf000 }, - { 0x3160, 0x0000 }, - { 0x3161, 0xf000 }, - { 0x3162, 0x0000 }, - { 0x3163, 0xf000 }, - { 0x3164, 0x0000 }, - { 0x3165, 0xf000 }, - { 0x3166, 0x0000 }, - { 0x3167, 0xf000 }, - { 0x3168, 0x0000 }, - { 0x3169, 0xf000 }, - { 0x316a, 0x0000 }, - { 0x316b, 0xf000 }, - { 0x316c, 0x0000 }, - { 0x316d, 0xf000 }, - { 0x316e, 0x0000 }, - { 0x316f, 0xf000 }, - { 0x3170, 0x0000 }, - { 0x3171, 0xf000 }, - { 0x3172, 0x0000 }, - { 0x3173, 0xf000 }, - { 0x3174, 0x0000 }, - { 0x3175, 0xf000 }, - { 0x3176, 0x0000 }, - { 0x3177, 0xf000 }, - { 0x3178, 0x0000 }, - { 0x3179, 0xf000 }, - { 0x317a, 0x0000 }, - { 0x317b, 0xf000 }, - { 0x317c, 0x0000 }, - { 0x317d, 0xf000 }, - { 0x317e, 0x0000 }, - { 0x317f, 0xf000 }, - { 0x3180, 0x2001 }, - { 0x3181, 0xf101 }, - { 0x3182, 0x0000 }, - { 0x3183, 0xf000 }, - { 0x3184, 0x0000 }, - { 0x3185, 0xf000 }, - { 0x3186, 0x0000 }, - { 0x3187, 0xf000 }, - { 0x3188, 0x0000 }, - { 0x3189, 0xf000 }, - { 0x318a, 0x0000 }, - { 0x318b, 0xf000 }, - { 0x318c, 0x0000 }, - { 0x318d, 0xf000 }, - { 0x318e, 0x0000 }, - { 0x318f, 0xf000 }, - { 0x3190, 0x0000 }, - { 0x3191, 0xf000 }, - { 0x3192, 0x0000 }, - { 0x3193, 0xf000 }, - { 0x3194, 0x0000 }, - { 0x3195, 0xf000 }, - { 0x3196, 0x0000 }, - { 0x3197, 0xf000 }, - { 0x3198, 0x0000 }, - { 0x3199, 0xf000 }, - { 0x319a, 0x0000 }, - { 0x319b, 0xf000 }, - { 0x319c, 0x0000 }, - { 0x319d, 0xf000 }, - { 0x319e, 0x0000 }, - { 0x319f, 0xf000 }, - { 0x31a0, 0x0000 }, - { 0x31a1, 0xf000 }, - { 0x31a2, 0x0000 }, - { 0x31a3, 0xf000 }, - { 0x31a4, 0x0000 }, - { 0x31a5, 0xf000 }, - { 0x31a6, 0x0000 }, - { 0x31a7, 0xf000 }, - { 0x31a8, 0x0000 }, - { 0x31a9, 0xf000 }, - { 0x31aa, 0x0000 }, - { 0x31ab, 0xf000 }, - { 0x31ac, 0x0000 }, - { 0x31ad, 0xf000 }, - { 0x31ae, 0x0000 }, - { 0x31af, 0xf000 }, - { 0x31b0, 0x0000 }, - { 0x31b1, 0xf000 }, - { 0x31b2, 0x0000 }, - { 0x31b3, 0xf000 }, - { 0x31b4, 0x0000 }, - { 0x31b5, 0xf000 }, - { 0x31b6, 0x0000 }, - { 0x31b7, 0xf000 }, - { 0x31b8, 0x0000 }, - { 0x31b9, 0xf000 }, - { 0x31ba, 0x0000 }, - { 0x31bb, 0xf000 }, - { 0x31bc, 0x0000 }, - { 0x31bd, 0xf000 }, - { 0x31be, 0x0000 }, - { 0x31bf, 0xf000 }, - { 0x31c0, 0x0000 }, - { 0x31c1, 0xf000 }, - { 0x31c2, 0x0000 }, - { 0x31c3, 0xf000 }, - { 0x31c4, 0x0000 }, - { 0x31c5, 0xf000 }, - { 0x31c6, 0x0000 }, - { 0x31c7, 0xf000 }, - { 0x31c8, 0x0000 }, - { 0x31c9, 0xf000 }, - { 0x31ca, 0x0000 }, - { 0x31cb, 0xf000 }, - { 0x31cc, 0x0000 }, - { 0x31cd, 0xf000 }, - { 0x31ce, 0x0000 }, - { 0x31cf, 0xf000 }, - { 0x31d0, 0x0000 }, - { 0x31d1, 0xf000 }, - { 0x31d2, 0x0000 }, - { 0x31d3, 0xf000 }, - { 0x31d4, 0x0000 }, - { 0x31d5, 0xf000 }, - { 0x31d6, 0x0000 }, - { 0x31d7, 0xf000 }, - { 0x31d8, 0x0000 }, - { 0x31d9, 0xf000 }, - { 0x31da, 0x0000 }, - { 0x31db, 0xf000 }, - { 0x31dc, 0x0000 }, - { 0x31dd, 0xf000 }, - { 0x31de, 0x0000 }, - { 0x31df, 0xf000 }, - { 0x31e0, 0x0000 }, - { 0x31e1, 0xf000 }, - { 0x31e2, 0x0000 }, - { 0x31e3, 0xf000 }, - { 0x31e4, 0x0000 }, - { 0x31e5, 0xf000 }, - { 0x31e6, 0x0000 }, - { 0x31e7, 0xf000 }, - { 0x31e8, 0x0000 }, - { 0x31e9, 0xf000 }, - { 0x31ea, 0x0000 }, - { 0x31eb, 0xf000 }, - { 0x31ec, 0x0000 }, - { 0x31ed, 0xf000 }, - { 0x31ee, 0x0000 }, - { 0x31ef, 0xf000 }, - { 0x31f0, 0x0000 }, - { 0x31f1, 0xf000 }, - { 0x31f2, 0x0000 }, - { 0x31f3, 0xf000 }, - { 0x31f4, 0x0000 }, - { 0x31f5, 0xf000 }, - { 0x31f6, 0x0000 }, - { 0x31f7, 0xf000 }, - { 0x31f8, 0x0000 }, - { 0x31f9, 0xf000 }, - { 0x31fa, 0x0000 }, - { 0x31fb, 0xf000 }, - { 0x31fc, 0x0000 }, - { 0x31fd, 0xf000 }, - { 0x31fe, 0x0000 }, - { 0x31ff, 0xf000 }, - { 0x024d, 0xff50 }, - { 0x0252, 0xff50 }, - { 0x0259, 0x0112 }, - { 0x025e, 0x0112 }, - { 0x101, 0x0304 }, { 0x80, 0x0000 }, }; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 374c46d..ec794a7 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1077,7 +1077,8 @@ EXPORT_SYMBOL_GPL(mtd_writev); * until the request succeeds or until the allocation size falls below * the system page size. This attempts to make sure it does not adversely * impact system performance, so when allocating more than one page, we - * ask the memory allocator to avoid re-trying. + * ask the memory allocator to avoid re-trying, swapping, writing back + * or performing I/O. * * Note, this function also makes sure that the allocated buffer is aligned to * the MTD device's min. I/O unit, i.e. the "mtd->writesize" value. @@ -1091,7 +1092,8 @@ EXPORT_SYMBOL_GPL(mtd_writev); */ void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size) { - gfp_t flags = __GFP_NOWARN | __GFP_WAIT | __GFP_NORETRY; + gfp_t flags = __GFP_NOWARN | __GFP_WAIT | + __GFP_NORETRY | __GFP_NO_KSWAPD; size_t min_alloc = max_t(size_t, mtd->writesize, PAGE_SIZE); void *kbuf; diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index e15cc11..7c9d136 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -84,6 +84,10 @@ static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb) /* Forward declaration */ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]); +static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp); +static void rlb_src_unlink(struct bonding *bond, u32 index); +static void rlb_src_link(struct bonding *bond, u32 ip_src_hash, + u32 ip_dst_hash); static inline u8 _simple_hash(const u8 *hash_start, int hash_size) { @@ -354,6 +358,18 @@ static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond, if (!arp) goto out; + /* We received an ARP from arp->ip_src. + * We might have used this IP address previously (on the bonding host + * itself or on a system that is bridged together with the bond). + * However, if arp->mac_src is different than what is stored in + * rx_hashtbl, some other host is now using the IP and we must prevent + * sending out client updates with this IP address and the old MAC + * address. + * Clean up all hash table entries that have this address as ip_src but + * have a different mac_src. + */ + rlb_purge_src_ip(bond, arp); + if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ rlb_update_entry_from_arp(bond, arp); @@ -432,9 +448,9 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) _lock_rx_hashtbl_bh(bond); rx_hash_table = bond_info->rx_hashtbl; - index = bond_info->rx_hashtbl_head; + index = bond_info->rx_hashtbl_used_head; for (; index != RLB_NULL_INDEX; index = next_index) { - next_index = rx_hash_table[index].next; + next_index = rx_hash_table[index].used_next; if (rx_hash_table[index].slave == slave) { struct slave *assigned_slave = rlb_next_rx_slave(bond); @@ -519,8 +535,9 @@ static void rlb_update_rx_clients(struct bonding *bond) _lock_rx_hashtbl_bh(bond); - hash_index = bond_info->rx_hashtbl_head; - for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { + hash_index = bond_info->rx_hashtbl_used_head; + for (; hash_index != RLB_NULL_INDEX; + hash_index = client_info->used_next) { client_info = &(bond_info->rx_hashtbl[hash_index]); if (client_info->ntt) { rlb_update_client(client_info); @@ -548,8 +565,9 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla _lock_rx_hashtbl_bh(bond); - hash_index = bond_info->rx_hashtbl_head; - for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { + hash_index = bond_info->rx_hashtbl_used_head; + for (; hash_index != RLB_NULL_INDEX; + hash_index = client_info->used_next) { client_info = &(bond_info->rx_hashtbl[hash_index]); if ((client_info->slave == slave) && @@ -578,8 +596,9 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip) _lock_rx_hashtbl(bond); - hash_index = bond_info->rx_hashtbl_head; - for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { + hash_index = bond_info->rx_hashtbl_used_head; + for (; hash_index != RLB_NULL_INDEX; + hash_index = client_info->used_next) { client_info = &(bond_info->rx_hashtbl[hash_index]); if (!client_info->slave) { @@ -625,6 +644,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon /* update mac address from arp */ memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); } + memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN); assigned_slave = client_info->slave; if (assigned_slave) { @@ -647,6 +667,17 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon assigned_slave = rlb_next_rx_slave(bond); if (assigned_slave) { + if (!(client_info->assigned && + client_info->ip_src == arp->ip_src)) { + /* ip_src is going to be updated, + * fix the src hash list + */ + u32 hash_src = _simple_hash((u8 *)&arp->ip_src, + sizeof(arp->ip_src)); + rlb_src_unlink(bond, hash_index); + rlb_src_link(bond, hash_src, hash_index); + } + client_info->ip_src = arp->ip_src; client_info->ip_dst = arp->ip_dst; /* arp->mac_dst is broadcast for arp reqeusts. @@ -654,6 +685,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon * upon receiving an arp reply. */ memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); + memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN); client_info->slave = assigned_slave; if (!ether_addr_equal_64bits(client_info->mac_dst, mac_bcast)) { @@ -669,11 +701,11 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon } if (!client_info->assigned) { - u32 prev_tbl_head = bond_info->rx_hashtbl_head; - bond_info->rx_hashtbl_head = hash_index; - client_info->next = prev_tbl_head; + u32 prev_tbl_head = bond_info->rx_hashtbl_used_head; + bond_info->rx_hashtbl_used_head = hash_index; + client_info->used_next = prev_tbl_head; if (prev_tbl_head != RLB_NULL_INDEX) { - bond_info->rx_hashtbl[prev_tbl_head].prev = + bond_info->rx_hashtbl[prev_tbl_head].used_prev = hash_index; } client_info->assigned = 1; @@ -694,6 +726,12 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) struct arp_pkt *arp = arp_pkt(skb); struct slave *tx_slave = NULL; + /* Don't modify or load balance ARPs that do not originate locally + * (e.g.,arrive via a bridge). + */ + if (!bond_slave_has_mac(bond, arp->mac_src)) + return NULL; + if (arp->op_code == htons(ARPOP_REPLY)) { /* the arp must be sent on the selected * rx channel @@ -740,8 +778,9 @@ static void rlb_rebalance(struct bonding *bond) _lock_rx_hashtbl_bh(bond); ntt = 0; - hash_index = bond_info->rx_hashtbl_head; - for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { + hash_index = bond_info->rx_hashtbl_used_head; + for (; hash_index != RLB_NULL_INDEX; + hash_index = client_info->used_next) { client_info = &(bond_info->rx_hashtbl[hash_index]); assigned_slave = rlb_next_rx_slave(bond); if (assigned_slave && (client_info->slave != assigned_slave)) { @@ -759,11 +798,113 @@ static void rlb_rebalance(struct bonding *bond) } /* Caller must hold rx_hashtbl lock */ +static void rlb_init_table_entry_dst(struct rlb_client_info *entry) +{ + entry->used_next = RLB_NULL_INDEX; + entry->used_prev = RLB_NULL_INDEX; + entry->assigned = 0; + entry->slave = NULL; + entry->tag = 0; +} +static void rlb_init_table_entry_src(struct rlb_client_info *entry) +{ + entry->src_first = RLB_NULL_INDEX; + entry->src_prev = RLB_NULL_INDEX; + entry->src_next = RLB_NULL_INDEX; +} + static void rlb_init_table_entry(struct rlb_client_info *entry) { memset(entry, 0, sizeof(struct rlb_client_info)); - entry->next = RLB_NULL_INDEX; - entry->prev = RLB_NULL_INDEX; + rlb_init_table_entry_dst(entry); + rlb_init_table_entry_src(entry); +} + +static void rlb_delete_table_entry_dst(struct bonding *bond, u32 index) +{ + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + u32 next_index = bond_info->rx_hashtbl[index].used_next; + u32 prev_index = bond_info->rx_hashtbl[index].used_prev; + + if (index == bond_info->rx_hashtbl_used_head) + bond_info->rx_hashtbl_used_head = next_index; + if (prev_index != RLB_NULL_INDEX) + bond_info->rx_hashtbl[prev_index].used_next = next_index; + if (next_index != RLB_NULL_INDEX) + bond_info->rx_hashtbl[next_index].used_prev = prev_index; +} + +/* unlink a rlb hash table entry from the src list */ +static void rlb_src_unlink(struct bonding *bond, u32 index) +{ + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + u32 next_index = bond_info->rx_hashtbl[index].src_next; + u32 prev_index = bond_info->rx_hashtbl[index].src_prev; + + bond_info->rx_hashtbl[index].src_next = RLB_NULL_INDEX; + bond_info->rx_hashtbl[index].src_prev = RLB_NULL_INDEX; + + if (next_index != RLB_NULL_INDEX) + bond_info->rx_hashtbl[next_index].src_prev = prev_index; + + if (prev_index == RLB_NULL_INDEX) + return; + + /* is prev_index pointing to the head of this list? */ + if (bond_info->rx_hashtbl[prev_index].src_first == index) + bond_info->rx_hashtbl[prev_index].src_first = next_index; + else + bond_info->rx_hashtbl[prev_index].src_next = next_index; + +} + +static void rlb_delete_table_entry(struct bonding *bond, u32 index) +{ + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct rlb_client_info *entry = &(bond_info->rx_hashtbl[index]); + + rlb_delete_table_entry_dst(bond, index); + rlb_init_table_entry_dst(entry); + + rlb_src_unlink(bond, index); +} + +/* add the rx_hashtbl[ip_dst_hash] entry to the list + * of entries with identical ip_src_hash + */ +static void rlb_src_link(struct bonding *bond, u32 ip_src_hash, u32 ip_dst_hash) +{ + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + u32 next; + + bond_info->rx_hashtbl[ip_dst_hash].src_prev = ip_src_hash; + next = bond_info->rx_hashtbl[ip_src_hash].src_first; + bond_info->rx_hashtbl[ip_dst_hash].src_next = next; + if (next != RLB_NULL_INDEX) + bond_info->rx_hashtbl[next].src_prev = ip_dst_hash; + bond_info->rx_hashtbl[ip_src_hash].src_first = ip_dst_hash; +} + +/* deletes all rx_hashtbl entries with arp->ip_src if their mac_src does + * not match arp->mac_src */ +static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp) +{ + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + u32 ip_src_hash = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src)); + u32 index; + + _lock_rx_hashtbl_bh(bond); + + index = bond_info->rx_hashtbl[ip_src_hash].src_first; + while (index != RLB_NULL_INDEX) { + struct rlb_client_info *entry = &(bond_info->rx_hashtbl[index]); + u32 next_index = entry->src_next; + if (entry->ip_src == arp->ip_src && + !ether_addr_equal_64bits(arp->mac_src, entry->mac_src)) + rlb_delete_table_entry(bond, index); + index = next_index; + } + _unlock_rx_hashtbl_bh(bond); } static int rlb_initialize(struct bonding *bond) @@ -781,7 +922,7 @@ static int rlb_initialize(struct bonding *bond) bond_info->rx_hashtbl = new_hashtbl; - bond_info->rx_hashtbl_head = RLB_NULL_INDEX; + bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX; for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) { rlb_init_table_entry(bond_info->rx_hashtbl + i); @@ -803,7 +944,7 @@ static void rlb_deinitialize(struct bonding *bond) kfree(bond_info->rx_hashtbl); bond_info->rx_hashtbl = NULL; - bond_info->rx_hashtbl_head = RLB_NULL_INDEX; + bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX; _unlock_rx_hashtbl_bh(bond); } @@ -815,25 +956,13 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id) _lock_rx_hashtbl_bh(bond); - curr_index = bond_info->rx_hashtbl_head; + curr_index = bond_info->rx_hashtbl_used_head; while (curr_index != RLB_NULL_INDEX) { struct rlb_client_info *curr = &(bond_info->rx_hashtbl[curr_index]); - u32 next_index = bond_info->rx_hashtbl[curr_index].next; - u32 prev_index = bond_info->rx_hashtbl[curr_index].prev; - - if (curr->tag && (curr->vlan_id == vlan_id)) { - if (curr_index == bond_info->rx_hashtbl_head) { - bond_info->rx_hashtbl_head = next_index; - } - if (prev_index != RLB_NULL_INDEX) { - bond_info->rx_hashtbl[prev_index].next = next_index; - } - if (next_index != RLB_NULL_INDEX) { - bond_info->rx_hashtbl[next_index].prev = prev_index; - } + u32 next_index = bond_info->rx_hashtbl[curr_index].used_next; - rlb_init_table_entry(curr); - } + if (curr->tag && (curr->vlan_id == vlan_id)) + rlb_delete_table_entry(bond, curr_index); curr_index = next_index; } diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 90f140a..e7a5b8b 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -94,15 +94,35 @@ struct tlb_client_info { /* ------------------------------------------------------------------------- * struct rlb_client_info contains all info related to a specific rx client - * connection. This is the Clients Hash Table entry struct + * connection. This is the Clients Hash Table entry struct. + * Note that this is not a proper hash table; if a new client's IP address + * hash collides with an existing client entry, the old entry is replaced. + * + * There is a linked list (linked by the used_next and used_prev members) + * linking all the used entries of the hash table. This allows updating + * all the clients without walking over all the unused elements of the table. + * + * There are also linked lists of entries with identical hash(ip_src). These + * allow cleaning up the table from ip_src<->mac_src associations that have + * become outdated and would cause sending out invalid ARP updates to the + * network. These are linked by the (src_next and src_prev members). * ------------------------------------------------------------------------- */ struct rlb_client_info { __be32 ip_src; /* the server IP address */ __be32 ip_dst; /* the client IP address */ + u8 mac_src[ETH_ALEN]; /* the server MAC address */ u8 mac_dst[ETH_ALEN]; /* the client MAC address */ - u32 next; /* The next Hash table entry index */ - u32 prev; /* The previous Hash table entry index */ + + /* list of used hash table entries, starting at rx_hashtbl_used_head */ + u32 used_next; + u32 used_prev; + + /* ip_src based hashing */ + u32 src_next; /* next entry with same hash(ip_src) */ + u32 src_prev; /* prev entry with same hash(ip_src) */ + u32 src_first; /* first entry with hash(ip_src) == this entry's index */ + u8 assigned; /* checking whether this entry is assigned */ u8 ntt; /* flag - need to transmit client info */ struct slave *slave; /* the slave assigned to this client */ @@ -131,7 +151,7 @@ struct alb_bond_info { int rlb_enabled; struct rlb_client_info *rx_hashtbl; /* Receive hash table */ spinlock_t rx_hashtbl_lock; - u32 rx_hashtbl_head; + u32 rx_hashtbl_used_head; u8 rx_ntt; /* flag - need to transmit * to all rx clients */ diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c index 2cf084e..5fc4c23 100644 --- a/drivers/net/bonding/bond_debugfs.c +++ b/drivers/net/bonding/bond_debugfs.c @@ -31,8 +31,9 @@ static int bond_debug_rlb_hash_show(struct seq_file *m, void *v) spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); - hash_index = bond_info->rx_hashtbl_head; - for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { + hash_index = bond_info->rx_hashtbl_used_head; + for (; hash_index != RLB_NULL_INDEX; + hash_index = client_info->used_next) { client_info = &(bond_info->rx_hashtbl[hash_index]); seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n", &client_info->ip_src, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index f8af2fc..6dded56 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,6 +22,7 @@ #include <linux/in6.h> #include <linux/netpoll.h> #include <linux/inetdevice.h> +#include <linux/etherdevice.h> #include "bond_3ad.h" #include "bond_alb.h" @@ -450,6 +451,18 @@ static inline void bond_destroy_proc_dir(struct bond_net *bn) } #endif +static inline struct slave *bond_slave_has_mac(struct bonding *bond, + const u8 *mac) +{ + int i = 0; + struct slave *tmp; + + bond_for_each_slave(bond, tmp, i) + if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr)) + return tmp; + + return NULL; +} /* exported from bond_main.c */ extern int bond_net_id; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 86f26a1..25723d8 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -519,8 +519,10 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, mc->pdev->dev.can.state = new_state; if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) { + struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb); + peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts->hwtstamp = timeval_to_ktime(tv); } netif_rx(skb); @@ -605,6 +607,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) struct sk_buff *skb; struct can_frame *cf; struct timeval tv; + struct skb_shared_hwtstamps *hwts; skb = alloc_can_skb(mc->netdev, &cf); if (!skb) @@ -652,7 +655,8 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) /* convert timestamp into kernel time */ peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); /* push the skb */ netif_rx(skb); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index e1626d9..30d79bf 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -532,6 +532,7 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, struct can_frame *can_frame; struct sk_buff *skb; struct timeval tv; + struct skb_shared_hwtstamps *hwts; skb = alloc_can_skb(netdev, &can_frame); if (!skb) @@ -549,7 +550,8 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, memcpy(can_frame->data, rx->data, can_frame->can_dlc); peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(rx->ts32), &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); netif_rx(skb); netdev->stats.rx_packets++; @@ -570,6 +572,7 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, u8 err_mask = 0; struct sk_buff *skb; struct timeval tv; + struct skb_shared_hwtstamps *hwts; /* nothing should be sent while in BUS_OFF state */ if (dev->can.state == CAN_STATE_BUS_OFF) @@ -664,7 +667,8 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, dev->can.state = new_state; peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); netif_rx(skb); netdev->stats.rx_packets++; netdev->stats.rx_bytes += can_frame->can_dlc; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index 5d367958..b799ab12 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -237,7 +237,7 @@ static int mlx4_en_dcbnl_ieee_setmaxrate(struct net_device *dev, if (err) return err; - memcpy(priv->maxrate, tmp, sizeof(*priv->maxrate)); + memcpy(priv->maxrate, tmp, sizeof(priv->maxrate)); return 0; } diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index d44cca3..ad86660 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1794,10 +1794,12 @@ static void team_setup(struct net_device *dev) dev->features |= NETIF_F_LLTX; dev->features |= NETIF_F_GRO; - dev->hw_features = NETIF_F_HW_VLAN_TX | + dev->hw_features = TEAM_VLAN_FEATURES | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM); dev->features |= dev->hw_features; } diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 3b566fa..1ea91f4 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -385,6 +385,7 @@ static const struct usb_device_id products[] = { }, /* 3. Combined interface devices matching on interface number */ + {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x19d2, 0x0002, 1)}, {QMI_FIXED_INTF(0x19d2, 0x0012, 1)}, {QMI_FIXED_INTF(0x19d2, 0x0017, 3)}, diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index f87d7e8..4e0d0c3 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -539,25 +539,25 @@ static void insert_char(struct vc_data *vc, unsigned int nr) { unsigned short *p = (unsigned short *) vc->vc_pos; - scr_memmovew(p + nr, p, vc->vc_cols - vc->vc_x); + scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x) * 2); scr_memsetw(p, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; if (DO_UPDATE(vc)) do_update_region(vc, (unsigned long) p, - (vc->vc_cols - vc->vc_x) / 2 + 1); + vc->vc_cols - vc->vc_x); } static void delete_char(struct vc_data *vc, unsigned int nr) { unsigned short *p = (unsigned short *) vc->vc_pos; - scr_memcpyw(p, p + nr, vc->vc_cols - vc->vc_x - nr); + scr_memcpyw(p, p + nr, (vc->vc_cols - vc->vc_x - nr) * 2); scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; if (DO_UPDATE(vc)) do_update_region(vc, (unsigned long) p, - (vc->vc_cols - vc->vc_x) / 2); + vc->vc_cols - vc->vc_x); } static int softcursor_original; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index ef8f598..5a3d0f1 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1049,7 +1049,7 @@ static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len, } _iov = iov + ret; size = reg->memory_size - addr + reg->guest_phys_addr; - _iov->iov_len = min((u64)len, size); + _iov->iov_len = min((u64)len - s, size); _iov->iov_base = (void __user *)(unsigned long) (reg->userspace_addr + addr - reg->guest_phys_addr); s += size; diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 51ea267..3e3422f 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -228,6 +228,8 @@ static void requeue_io(struct inode *inode, struct bdi_writeback *wb) static void inode_sync_complete(struct inode *inode) { inode->i_state &= ~I_SYNC; + /* If inode is clean an unused, put it into LRU now... */ + inode_add_lru(inode); /* Waiters must see I_SYNC cleared before being woken up */ smp_mb(); wake_up_bit(&inode->i_state, __I_SYNC); @@ -408,6 +408,19 @@ static void inode_lru_list_add(struct inode *inode) spin_unlock(&inode->i_sb->s_inode_lru_lock); } +/* + * Add inode to LRU if needed (inode is unused and clean). + * + * Needs inode->i_lock held. + */ +void inode_add_lru(struct inode *inode) +{ + if (!(inode->i_state & (I_DIRTY | I_SYNC | I_FREEING | I_WILL_FREE)) && + !atomic_read(&inode->i_count) && inode->i_sb->s_flags & MS_ACTIVE) + inode_lru_list_add(inode); +} + + static void inode_lru_list_del(struct inode *inode) { spin_lock(&inode->i_sb->s_inode_lru_lock); @@ -1390,8 +1403,7 @@ static void iput_final(struct inode *inode) if (!drop && (sb->s_flags & MS_ACTIVE)) { inode->i_state |= I_REFERENCED; - if (!(inode->i_state & (I_DIRTY|I_SYNC))) - inode_lru_list_add(inode); + inode_add_lru(inode); spin_unlock(&inode->i_lock); return; } diff --git a/fs/internal.h b/fs/internal.h index 916b7cb..2f6af7f 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -110,6 +110,7 @@ extern int open_check_o_direct(struct file *f); * inode.c */ extern spinlock_t inode_sb_list_lock; +extern void inode_add_lru(struct inode *inode); /* * fs-writeback.c diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 78b7f84..7f5120b 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1961,7 +1961,9 @@ retry: spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); spin_unlock(&journal->j_state_lock); + unlock_buffer(bh); log_wait_commit(journal, tid); + lock_buffer(bh); goto retry; } /* diff --git a/fs/proc/base.c b/fs/proc/base.c index 3c231ad..9e28356 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1877,8 +1877,9 @@ static struct dentry *proc_map_files_lookup(struct inode *dir, if (!vma) goto out_no_vma; - result = proc_map_files_instantiate(dir, dentry, task, - (void *)(unsigned long)vma->vm_file->f_mode); + if (vma->vm_file) + result = proc_map_files_instantiate(dir, dentry, task, + (void *)(unsigned long)vma->vm_file->f_mode); out_no_vma: up_read(&mm->mmap_sem); diff --git a/include/linux/bug.h b/include/linux/bug.h index aaac4bb..b1cf40d 100644 --- a/include/linux/bug.h +++ b/include/linux/bug.h @@ -15,6 +15,7 @@ struct pt_regs; #define BUILD_BUG_ON_NOT_POWER_OF_2(n) #define BUILD_BUG_ON_ZERO(e) (0) #define BUILD_BUG_ON_NULL(e) ((void*)0) +#define BUILD_BUG_ON_INVALID(e) (0) #define BUILD_BUG_ON(condition) #define BUILD_BUG() (0) #else /* __CHECKER__ */ diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 02c1c97..d0a7967 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -31,6 +31,7 @@ struct vm_area_struct; #define ___GFP_THISNODE 0x40000u #define ___GFP_RECLAIMABLE 0x80000u #define ___GFP_NOTRACK 0x200000u +#define ___GFP_NO_KSWAPD 0x400000u #define ___GFP_OTHER_NODE 0x800000u #define ___GFP_WRITE 0x1000000u @@ -85,6 +86,7 @@ struct vm_area_struct; #define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE) /* Page is reclaimable */ #define __GFP_NOTRACK ((__force gfp_t)___GFP_NOTRACK) /* Don't track with kmemcheck */ +#define __GFP_NO_KSWAPD ((__force gfp_t)___GFP_NO_KSWAPD) #define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */ #define __GFP_WRITE ((__force gfp_t)___GFP_WRITE) /* Allocator intends to dirty page */ @@ -114,7 +116,8 @@ struct vm_area_struct; __GFP_MOVABLE) #define GFP_IOFS (__GFP_IO | __GFP_FS) #define GFP_TRANSHUGE (GFP_HIGHUSER_MOVABLE | __GFP_COMP | \ - __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN) + __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN | \ + __GFP_NO_KSWAPD) #ifdef CONFIG_NUMA #define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e9929ab..18c5dc9 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2153,16 +2153,10 @@ extern void dev_kfree_skb_any(struct sk_buff *skb); extern int netif_rx(struct sk_buff *skb); extern int netif_rx_ni(struct sk_buff *skb); extern int netif_receive_skb(struct sk_buff *skb); -extern gro_result_t dev_gro_receive(struct napi_struct *napi, - struct sk_buff *skb); -extern gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb); extern gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb); extern void napi_gro_flush(struct napi_struct *napi, bool flush_old); extern struct sk_buff * napi_get_frags(struct napi_struct *napi); -extern gro_result_t napi_frags_finish(struct napi_struct *napi, - struct sk_buff *skb, - gro_result_t ret); extern gro_result_t napi_gro_frags(struct napi_struct *napi); static inline void napi_free_frags(struct napi_struct *napi) diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 5f84c62..610208b1 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -47,15 +47,6 @@ ip6t_ext_hdr(u8 nexthdr) (nexthdr == IPPROTO_DSTOPTS); } -enum { - IP6T_FH_F_FRAG = (1 << 0), - IP6T_FH_F_AUTH = (1 << 1), -}; - -/* find specified header and get offset to it */ -extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, - int target, unsigned short *fragoff, int *fragflg); - #ifdef CONFIG_COMPAT #include <net/compat.h> diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h index eb1efa5..d42e174 100644 --- a/include/linux/openvswitch.h +++ b/include/linux/openvswitch.h @@ -243,6 +243,7 @@ enum ovs_key_attr { OVS_KEY_ATTR_ICMPV6, /* struct ovs_key_icmpv6 */ OVS_KEY_ATTR_ARP, /* struct ovs_key_arp */ OVS_KEY_ATTR_ND, /* struct ovs_key_nd */ + OVS_KEY_ATTR_SKB_MARK, /* u32 skb mark */ __OVS_KEY_ATTR_MAX }; diff --git a/include/linux/percpu-rwsem.h b/include/linux/percpu-rwsem.h index 250a4ac..bd1e860 100644 --- a/include/linux/percpu-rwsem.h +++ b/include/linux/percpu-rwsem.h @@ -13,7 +13,7 @@ struct percpu_rw_semaphore { }; #define light_mb() barrier() -#define heavy_mb() synchronize_sched() +#define heavy_mb() synchronize_sched_expedited() static inline void percpu_down_read(struct percpu_rw_semaphore *p) { @@ -51,7 +51,7 @@ static inline void percpu_down_write(struct percpu_rw_semaphore *p) { mutex_lock(&p->mtx); p->locked = true; - synchronize_sched(); /* make sure that all readers exit the rcu_read_lock_sched region */ + synchronize_sched_expedited(); /* make sure that all readers exit the rcu_read_lock_sched region */ while (__percpu_count(p->counters)) msleep(1); heavy_mb(); /* C, between read of p->counter and write to data, paired with B */ diff --git a/include/media/adv7604.h b/include/media/adv7604.h index 171b957..dc004bc 100644 --- a/include/media/adv7604.h +++ b/include/media/adv7604.h @@ -40,14 +40,6 @@ enum adv7604_op_ch_sel { ADV7604_OP_CH_SEL_RBG = 5, }; -/* Primary mode (IO register 0x01, [3:0]) */ -enum adv7604_prim_mode { - ADV7604_PRIM_MODE_COMP = 1, - ADV7604_PRIM_MODE_RGB = 2, - ADV7604_PRIM_MODE_HDMI_COMP = 5, - ADV7604_PRIM_MODE_HDMI_GR = 6, -}; - /* Input Color Space (IO register 0x02, [7:4]) */ enum adv7604_inp_color_space { ADV7604_INP_COLOR_SPACE_LIM_RGB = 0, @@ -103,9 +95,6 @@ struct adv7604_platform_data { /* Bus rotation and reordering */ enum adv7604_op_ch_sel op_ch_sel; - /* Primary mode */ - enum adv7604_prim_mode prim_mode; - /* Select output format */ enum adv7604_op_format_sel op_format_sel; @@ -142,6 +131,16 @@ struct adv7604_platform_data { u8 i2c_vdp; }; +/* + * Mode of operation. + * This is used as the input argument of the s_routing video op. + */ +enum adv7604_mode { + ADV7604_MODE_COMP, + ADV7604_MODE_GR, + ADV7604_MODE_HDMI, +}; + #define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CLASS_BASE + 0x1000) #define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL (V4L2_CID_DV_CLASS_BASE + 0x1001) #define V4L2_CID_ADV_RX_FREE_RUN_COLOR (V4L2_CID_DV_CLASS_BASE + 0x1002) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 979bf6c..acbd8e0 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -630,6 +630,16 @@ extern int ipv6_skip_exthdr(const struct sk_buff *, int start, extern bool ipv6_ext_hdr(u8 nexthdr); +enum { + IP6_FH_F_FRAG = (1 << 0), + IP6_FH_F_AUTH = (1 << 1), + IP6_FH_F_SKIP_RH = (1 << 2), +}; + +/* find specified header and get offset to it */ +extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, + int target, unsigned short *fragoff, int *fragflg); + extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type); extern struct in6_addr *fl6_update_dst(struct flowi6 *fl6, diff --git a/include/trace/events/gfpflags.h b/include/trace/events/gfpflags.h index 9391706..d6fd8e5 100644 --- a/include/trace/events/gfpflags.h +++ b/include/trace/events/gfpflags.h @@ -36,6 +36,7 @@ {(unsigned long)__GFP_RECLAIMABLE, "GFP_RECLAIMABLE"}, \ {(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" diff --git a/kernel/futex.c b/kernel/futex.c index 20ef219..19eb089 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -843,6 +843,9 @@ static void wake_futex(struct futex_q *q) { struct task_struct *p = q->task; + if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n")) + return; + /* * We set q->lock_ptr = NULL _before_ we wake up the task. If * a non-futex wake up happens on another CPU then the task @@ -1078,6 +1081,10 @@ retry_private: plist_for_each_entry_safe(this, next, head, list) { if (match_futex (&this->key, &key1)) { + if (this->pi_state || this->rt_waiter) { + ret = -EINVAL; + goto out_unlock; + } wake_futex(this); if (++ret >= nr_wake) break; @@ -1090,6 +1097,10 @@ retry_private: op_ret = 0; plist_for_each_entry_safe(this, next, head, list) { if (match_futex (&this->key, &key2)) { + if (this->pi_state || this->rt_waiter) { + ret = -EINVAL; + goto out_unlock; + } wake_futex(this); if (++op_ret >= nr_wake2) break; @@ -1098,6 +1109,7 @@ retry_private: ret += op_ret; } +out_unlock: double_unlock_hb(hb1, hb2); out_put_keys: put_futex_key(&key2); @@ -1387,9 +1399,13 @@ retry_private: /* * FUTEX_WAIT_REQEUE_PI and FUTEX_CMP_REQUEUE_PI should always * be paired with each other and no other futex ops. + * + * We should never be requeueing a futex_q with a pi_state, + * which is awaiting a futex_unlock_pi(). */ if ((requeue_pi && !this->rt_waiter) || - (!requeue_pi && this->rt_waiter)) { + (!requeue_pi && this->rt_waiter) || + this->pi_state) { ret = -EINVAL; break; } diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 9d4c8d5..dd4b80a 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -116,7 +116,7 @@ static unsigned long get_timestamp(int this_cpu) return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */ } -static unsigned long get_sample_period(void) +static u64 get_sample_period(void) { /* * convert watchdog_thresh from seconds to ns @@ -125,7 +125,7 @@ static unsigned long get_sample_period(void) * and hard thresholds) to increment before the * hardlockup detector generates a warning */ - return get_softlockup_thresh() * (NSEC_PER_SEC / 5); + return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5); } /* Commands for resetting the watchdog */ diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h index 678ce4f..095ab15 100644 --- a/lib/mpi/longlong.h +++ b/lib/mpi/longlong.h @@ -641,7 +641,14 @@ do { \ ************** MIPS ***************** ***************************************/ #if defined(__mips__) && W_TYPE_SIZE == 32 -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#define umul_ppmm(w1, w0, u, v) \ +do { \ + UDItype __ll = (UDItype)(u) * (v); \ + w1 = __ll >> 32; \ + w0 = __ll; \ +} while (0) +#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7 #define umul_ppmm(w1, w0, u, v) \ __asm__ ("multu %2,%3" \ : "=l" ((USItype)(w0)), \ @@ -666,7 +673,15 @@ do { \ ************** MIPS/64 ************** ***************************************/ #if (defined(__mips) && __mips >= 3) && W_TYPE_SIZE == 64 -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7 +#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#define umul_ppmm(w1, w0, u, v) \ +do { \ + typedef unsigned int __ll_UTItype __attribute__((mode(TI))); \ + __ll_UTItype __ll = (__ll_UTItype)(u) * (v); \ + w1 = __ll >> 64; \ + w0 = __ll; \ +} while (0) +#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7 #define umul_ppmm(w1, w0, u, v) \ __asm__ ("dmultu %2,%3" \ : "=l" ((UDItype)(w0)), \ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index bcb72c6..9287157 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2416,8 +2416,9 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, goto nopage; restart: - wake_all_kswapd(order, zonelist, high_zoneidx, - zone_idx(preferred_zone)); + if (!(gfp_mask & __GFP_NO_KSWAPD)) + wake_all_kswapd(order, zonelist, high_zoneidx, + zone_idx(preferred_zone)); /* * OK, we're below the kswapd watermark and have kicked background @@ -2494,7 +2495,7 @@ rebalance: * system then fail the allocation instead of entering direct reclaim. */ if ((deferred_compaction || contended_compaction) && - (gfp_mask & (__GFP_MOVABLE|__GFP_REPEAT)) == __GFP_MOVABLE) + (gfp_mask & __GFP_NO_KSWAPD)) goto nopage; /* Try direct reclaim and then allocating */ diff --git a/mm/vmscan.c b/mm/vmscan.c index 48550c6..cbf84e1 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2207,9 +2207,12 @@ static bool pfmemalloc_watermark_ok(pg_data_t *pgdat) * Throttle direct reclaimers if backing storage is backed by the network * and the PFMEMALLOC reserve for the preferred node is getting dangerously * depleted. kswapd will continue to make progress and wake the processes - * when the low watermark is reached + * when the low watermark is reached. + * + * Returns true if a fatal signal was delivered during throttling. If this + * happens, the page allocator should not consider triggering the OOM killer. */ -static void throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist, +static bool throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist, nodemask_t *nodemask) { struct zone *zone; @@ -2224,13 +2227,20 @@ static void throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist, * processes to block on log_wait_commit(). */ if (current->flags & PF_KTHREAD) - return; + goto out; + + /* + * If a fatal signal is pending, this process should not throttle. + * It should return quickly so it can exit and free its memory + */ + if (fatal_signal_pending(current)) + goto out; /* Check if the pfmemalloc reserves are ok */ first_zones_zonelist(zonelist, high_zoneidx, NULL, &zone); pgdat = zone->zone_pgdat; if (pfmemalloc_watermark_ok(pgdat)) - return; + goto out; /* Account for the throttling */ count_vm_event(PGSCAN_DIRECT_THROTTLE); @@ -2246,12 +2256,20 @@ static void throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist, if (!(gfp_mask & __GFP_FS)) { wait_event_interruptible_timeout(pgdat->pfmemalloc_wait, pfmemalloc_watermark_ok(pgdat), HZ); - return; + + goto check_pending; } /* Throttle until kswapd wakes the process */ wait_event_killable(zone->zone_pgdat->pfmemalloc_wait, pfmemalloc_watermark_ok(pgdat)); + +check_pending: + if (fatal_signal_pending(current)) + return true; + +out: + return false; } unsigned long try_to_free_pages(struct zonelist *zonelist, int order, @@ -2273,13 +2291,12 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order, .gfp_mask = sc.gfp_mask, }; - throttle_direct_reclaim(gfp_mask, zonelist, nodemask); - /* - * Do not enter reclaim if fatal signal is pending. 1 is returned so - * that the page allocator does not consider triggering OOM + * Do not enter reclaim if fatal signal was delivered while throttled. + * 1 is returned so that the page allocator does not OOM kill at this + * point. */ - if (fatal_signal_pending(current)) + if (throttle_direct_reclaim(gfp_mask, zonelist, nodemask)) return 1; trace_mm_vmscan_direct_reclaim_begin(order, diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index afba51e..a292e80 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -242,6 +242,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) * hope the underlying device can handle it. */ new_dev->mtu = real_dev->mtu; + new_dev->priv_flags |= (real_dev->priv_flags & IFF_UNICAST_FLT); vlan_dev_priv(new_dev)->vlan_id = vlan_id; vlan_dev_priv(new_dev)->real_dev = real_dev; diff --git a/net/can/bcm.c b/net/can/bcm.c index 6f74758..969b7cd 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1084,6 +1084,9 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, op->sk = sk; op->ifindex = ifindex; + /* ifindex for timeout events w/o previous frame reception */ + op->rx_ifindex = ifindex; + /* initialize uninitialized (kzalloc) structure */ hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); op->timer.function = bcm_rx_timeout_handler; diff --git a/net/core/dev.c b/net/core/dev.c index 2a5f5586..2f94df2 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3592,7 +3592,7 @@ void napi_gro_flush(struct napi_struct *napi, bool flush_old) } EXPORT_SYMBOL(napi_gro_flush); -enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) +static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { struct sk_buff **pp = NULL; struct packet_offload *ptype; @@ -3683,7 +3683,6 @@ normal: ret = GRO_NORMAL; goto pull; } -EXPORT_SYMBOL(dev_gro_receive); static inline gro_result_t __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) @@ -3710,7 +3709,7 @@ __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) return dev_gro_receive(napi, skb); } -gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) +static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) { switch (ret) { case GRO_NORMAL: @@ -3736,7 +3735,6 @@ gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) return ret; } -EXPORT_SYMBOL(napi_skb_finish); static void skb_gro_reset_offset(struct sk_buff *skb) { @@ -3788,7 +3786,7 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) } EXPORT_SYMBOL(napi_get_frags); -gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, +static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, gro_result_t ret) { switch (ret) { @@ -3813,7 +3811,6 @@ gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, return ret; } -EXPORT_SYMBOL(napi_frags_finish); static struct sk_buff *napi_frags_skb(struct napi_struct *napi) { diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index f2eccd5..17ff9fd 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -257,7 +257,8 @@ static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, struct inet_peer *peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, 1); rc = inet_peer_xrlim_allow(peer, net->ipv4.sysctl_icmp_ratelimit); - inet_putpeer(peer); + if (peer) + inet_putpeer(peer); } out: return rc; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index fc09ef9..58e4160 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1323,6 +1323,10 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi if (get_user(v, (u32 __user *)optval)) return -EFAULT; + /* "pimreg%u" should not exceed 16 bytes (IFNAMSIZ) */ + if (v != RT_TABLE_DEFAULT && v >= 1000000000) + return -EINVAL; + rtnl_lock(); ret = 0; if (sk == rtnl_dereference(mrt->mroute_sk)) { diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c index e7d756e..c5e83fa 100644 --- a/net/ipv6/exthdrs_core.c +++ b/net/ipv6/exthdrs_core.c @@ -155,3 +155,127 @@ int ipv6_find_tlv(struct sk_buff *skb, int offset, int type) return -1; } EXPORT_SYMBOL_GPL(ipv6_find_tlv); + +/* + * find the offset to specified header or the protocol number of last header + * if target < 0. "last header" is transport protocol header, ESP, or + * "No next header". + * + * Note that *offset is used as input/output parameter. an if it is not zero, + * then it must be a valid offset to an inner IPv6 header. This can be used + * to explore inner IPv6 header, eg. ICMPv6 error messages. + * + * If target header is found, its offset is set in *offset and return protocol + * number. Otherwise, return -1. + * + * If the first fragment doesn't contain the final protocol header or + * NEXTHDR_NONE it is considered invalid. + * + * Note that non-1st fragment is special case that "the protocol number + * of last header" is "next header" field in Fragment header. In this case, + * *offset is meaningless and fragment offset is stored in *fragoff if fragoff + * isn't NULL. + * + * if flags is not NULL and it's a fragment, then the frag flag + * IP6_FH_F_FRAG will be set. If it's an AH header, the + * IP6_FH_F_AUTH flag is set and target < 0, then this function will + * stop at the AH header. If IP6_FH_F_SKIP_RH flag was passed, then this + * function will skip all those routing headers, where segements_left was 0. + */ +int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, + int target, unsigned short *fragoff, int *flags) +{ + unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); + u8 nexthdr = ipv6_hdr(skb)->nexthdr; + unsigned int len; + bool found; + + if (fragoff) + *fragoff = 0; + + if (*offset) { + struct ipv6hdr _ip6, *ip6; + + ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6); + if (!ip6 || (ip6->version != 6)) { + printk(KERN_ERR "IPv6 header not found\n"); + return -EBADMSG; + } + start = *offset + sizeof(struct ipv6hdr); + nexthdr = ip6->nexthdr; + } + len = skb->len - start; + + do { + struct ipv6_opt_hdr _hdr, *hp; + unsigned int hdrlen; + found = (nexthdr == target); + + if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { + if (target < 0) + break; + return -ENOENT; + } + + hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); + if (hp == NULL) + return -EBADMSG; + + if (nexthdr == NEXTHDR_ROUTING) { + struct ipv6_rt_hdr _rh, *rh; + + rh = skb_header_pointer(skb, start, sizeof(_rh), + &_rh); + if (rh == NULL) + return -EBADMSG; + + if (flags && (*flags & IP6_FH_F_SKIP_RH) && + rh->segments_left == 0) + found = false; + } + + if (nexthdr == NEXTHDR_FRAGMENT) { + unsigned short _frag_off; + __be16 *fp; + + if (flags) /* Indicate that this is a fragment */ + *flags |= IP6_FH_F_FRAG; + fp = skb_header_pointer(skb, + start+offsetof(struct frag_hdr, + frag_off), + sizeof(_frag_off), + &_frag_off); + if (fp == NULL) + return -EBADMSG; + + _frag_off = ntohs(*fp) & ~0x7; + if (_frag_off) { + if (target < 0 && + ((!ipv6_ext_hdr(hp->nexthdr)) || + hp->nexthdr == NEXTHDR_NONE)) { + if (fragoff) + *fragoff = _frag_off; + return hp->nexthdr; + } + return -ENOENT; + } + hdrlen = 8; + } else if (nexthdr == NEXTHDR_AUTH) { + if (flags && (*flags & IP6_FH_F_AUTH) && (target < 0)) + break; + hdrlen = (hp->hdrlen + 2) << 2; + } else + hdrlen = ipv6_optlen(hp); + + if (!found) { + nexthdr = hp->nexthdr; + len -= hdrlen; + start += hdrlen; + } + } while (!found); + + *offset = start; + return nexthdr; +} +EXPORT_SYMBOL(ipv6_find_hdr); + diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 74cadd0..125a90d 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -2271,112 +2271,9 @@ static void __exit ip6_tables_fini(void) unregister_pernet_subsys(&ip6_tables_net_ops); } -/* - * find the offset to specified header or the protocol number of last header - * if target < 0. "last header" is transport protocol header, ESP, or - * "No next header". - * - * Note that *offset is used as input/output parameter. an if it is not zero, - * then it must be a valid offset to an inner IPv6 header. This can be used - * to explore inner IPv6 header, eg. ICMPv6 error messages. - * - * If target header is found, its offset is set in *offset and return protocol - * number. Otherwise, return -1. - * - * If the first fragment doesn't contain the final protocol header or - * NEXTHDR_NONE it is considered invalid. - * - * Note that non-1st fragment is special case that "the protocol number - * of last header" is "next header" field in Fragment header. In this case, - * *offset is meaningless and fragment offset is stored in *fragoff if fragoff - * isn't NULL. - * - * if flags is not NULL and it's a fragment, then the frag flag IP6T_FH_F_FRAG - * will be set. If it's an AH header, the IP6T_FH_F_AUTH flag is set and - * target < 0, then this function will stop at the AH header. - */ -int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, - int target, unsigned short *fragoff, int *flags) -{ - unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); - u8 nexthdr = ipv6_hdr(skb)->nexthdr; - unsigned int len; - - if (fragoff) - *fragoff = 0; - - if (*offset) { - struct ipv6hdr _ip6, *ip6; - - ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6); - if (!ip6 || (ip6->version != 6)) { - printk(KERN_ERR "IPv6 header not found\n"); - return -EBADMSG; - } - start = *offset + sizeof(struct ipv6hdr); - nexthdr = ip6->nexthdr; - } - len = skb->len - start; - - while (nexthdr != target) { - struct ipv6_opt_hdr _hdr, *hp; - unsigned int hdrlen; - - if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { - if (target < 0) - break; - return -ENOENT; - } - - hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); - if (hp == NULL) - return -EBADMSG; - if (nexthdr == NEXTHDR_FRAGMENT) { - unsigned short _frag_off; - __be16 *fp; - - if (flags) /* Indicate that this is a fragment */ - *flags |= IP6T_FH_F_FRAG; - fp = skb_header_pointer(skb, - start+offsetof(struct frag_hdr, - frag_off), - sizeof(_frag_off), - &_frag_off); - if (fp == NULL) - return -EBADMSG; - - _frag_off = ntohs(*fp) & ~0x7; - if (_frag_off) { - if (target < 0 && - ((!ipv6_ext_hdr(hp->nexthdr)) || - hp->nexthdr == NEXTHDR_NONE)) { - if (fragoff) - *fragoff = _frag_off; - return hp->nexthdr; - } - return -ENOENT; - } - hdrlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) { - if (flags && (*flags & IP6T_FH_F_AUTH) && (target < 0)) - break; - hdrlen = (hp->hdrlen + 2) << 2; - } else - hdrlen = ipv6_optlen(hp); - - nexthdr = hp->nexthdr; - len -= hdrlen; - start += hdrlen; - } - - *offset = start; - return nexthdr; -} - EXPORT_SYMBOL(ip6t_register_table); EXPORT_SYMBOL(ip6t_unregister_table); EXPORT_SYMBOL(ip6t_do_table); -EXPORT_SYMBOL(ipv6_find_hdr); module_init(ip6_tables_init); module_exit(ip6_tables_fini); diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 1002e33..ae43c62 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -441,6 +441,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify) lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0); if (lsap == NULL) { IRDA_DEBUG(0, "%s: unable to allocate LSAP!!\n", __func__); + __irttp_close_tsap(self); return NULL; } diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index b9a6338..45a1014 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c @@ -793,7 +793,7 @@ static struct ip_set_type hash_netiface_type __read_mostly = { [IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, [IPSET_ATTR_IFACE] = { .type = NLA_NUL_STRING, - .len = IPSET_MAXNAMELEN - 1 }, + .len = IFNAMSIZ - 1 }, [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index fb45640..47edf5a 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -942,7 +942,7 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related, /* Fragment header that is before ICMP header tells us that: * it's not an error message since they can't be fragmented. */ - if (ipvsh->flags & IP6T_FH_F_FRAG) + if (ipvsh->flags & IP6_FH_F_FRAG) return NF_DROP; IP_VS_DBG(8, "Outgoing ICMPv6 (%d,%d) %pI6c->%pI6c\n", @@ -1475,7 +1475,7 @@ static int ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, /* Fragment header that is before ICMP header tells us that: * it's not an error message since they can't be fragmented. */ - if (iph->flags & IP6T_FH_F_FRAG) + if (iph->flags & IP6_FH_F_FRAG) return NF_DROP; IP_VS_DBG(8, "Incoming ICMPv6 (%d,%d) %pI6c->%pI6c\n", diff --git a/net/netfilter/xt_HMARK.c b/net/netfilter/xt_HMARK.c index 1686ca1..73b73f6 100644 --- a/net/netfilter/xt_HMARK.c +++ b/net/netfilter/xt_HMARK.c @@ -167,7 +167,7 @@ hmark_pkt_set_htuple_ipv6(const struct sk_buff *skb, struct hmark_tuple *t, const struct xt_hmark_info *info) { struct ipv6hdr *ip6, _ip6; - int flag = IP6T_FH_F_AUTH; + int flag = IP6_FH_F_AUTH; unsigned int nhoff = 0; u16 fragoff = 0; int nexthdr; @@ -177,7 +177,7 @@ hmark_pkt_set_htuple_ipv6(const struct sk_buff *skb, struct hmark_tuple *t, if (nexthdr < 0) return 0; /* No need to check for icmp errors on fragments */ - if ((flag & IP6T_FH_F_FRAG) || (nexthdr != IPPROTO_ICMPV6)) + if ((flag & IP6_FH_F_FRAG) || (nexthdr != IPPROTO_ICMPV6)) goto noicmp; /* Use inner header in case of ICMP errors */ if (get_inner6_hdr(skb, &nhoff)) { @@ -185,7 +185,7 @@ hmark_pkt_set_htuple_ipv6(const struct sk_buff *skb, struct hmark_tuple *t, if (ip6 == NULL) return -1; /* If AH present, use SPI like in ESP. */ - flag = IP6T_FH_F_AUTH; + flag = IP6_FH_F_AUTH; nexthdr = ipv6_find_hdr(skb, &nhoff, -1, &fragoff, &flag); if (nexthdr < 0) return -1; @@ -201,7 +201,7 @@ noicmp: if (t->proto == IPPROTO_ICMPV6) return 0; - if (flag & IP6T_FH_F_FRAG) + if (flag & IP6_FH_F_FRAG) return 0; hmark_set_tuple_ports(skb, nhoff, t, info); diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 0811447..ac2defe 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -28,6 +28,7 @@ #include <linux/if_arp.h> #include <linux/if_vlan.h> #include <net/ip.h> +#include <net/ipv6.h> #include <net/checksum.h> #include <net/dsfield.h> @@ -162,6 +163,53 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, *addr = new_addr; } +static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto, + __be32 addr[4], const __be32 new_addr[4]) +{ + int transport_len = skb->len - skb_transport_offset(skb); + + if (l4_proto == IPPROTO_TCP) { + if (likely(transport_len >= sizeof(struct tcphdr))) + inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb, + addr, new_addr, 1); + } else if (l4_proto == IPPROTO_UDP) { + if (likely(transport_len >= sizeof(struct udphdr))) { + struct udphdr *uh = udp_hdr(skb); + + if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { + inet_proto_csum_replace16(&uh->check, skb, + addr, new_addr, 1); + if (!uh->check) + uh->check = CSUM_MANGLED_0; + } + } + } +} + +static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto, + __be32 addr[4], const __be32 new_addr[4], + bool recalculate_csum) +{ + if (recalculate_csum) + update_ipv6_checksum(skb, l4_proto, addr, new_addr); + + skb->rxhash = 0; + memcpy(addr, new_addr, sizeof(__be32[4])); +} + +static void set_ipv6_tc(struct ipv6hdr *nh, u8 tc) +{ + nh->priority = tc >> 4; + nh->flow_lbl[0] = (nh->flow_lbl[0] & 0x0F) | ((tc & 0x0F) << 4); +} + +static void set_ipv6_fl(struct ipv6hdr *nh, u32 fl) +{ + nh->flow_lbl[0] = (nh->flow_lbl[0] & 0xF0) | (fl & 0x000F0000) >> 16; + nh->flow_lbl[1] = (fl & 0x0000FF00) >> 8; + nh->flow_lbl[2] = fl & 0x000000FF; +} + static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl) { csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8)); @@ -195,6 +243,47 @@ static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key) return 0; } +static int set_ipv6(struct sk_buff *skb, const struct ovs_key_ipv6 *ipv6_key) +{ + struct ipv6hdr *nh; + int err; + __be32 *saddr; + __be32 *daddr; + + err = make_writable(skb, skb_network_offset(skb) + + sizeof(struct ipv6hdr)); + if (unlikely(err)) + return err; + + nh = ipv6_hdr(skb); + saddr = (__be32 *)&nh->saddr; + daddr = (__be32 *)&nh->daddr; + + if (memcmp(ipv6_key->ipv6_src, saddr, sizeof(ipv6_key->ipv6_src))) + set_ipv6_addr(skb, ipv6_key->ipv6_proto, saddr, + ipv6_key->ipv6_src, true); + + if (memcmp(ipv6_key->ipv6_dst, daddr, sizeof(ipv6_key->ipv6_dst))) { + unsigned int offset = 0; + int flags = IP6_FH_F_SKIP_RH; + bool recalc_csum = true; + + if (ipv6_ext_hdr(nh->nexthdr)) + recalc_csum = ipv6_find_hdr(skb, &offset, + NEXTHDR_ROUTING, NULL, + &flags) != NEXTHDR_ROUTING; + + set_ipv6_addr(skb, ipv6_key->ipv6_proto, daddr, + ipv6_key->ipv6_dst, recalc_csum); + } + + set_ipv6_tc(nh, ipv6_key->ipv6_tclass); + set_ipv6_fl(nh, ntohl(ipv6_key->ipv6_label)); + nh->hop_limit = ipv6_key->ipv6_hlimit; + + return 0; +} + /* Must follow make_writable() since that can move the skb data. */ static void set_tp_port(struct sk_buff *skb, __be16 *port, __be16 new_port, __sum16 *check) @@ -339,6 +428,10 @@ static int execute_set_action(struct sk_buff *skb, skb->priority = nla_get_u32(nested_attr); break; + case OVS_KEY_ATTR_SKB_MARK: + skb->mark = nla_get_u32(nested_attr); + break; + case OVS_KEY_ATTR_ETHERNET: err = set_eth_addr(skb, nla_data(nested_attr)); break; @@ -347,6 +440,10 @@ static int execute_set_action(struct sk_buff *skb, err = set_ipv4(skb, nla_data(nested_attr)); break; + case OVS_KEY_ATTR_IPV6: + err = set_ipv6(skb, nla_data(nested_attr)); + break; + case OVS_KEY_ATTR_TCP: err = set_tcp(skb, nla_data(nested_attr)); break; diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 4c4b62c..f996db3 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -208,7 +208,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) int error; int key_len; - stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id()); + stats = this_cpu_ptr(dp->stats_percpu); /* Extract flow from 'skb' into 'key'. */ error = ovs_flow_extract(skb, p->port_no, &key, &key_len); @@ -282,7 +282,7 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, return 0; err: - stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id()); + stats = this_cpu_ptr(dp->stats_percpu); u64_stats_update_begin(&stats->sync); stats->n_lost++; @@ -479,8 +479,10 @@ static int validate_set(const struct nlattr *a, switch (key_type) { const struct ovs_key_ipv4 *ipv4_key; + const struct ovs_key_ipv6 *ipv6_key; case OVS_KEY_ATTR_PRIORITY: + case OVS_KEY_ATTR_SKB_MARK: case OVS_KEY_ATTR_ETHERNET: break; @@ -500,6 +502,25 @@ static int validate_set(const struct nlattr *a, break; + case OVS_KEY_ATTR_IPV6: + if (flow_key->eth.type != htons(ETH_P_IPV6)) + return -EINVAL; + + if (!flow_key->ip.proto) + return -EINVAL; + + ipv6_key = nla_data(ovs_key); + if (ipv6_key->ipv6_proto != flow_key->ip.proto) + return -EINVAL; + + if (ipv6_key->ipv6_frag != flow_key->ip.frag) + return -EINVAL; + + if (ntohl(ipv6_key->ipv6_label) & 0xFFF00000) + return -EINVAL; + + break; + case OVS_KEY_ATTR_TCP: if (flow_key->ip.proto != IPPROTO_TCP) return -EINVAL; @@ -675,6 +696,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) goto err_flow_free; err = ovs_flow_metadata_from_nlattrs(&flow->key.phy.priority, + &flow->key.phy.skb_mark, &flow->key.phy.in_port, a[OVS_PACKET_ATTR_KEY]); if (err) @@ -694,6 +716,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) OVS_CB(packet)->flow = flow; packet->priority = flow->key.phy.priority; + packet->mark = flow->key.phy.skb_mark; rcu_read_lock(); dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 98c7063..c3294ce 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -604,6 +604,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, key->phy.priority = skb->priority; key->phy.in_port = in_port; + key->phy.skb_mark = skb->mark; skb_reset_mac_header(skb); @@ -689,7 +690,8 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, } } - } else if (key->eth.type == htons(ETH_P_ARP) && arphdr_ok(skb)) { + } else if ((key->eth.type == htons(ETH_P_ARP) || + key->eth.type == htons(ETH_P_RARP)) && arphdr_ok(skb)) { struct arp_eth_header *arp; arp = (struct arp_eth_header *)skb_network_header(skb); @@ -702,15 +704,11 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, /* We only match on the lower 8 bits of the opcode. */ if (ntohs(arp->ar_op) <= 0xff) key->ip.proto = ntohs(arp->ar_op); - - if (key->ip.proto == ARPOP_REQUEST - || key->ip.proto == ARPOP_REPLY) { - memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src)); - memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst)); - memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN); - memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN); - key_len = SW_FLOW_KEY_OFFSET(ipv4.arp); - } + memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src)); + memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst)); + memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN); + memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN); + key_len = SW_FLOW_KEY_OFFSET(ipv4.arp); } } else if (key->eth.type == htons(ETH_P_IPV6)) { int nh_len; /* IPv6 Header + Extensions */ @@ -806,6 +804,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { [OVS_KEY_ATTR_ENCAP] = -1, [OVS_KEY_ATTR_PRIORITY] = sizeof(u32), [OVS_KEY_ATTR_IN_PORT] = sizeof(u32), + [OVS_KEY_ATTR_SKB_MARK] = sizeof(u32), [OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet), [OVS_KEY_ATTR_VLAN] = sizeof(__be16), [OVS_KEY_ATTR_ETHERTYPE] = sizeof(__be16), @@ -991,6 +990,10 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, } else { swkey->phy.in_port = DP_MAX_PORTS; } + if (attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) { + swkey->phy.skb_mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]); + attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK); + } /* Data attributes. */ if (!(attrs & (1 << OVS_KEY_ATTR_ETHERNET))) @@ -1090,7 +1093,8 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, if (err) return err; } - } else if (swkey->eth.type == htons(ETH_P_ARP)) { + } else if (swkey->eth.type == htons(ETH_P_ARP) || + swkey->eth.type == htons(ETH_P_RARP)) { const struct ovs_key_arp *arp_key; if (!(attrs & (1 << OVS_KEY_ATTR_ARP))) @@ -1117,6 +1121,8 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, /** * ovs_flow_metadata_from_nlattrs - parses Netlink attributes into a flow key. + * @priority: receives the skb priority + * @mark: receives the skb mark * @in_port: receives the extracted input port. * @key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute * sequence. @@ -1126,7 +1132,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, * get the metadata, that is, the parts of the flow key that cannot be * extracted from the packet itself. */ -int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, +int ovs_flow_metadata_from_nlattrs(u32 *priority, u32 *mark, u16 *in_port, const struct nlattr *attr) { const struct nlattr *nla; @@ -1134,6 +1140,7 @@ int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, *in_port = DP_MAX_PORTS; *priority = 0; + *mark = 0; nla_for_each_nested(nla, attr, rem) { int type = nla_type(nla); @@ -1152,6 +1159,10 @@ int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, return -EINVAL; *in_port = nla_get_u32(nla); break; + + case OVS_KEY_ATTR_SKB_MARK: + *mark = nla_get_u32(nla); + break; } } } @@ -1173,6 +1184,10 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port)) goto nla_put_failure; + if (swkey->phy.skb_mark && + nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, swkey->phy.skb_mark)) + goto nla_put_failure; + nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key)); if (!nla) goto nla_put_failure; @@ -1226,7 +1241,8 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) ipv6_key->ipv6_tclass = swkey->ip.tos; ipv6_key->ipv6_hlimit = swkey->ip.ttl; ipv6_key->ipv6_frag = swkey->ip.frag; - } else if (swkey->eth.type == htons(ETH_P_ARP)) { + } else if (swkey->eth.type == htons(ETH_P_ARP) || + swkey->eth.type == htons(ETH_P_RARP)) { struct ovs_key_arp *arp_key; nla = nla_reserve(skb, OVS_KEY_ATTR_ARP, sizeof(*arp_key)); diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index 14a324e..a7bb60f 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h @@ -43,6 +43,7 @@ struct sw_flow_actions { struct sw_flow_key { struct { u32 priority; /* Packet QoS priority. */ + u32 skb_mark; /* SKB mark. */ u16 in_port; /* Input switch port (or DP_MAX_PORTS). */ } phy; struct { @@ -144,6 +145,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies); * ------ --- ------ ----- * OVS_KEY_ATTR_PRIORITY 4 -- 4 8 * OVS_KEY_ATTR_IN_PORT 4 -- 4 8 + * OVS_KEY_ATTR_SKB_MARK 4 -- 4 8 * OVS_KEY_ATTR_ETHERNET 12 -- 4 16 * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype) * OVS_KEY_ATTR_8021Q 4 -- 4 8 @@ -153,14 +155,14 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies); * OVS_KEY_ATTR_ICMPV6 2 2 4 8 * OVS_KEY_ATTR_ND 28 -- 4 32 * ------------------------------------------------- - * total 144 + * total 152 */ -#define FLOW_BUFSIZE 144 +#define FLOW_BUFSIZE 152 int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, const struct nlattr *); -int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, +int ovs_flow_metadata_from_nlattrs(u32 *priority, u32 *mark, u16 *in_port, const struct nlattr *); #define MAX_ACTIONS_BUFSIZE (16 * 1024) diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index 3c1e58b..a9327e2 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -114,6 +114,15 @@ error: return ERR_PTR(err); } +static void free_port_rcu(struct rcu_head *rcu) +{ + struct netdev_vport *netdev_vport = container_of(rcu, + struct netdev_vport, rcu); + + dev_put(netdev_vport->dev); + ovs_vport_free(vport_from_priv(netdev_vport)); +} + static void netdev_destroy(struct vport *vport) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); @@ -122,10 +131,7 @@ static void netdev_destroy(struct vport *vport) netdev_rx_handler_unregister(netdev_vport->dev); dev_set_promiscuity(netdev_vport->dev, -1); - synchronize_rcu(); - - dev_put(netdev_vport->dev); - ovs_vport_free(vport); + call_rcu(&netdev_vport->rcu, free_port_rcu); } const char *ovs_netdev_get_name(const struct vport *vport) @@ -158,7 +164,7 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb) if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) { net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n", - ovs_dp_name(vport->dp), + netdev_vport->dev->name, packet_length(skb), mtu); goto error; } diff --git a/net/openvswitch/vport-netdev.h b/net/openvswitch/vport-netdev.h index f7072a2..6478079 100644 --- a/net/openvswitch/vport-netdev.h +++ b/net/openvswitch/vport-netdev.h @@ -20,12 +20,15 @@ #define VPORT_NETDEV_H 1 #include <linux/netdevice.h> +#include <linux/rcupdate.h> #include "vport.h" struct vport *ovs_netdev_get_vport(struct net_device *dev); struct netdev_vport { + struct rcu_head rcu; + struct net_device *dev; }; diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 03779e8..70af0be 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -333,8 +333,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb) { struct vport_percpu_stats *stats; - stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); - + stats = this_cpu_ptr(vport->percpu_stats); u64_stats_update_begin(&stats->sync); stats->rx_packets++; stats->rx_bytes += skb->len; @@ -359,7 +358,7 @@ int ovs_vport_send(struct vport *vport, struct sk_buff *skb) if (likely(sent)) { struct vport_percpu_stats *stats; - stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); + stats = this_cpu_ptr(vport->percpu_stats); u64_stats_update_begin(&stats->sync); stats->tx_packets++; diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 7c2df9c..69ce21e 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -183,7 +183,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, msg = sctp_datamsg_new(GFP_KERNEL); if (!msg) - return NULL; + return ERR_PTR(-ENOMEM); /* Note: Calculate this outside of the loop, so that all fragments * have the same expiration. @@ -280,11 +280,14 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); - if (!chunk) + if (!chunk) { + err = -ENOMEM; goto errout; + } + err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov); if (err < 0) - goto errout; + goto errout_chunk_free; offset += len; @@ -315,8 +318,10 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); - if (!chunk) + if (!chunk) { + err = -ENOMEM; goto errout; + } err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov); @@ -324,7 +329,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr - (__u8 *)chunk->skb->data); if (err < 0) - goto errout; + goto errout_chunk_free; sctp_datamsg_assign(msg, chunk); list_add_tail(&chunk->frag_list, &msg->chunks); @@ -332,6 +337,9 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, return msg; +errout_chunk_free: + sctp_chunk_free(chunk); + errout: list_for_each_safe(pos, temp, &msg->chunks) { list_del_init(pos); @@ -339,7 +347,7 @@ errout: sctp_chunk_free(chunk); } sctp_datamsg_put(msg); - return NULL; + return ERR_PTR(err); } /* Check whether this message has expired. */ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 2e89706..bc16249 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1916,8 +1916,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, /* Break the message into multiple chunks of maximum size. */ datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len); - if (!datamsg) { - err = -ENOMEM; + if (IS_ERR(datamsg)) { + err = PTR_ERR(datamsg); goto out_free; } diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 953c21e..206cf52 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -331,7 +331,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) * 1/8, rto_alpha would be expressed as 3. */ tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta) - + ((abs(tp->srtt - rtt)) >> net->sctp.rto_beta); + + (((__u32)abs64((__s64)tp->srtt - (__s64)rtt)) >> net->sctp.rto_beta); tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha) + (rtt >> net->sctp.rto_alpha); } else { diff --git a/scripts/headers_install.pl b/scripts/headers_install.pl index 239d22d..6c353ae 100644 --- a/scripts/headers_install.pl +++ b/scripts/headers_install.pl @@ -42,6 +42,9 @@ foreach my $filename (@files) { $line =~ s/(^|\s)(inline)\b/$1__$2__/g; $line =~ s/(^|\s)(asm)\b(\s|[(]|$)/$1__$2__$3/g; $line =~ s/(^|\s|[(])(volatile)\b(\s|[(]|$)/$1__$2__$3/g; + $line =~ s/#ifndef _UAPI/#ifndef /; + $line =~ s/#define _UAPI/#define /; + $line =~ s!#endif /[*] _UAPI!#endif /* !; printf {$out} "%s", $line; } close $out; |