From 852e372532bed457eaeb3edd198b939caeb863c5 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Oct 2012 09:46:41 +0100 Subject: UAPI: (Scripted) Disintegrate arch/cris/include/arch-v10/arch Signed-off-by: David Howells Acked-by: Arnd Bergmann Acked-by: Thomas Gleixner Acked-by: Michael Kerrisk Acked-by: Paul E. McKenney Acked-by: Dave Jones diff --git a/arch/cris/include/arch-v10/arch/Kbuild b/arch/cris/include/arch-v10/arch/Kbuild index 7a192e1..e69de29 100644 --- a/arch/cris/include/arch-v10/arch/Kbuild +++ b/arch/cris/include/arch-v10/arch/Kbuild @@ -1,4 +0,0 @@ -header-y += user.h -header-y += svinto.h -header-y += sv_addr_ag.h -header-y += sv_addr.agh diff --git a/arch/cris/include/arch-v10/arch/sv_addr.agh b/arch/cris/include/arch-v10/arch/sv_addr.agh deleted file mode 100644 index 6ac3a7b..0000000 --- a/arch/cris/include/arch-v10/arch/sv_addr.agh +++ /dev/null @@ -1,7306 +0,0 @@ -/* -!* This file was automatically generated by /n/asic/bin/reg_macro_gen -!* from the file `/n/asic/projects/etrax_ng/doc/work/etrax_ng_regs.rd'. -!* Editing within this file is thus not recommended, -!* make the changes in `/n/asic/projects/etrax_ng/doc/work/etrax_ng_regs.rd' instead. -!*/ - - -/* -!* Bus interface configuration registers -!*/ - -#define R_WAITSTATES (IO_TYPECAST_UDWORD 0xb0000000) -#define R_WAITSTATES__pcs4_7_zw__BITNR 30 -#define R_WAITSTATES__pcs4_7_zw__WIDTH 2 -#define R_WAITSTATES__pcs4_7_ew__BITNR 28 -#define R_WAITSTATES__pcs4_7_ew__WIDTH 2 -#define R_WAITSTATES__pcs4_7_lw__BITNR 24 -#define R_WAITSTATES__pcs4_7_lw__WIDTH 4 -#define R_WAITSTATES__pcs0_3_zw__BITNR 22 -#define R_WAITSTATES__pcs0_3_zw__WIDTH 2 -#define R_WAITSTATES__pcs0_3_ew__BITNR 20 -#define R_WAITSTATES__pcs0_3_ew__WIDTH 2 -#define R_WAITSTATES__pcs0_3_lw__BITNR 16 -#define R_WAITSTATES__pcs0_3_lw__WIDTH 4 -#define R_WAITSTATES__sram_zw__BITNR 14 -#define R_WAITSTATES__sram_zw__WIDTH 2 -#define R_WAITSTATES__sram_ew__BITNR 12 -#define R_WAITSTATES__sram_ew__WIDTH 2 -#define R_WAITSTATES__sram_lw__BITNR 8 -#define R_WAITSTATES__sram_lw__WIDTH 4 -#define R_WAITSTATES__flash_zw__BITNR 6 -#define R_WAITSTATES__flash_zw__WIDTH 2 -#define R_WAITSTATES__flash_ew__BITNR 4 -#define R_WAITSTATES__flash_ew__WIDTH 2 -#define R_WAITSTATES__flash_lw__BITNR 0 -#define R_WAITSTATES__flash_lw__WIDTH 4 - -#define R_BUS_CONFIG (IO_TYPECAST_UDWORD 0xb0000004) -#define R_BUS_CONFIG__sram_type__BITNR 9 -#define R_BUS_CONFIG__sram_type__WIDTH 1 -#define R_BUS_CONFIG__sram_type__cwe 1 -#define R_BUS_CONFIG__sram_type__bwe 0 -#define R_BUS_CONFIG__dma_burst__BITNR 8 -#define R_BUS_CONFIG__dma_burst__WIDTH 1 -#define R_BUS_CONFIG__dma_burst__burst16 1 -#define R_BUS_CONFIG__dma_burst__burst32 0 -#define R_BUS_CONFIG__pcs4_7_wr__BITNR 7 -#define R_BUS_CONFIG__pcs4_7_wr__WIDTH 1 -#define R_BUS_CONFIG__pcs4_7_wr__ext 1 -#define R_BUS_CONFIG__pcs4_7_wr__norm 0 -#define R_BUS_CONFIG__pcs0_3_wr__BITNR 6 -#define R_BUS_CONFIG__pcs0_3_wr__WIDTH 1 -#define R_BUS_CONFIG__pcs0_3_wr__ext 1 -#define R_BUS_CONFIG__pcs0_3_wr__norm 0 -#define R_BUS_CONFIG__sram_wr__BITNR 5 -#define R_BUS_CONFIG__sram_wr__WIDTH 1 -#define R_BUS_CONFIG__sram_wr__ext 1 -#define R_BUS_CONFIG__sram_wr__norm 0 -#define R_BUS_CONFIG__flash_wr__BITNR 4 -#define R_BUS_CONFIG__flash_wr__WIDTH 1 -#define R_BUS_CONFIG__flash_wr__ext 1 -#define R_BUS_CONFIG__flash_wr__norm 0 -#define R_BUS_CONFIG__pcs4_7_bw__BITNR 3 -#define R_BUS_CONFIG__pcs4_7_bw__WIDTH 1 -#define R_BUS_CONFIG__pcs4_7_bw__bw32 1 -#define R_BUS_CONFIG__pcs4_7_bw__bw16 0 -#define R_BUS_CONFIG__pcs0_3_bw__BITNR 2 -#define R_BUS_CONFIG__pcs0_3_bw__WIDTH 1 -#define R_BUS_CONFIG__pcs0_3_bw__bw32 1 -#define R_BUS_CONFIG__pcs0_3_bw__bw16 0 -#define R_BUS_CONFIG__sram_bw__BITNR 1 -#define R_BUS_CONFIG__sram_bw__WIDTH 1 -#define R_BUS_CONFIG__sram_bw__bw32 1 -#define R_BUS_CONFIG__sram_bw__bw16 0 -#define R_BUS_CONFIG__flash_bw__BITNR 0 -#define R_BUS_CONFIG__flash_bw__WIDTH 1 -#define R_BUS_CONFIG__flash_bw__bw32 1 -#define R_BUS_CONFIG__flash_bw__bw16 0 - -#define R_BUS_STATUS (IO_TYPECAST_RO_UDWORD 0xb0000004) -#define R_BUS_STATUS__pll_lock_tm__BITNR 5 -#define R_BUS_STATUS__pll_lock_tm__WIDTH 1 -#define R_BUS_STATUS__pll_lock_tm__expired 0 -#define R_BUS_STATUS__pll_lock_tm__counting 1 -#define R_BUS_STATUS__both_faults__BITNR 4 -#define R_BUS_STATUS__both_faults__WIDTH 1 -#define R_BUS_STATUS__both_faults__no 0 -#define R_BUS_STATUS__both_faults__yes 1 -#define R_BUS_STATUS__bsen___BITNR 3 -#define R_BUS_STATUS__bsen___WIDTH 1 -#define R_BUS_STATUS__bsen___enable 0 -#define R_BUS_STATUS__bsen___disable 1 -#define R_BUS_STATUS__boot__BITNR 1 -#define R_BUS_STATUS__boot__WIDTH 2 -#define R_BUS_STATUS__boot__uncached 0 -#define R_BUS_STATUS__boot__serial 1 -#define R_BUS_STATUS__boot__network 2 -#define R_BUS_STATUS__boot__parallel 3 -#define R_BUS_STATUS__flashw__BITNR 0 -#define R_BUS_STATUS__flashw__WIDTH 1 -#define R_BUS_STATUS__flashw__bw32 1 -#define R_BUS_STATUS__flashw__bw16 0 - -#define R_DRAM_TIMING (IO_TYPECAST_UDWORD 0xb0000008) -#define R_DRAM_TIMING__sdram__BITNR 31 -#define R_DRAM_TIMING__sdram__WIDTH 1 -#define R_DRAM_TIMING__sdram__enable 1 -#define R_DRAM_TIMING__sdram__disable 0 -#define R_DRAM_TIMING__ref__BITNR 14 -#define R_DRAM_TIMING__ref__WIDTH 2 -#define R_DRAM_TIMING__ref__e52us 0 -#define R_DRAM_TIMING__ref__e13us 1 -#define R_DRAM_TIMING__ref__e8700ns 2 -#define R_DRAM_TIMING__ref__disable 3 -#define R_DRAM_TIMING__rp__BITNR 12 -#define R_DRAM_TIMING__rp__WIDTH 2 -#define R_DRAM_TIMING__rs__BITNR 10 -#define R_DRAM_TIMING__rs__WIDTH 2 -#define R_DRAM_TIMING__rh__BITNR 8 -#define R_DRAM_TIMING__rh__WIDTH 2 -#define R_DRAM_TIMING__w__BITNR 7 -#define R_DRAM_TIMING__w__WIDTH 1 -#define R_DRAM_TIMING__w__norm 0 -#define R_DRAM_TIMING__w__ext 1 -#define R_DRAM_TIMING__c__BITNR 6 -#define R_DRAM_TIMING__c__WIDTH 1 -#define R_DRAM_TIMING__c__norm 0 -#define R_DRAM_TIMING__c__ext 1 -#define R_DRAM_TIMING__cz__BITNR 4 -#define R_DRAM_TIMING__cz__WIDTH 2 -#define R_DRAM_TIMING__cp__BITNR 2 -#define R_DRAM_TIMING__cp__WIDTH 2 -#define R_DRAM_TIMING__cw__BITNR 0 -#define R_DRAM_TIMING__cw__WIDTH 2 - -#define R_SDRAM_TIMING (IO_TYPECAST_UDWORD 0xb0000008) -#define R_SDRAM_TIMING__sdram__BITNR 31 -#define R_SDRAM_TIMING__sdram__WIDTH 1 -#define R_SDRAM_TIMING__sdram__enable 1 -#define R_SDRAM_TIMING__sdram__disable 0 -#define R_SDRAM_TIMING__mrs_data__BITNR 16 -#define R_SDRAM_TIMING__mrs_data__WIDTH 15 -#define R_SDRAM_TIMING__ref__BITNR 14 -#define R_SDRAM_TIMING__ref__WIDTH 2 -#define R_SDRAM_TIMING__ref__e52us 0 -#define R_SDRAM_TIMING__ref__e13us 1 -#define R_SDRAM_TIMING__ref__e6500ns 2 -#define R_SDRAM_TIMING__ref__disable 3 -#define R_SDRAM_TIMING__ddr__BITNR 13 -#define R_SDRAM_TIMING__ddr__WIDTH 1 -#define R_SDRAM_TIMING__ddr__on 1 -#define R_SDRAM_TIMING__ddr__off 0 -#define R_SDRAM_TIMING__clk100__BITNR 12 -#define R_SDRAM_TIMING__clk100__WIDTH 1 -#define R_SDRAM_TIMING__clk100__on 1 -#define R_SDRAM_TIMING__clk100__off 0 -#define R_SDRAM_TIMING__ps__BITNR 11 -#define R_SDRAM_TIMING__ps__WIDTH 1 -#define R_SDRAM_TIMING__ps__on 1 -#define R_SDRAM_TIMING__ps__off 0 -#define R_SDRAM_TIMING__cmd__BITNR 9 -#define R_SDRAM_TIMING__cmd__WIDTH 2 -#define R_SDRAM_TIMING__cmd__pre 3 -#define R_SDRAM_TIMING__cmd__ref 2 -#define R_SDRAM_TIMING__cmd__mrs 1 -#define R_SDRAM_TIMING__cmd__nop 0 -#define R_SDRAM_TIMING__pde__BITNR 8 -#define R_SDRAM_TIMING__pde__WIDTH 1 -#define R_SDRAM_TIMING__rc__BITNR 6 -#define R_SDRAM_TIMING__rc__WIDTH 2 -#define R_SDRAM_TIMING__rp__BITNR 4 -#define R_SDRAM_TIMING__rp__WIDTH 2 -#define R_SDRAM_TIMING__rcd__BITNR 2 -#define R_SDRAM_TIMING__rcd__WIDTH 2 -#define R_SDRAM_TIMING__cl__BITNR 0 -#define R_SDRAM_TIMING__cl__WIDTH 2 - -#define R_DRAM_CONFIG (IO_TYPECAST_UDWORD 0xb000000c) -#define R_DRAM_CONFIG__wmm1__BITNR 31 -#define R_DRAM_CONFIG__wmm1__WIDTH 1 -#define R_DRAM_CONFIG__wmm1__wmm 1 -#define R_DRAM_CONFIG__wmm1__norm 0 -#define R_DRAM_CONFIG__wmm0__BITNR 30 -#define R_DRAM_CONFIG__wmm0__WIDTH 1 -#define R_DRAM_CONFIG__wmm0__wmm 1 -#define R_DRAM_CONFIG__wmm0__norm 0 -#define R_DRAM_CONFIG__sh1__BITNR 27 -#define R_DRAM_CONFIG__sh1__WIDTH 3 -#define R_DRAM_CONFIG__sh0__BITNR 24 -#define R_DRAM_CONFIG__sh0__WIDTH 3 -#define R_DRAM_CONFIG__w__BITNR 23 -#define R_DRAM_CONFIG__w__WIDTH 1 -#define R_DRAM_CONFIG__w__bw16 0 -#define R_DRAM_CONFIG__w__bw32 1 -#define R_DRAM_CONFIG__c__BITNR 22 -#define R_DRAM_CONFIG__c__WIDTH 1 -#define R_DRAM_CONFIG__c__byte 0 -#define R_DRAM_CONFIG__c__bank 1 -#define R_DRAM_CONFIG__e__BITNR 21 -#define R_DRAM_CONFIG__e__WIDTH 1 -#define R_DRAM_CONFIG__e__fast 0 -#define R_DRAM_CONFIG__e__edo 1 -#define R_DRAM_CONFIG__group_sel__BITNR 16 -#define R_DRAM_CONFIG__group_sel__WIDTH 5 -#define R_DRAM_CONFIG__group_sel__grp0 0 -#define R_DRAM_CONFIG__group_sel__grp1 1 -#define R_DRAM_CONFIG__group_sel__bit9 9 -#define R_DRAM_CONFIG__group_sel__bit10 10 -#define R_DRAM_CONFIG__group_sel__bit11 11 -#define R_DRAM_CONFIG__group_sel__bit12 12 -#define R_DRAM_CONFIG__group_sel__bit13 13 -#define R_DRAM_CONFIG__group_sel__bit14 14 -#define R_DRAM_CONFIG__group_sel__bit15 15 -#define R_DRAM_CONFIG__group_sel__bit16 16 -#define R_DRAM_CONFIG__group_sel__bit17 17 -#define R_DRAM_CONFIG__group_sel__bit18 18 -#define R_DRAM_CONFIG__group_sel__bit19 19 -#define R_DRAM_CONFIG__group_sel__bit20 20 -#define R_DRAM_CONFIG__group_sel__bit21 21 -#define R_DRAM_CONFIG__group_sel__bit22 22 -#define R_DRAM_CONFIG__group_sel__bit23 23 -#define R_DRAM_CONFIG__group_sel__bit24 24 -#define R_DRAM_CONFIG__group_sel__bit25 25 -#define R_DRAM_CONFIG__group_sel__bit26 26 -#define R_DRAM_CONFIG__group_sel__bit27 27 -#define R_DRAM_CONFIG__group_sel__bit28 28 -#define R_DRAM_CONFIG__group_sel__bit29 29 -#define R_DRAM_CONFIG__ca1__BITNR 13 -#define R_DRAM_CONFIG__ca1__WIDTH 3 -#define R_DRAM_CONFIG__bank23sel__BITNR 8 -#define R_DRAM_CONFIG__bank23sel__WIDTH 5 -#define R_DRAM_CONFIG__bank23sel__bank0 0 -#define R_DRAM_CONFIG__bank23sel__bank1 1 -#define R_DRAM_CONFIG__bank23sel__bit9 9 -#define R_DRAM_CONFIG__bank23sel__bit10 10 -#define R_DRAM_CONFIG__bank23sel__bit11 11 -#define R_DRAM_CONFIG__bank23sel__bit12 12 -#define R_DRAM_CONFIG__bank23sel__bit13 13 -#define R_DRAM_CONFIG__bank23sel__bit14 14 -#define R_DRAM_CONFIG__bank23sel__bit15 15 -#define R_DRAM_CONFIG__bank23sel__bit16 16 -#define R_DRAM_CONFIG__bank23sel__bit17 17 -#define R_DRAM_CONFIG__bank23sel__bit18 18 -#define R_DRAM_CONFIG__bank23sel__bit19 19 -#define R_DRAM_CONFIG__bank23sel__bit20 20 -#define R_DRAM_CONFIG__bank23sel__bit21 21 -#define R_DRAM_CONFIG__bank23sel__bit22 22 -#define R_DRAM_CONFIG__bank23sel__bit23 23 -#define R_DRAM_CONFIG__bank23sel__bit24 24 -#define R_DRAM_CONFIG__bank23sel__bit25 25 -#define R_DRAM_CONFIG__bank23sel__bit26 26 -#define R_DRAM_CONFIG__bank23sel__bit27 27 -#define R_DRAM_CONFIG__bank23sel__bit28 28 -#define R_DRAM_CONFIG__bank23sel__bit29 29 -#define R_DRAM_CONFIG__ca0__BITNR 5 -#define R_DRAM_CONFIG__ca0__WIDTH 3 -#define R_DRAM_CONFIG__bank01sel__BITNR 0 -#define R_DRAM_CONFIG__bank01sel__WIDTH 5 -#define R_DRAM_CONFIG__bank01sel__bank0 0 -#define R_DRAM_CONFIG__bank01sel__bank1 1 -#define R_DRAM_CONFIG__bank01sel__bit9 9 -#define R_DRAM_CONFIG__bank01sel__bit10 10 -#define R_DRAM_CONFIG__bank01sel__bit11 11 -#define R_DRAM_CONFIG__bank01sel__bit12 12 -#define R_DRAM_CONFIG__bank01sel__bit13 13 -#define R_DRAM_CONFIG__bank01sel__bit14 14 -#define R_DRAM_CONFIG__bank01sel__bit15 15 -#define R_DRAM_CONFIG__bank01sel__bit16 16 -#define R_DRAM_CONFIG__bank01sel__bit17 17 -#define R_DRAM_CONFIG__bank01sel__bit18 18 -#define R_DRAM_CONFIG__bank01sel__bit19 19 -#define R_DRAM_CONFIG__bank01sel__bit20 20 -#define R_DRAM_CONFIG__bank01sel__bit21 21 -#define R_DRAM_CONFIG__bank01sel__bit22 22 -#define R_DRAM_CONFIG__bank01sel__bit23 23 -#define R_DRAM_CONFIG__bank01sel__bit24 24 -#define R_DRAM_CONFIG__bank01sel__bit25 25 -#define R_DRAM_CONFIG__bank01sel__bit26 26 -#define R_DRAM_CONFIG__bank01sel__bit27 27 -#define R_DRAM_CONFIG__bank01sel__bit28 28 -#define R_DRAM_CONFIG__bank01sel__bit29 29 - -#define R_SDRAM_CONFIG (IO_TYPECAST_UDWORD 0xb000000c) -#define R_SDRAM_CONFIG__wmm1__BITNR 31 -#define R_SDRAM_CONFIG__wmm1__WIDTH 1 -#define R_SDRAM_CONFIG__wmm1__wmm 1 -#define R_SDRAM_CONFIG__wmm1__norm 0 -#define R_SDRAM_CONFIG__wmm0__BITNR 30 -#define R_SDRAM_CONFIG__wmm0__WIDTH 1 -#define R_SDRAM_CONFIG__wmm0__wmm 1 -#define R_SDRAM_CONFIG__wmm0__norm 0 -#define R_SDRAM_CONFIG__sh1__BITNR 27 -#define R_SDRAM_CONFIG__sh1__WIDTH 3 -#define R_SDRAM_CONFIG__sh0__BITNR 24 -#define R_SDRAM_CONFIG__sh0__WIDTH 3 -#define R_SDRAM_CONFIG__w__BITNR 23 -#define R_SDRAM_CONFIG__w__WIDTH 1 -#define R_SDRAM_CONFIG__w__bw16 0 -#define R_SDRAM_CONFIG__w__bw32 1 -#define R_SDRAM_CONFIG__type1__BITNR 22 -#define R_SDRAM_CONFIG__type1__WIDTH 1 -#define R_SDRAM_CONFIG__type1__bank2 0 -#define R_SDRAM_CONFIG__type1__bank4 1 -#define R_SDRAM_CONFIG__type0__BITNR 21 -#define R_SDRAM_CONFIG__type0__WIDTH 1 -#define R_SDRAM_CONFIG__type0__bank2 0 -#define R_SDRAM_CONFIG__type0__bank4 1 -#define R_SDRAM_CONFIG__group_sel__BITNR 16 -#define R_SDRAM_CONFIG__group_sel__WIDTH 5 -#define R_SDRAM_CONFIG__group_sel__grp0 0 -#define R_SDRAM_CONFIG__group_sel__grp1 1 -#define R_SDRAM_CONFIG__group_sel__bit9 9 -#define R_SDRAM_CONFIG__group_sel__bit10 10 -#define R_SDRAM_CONFIG__group_sel__bit11 11 -#define R_SDRAM_CONFIG__group_sel__bit12 12 -#define R_SDRAM_CONFIG__group_sel__bit13 13 -#define R_SDRAM_CONFIG__group_sel__bit14 14 -#define R_SDRAM_CONFIG__group_sel__bit15 15 -#define R_SDRAM_CONFIG__group_sel__bit16 16 -#define R_SDRAM_CONFIG__group_sel__bit17 17 -#define R_SDRAM_CONFIG__group_sel__bit18 18 -#define R_SDRAM_CONFIG__group_sel__bit19 19 -#define R_SDRAM_CONFIG__group_sel__bit20 20 -#define R_SDRAM_CONFIG__group_sel__bit21 21 -#define R_SDRAM_CONFIG__group_sel__bit22 22 -#define R_SDRAM_CONFIG__group_sel__bit23 23 -#define R_SDRAM_CONFIG__group_sel__bit24 24 -#define R_SDRAM_CONFIG__group_sel__bit25 25 -#define R_SDRAM_CONFIG__group_sel__bit26 26 -#define R_SDRAM_CONFIG__group_sel__bit27 27 -#define R_SDRAM_CONFIG__group_sel__bit28 28 -#define R_SDRAM_CONFIG__group_sel__bit29 29 -#define R_SDRAM_CONFIG__ca1__BITNR 13 -#define R_SDRAM_CONFIG__ca1__WIDTH 3 -#define R_SDRAM_CONFIG__bank_sel1__BITNR 8 -#define R_SDRAM_CONFIG__bank_sel1__WIDTH 5 -#define R_SDRAM_CONFIG__bank_sel1__bit9 9 -#define R_SDRAM_CONFIG__bank_sel1__bit10 10 -#define R_SDRAM_CONFIG__bank_sel1__bit11 11 -#define R_SDRAM_CONFIG__bank_sel1__bit12 12 -#define R_SDRAM_CONFIG__bank_sel1__bit13 13 -#define R_SDRAM_CONFIG__bank_sel1__bit14 14 -#define R_SDRAM_CONFIG__bank_sel1__bit15 15 -#define R_SDRAM_CONFIG__bank_sel1__bit16 16 -#define R_SDRAM_CONFIG__bank_sel1__bit17 17 -#define R_SDRAM_CONFIG__bank_sel1__bit18 18 -#define R_SDRAM_CONFIG__bank_sel1__bit19 19 -#define R_SDRAM_CONFIG__bank_sel1__bit20 20 -#define R_SDRAM_CONFIG__bank_sel1__bit21 21 -#define R_SDRAM_CONFIG__bank_sel1__bit22 22 -#define R_SDRAM_CONFIG__bank_sel1__bit23 23 -#define R_SDRAM_CONFIG__bank_sel1__bit24 24 -#define R_SDRAM_CONFIG__bank_sel1__bit25 25 -#define R_SDRAM_CONFIG__bank_sel1__bit26 26 -#define R_SDRAM_CONFIG__bank_sel1__bit27 27 -#define R_SDRAM_CONFIG__bank_sel1__bit28 28 -#define R_SDRAM_CONFIG__bank_sel1__bit29 29 -#define R_SDRAM_CONFIG__ca0__BITNR 5 -#define R_SDRAM_CONFIG__ca0__WIDTH 3 -#define R_SDRAM_CONFIG__bank_sel0__BITNR 0 -#define R_SDRAM_CONFIG__bank_sel0__WIDTH 5 -#define R_SDRAM_CONFIG__bank_sel0__bit9 9 -#define R_SDRAM_CONFIG__bank_sel0__bit10 10 -#define R_SDRAM_CONFIG__bank_sel0__bit11 11 -#define R_SDRAM_CONFIG__bank_sel0__bit12 12 -#define R_SDRAM_CONFIG__bank_sel0__bit13 13 -#define R_SDRAM_CONFIG__bank_sel0__bit14 14 -#define R_SDRAM_CONFIG__bank_sel0__bit15 15 -#define R_SDRAM_CONFIG__bank_sel0__bit16 16 -#define R_SDRAM_CONFIG__bank_sel0__bit17 17 -#define R_SDRAM_CONFIG__bank_sel0__bit18 18 -#define R_SDRAM_CONFIG__bank_sel0__bit19 19 -#define R_SDRAM_CONFIG__bank_sel0__bit20 20 -#define R_SDRAM_CONFIG__bank_sel0__bit21 21 -#define R_SDRAM_CONFIG__bank_sel0__bit22 22 -#define R_SDRAM_CONFIG__bank_sel0__bit23 23 -#define R_SDRAM_CONFIG__bank_sel0__bit24 24 -#define R_SDRAM_CONFIG__bank_sel0__bit25 25 -#define R_SDRAM_CONFIG__bank_sel0__bit26 26 -#define R_SDRAM_CONFIG__bank_sel0__bit27 27 -#define R_SDRAM_CONFIG__bank_sel0__bit28 28 -#define R_SDRAM_CONFIG__bank_sel0__bit29 29 - -/* -!* External DMA registers -!*/ - -#define R_EXT_DMA_0_CMD (IO_TYPECAST_UDWORD 0xb0000010) -#define R_EXT_DMA_0_CMD__cnt__BITNR 23 -#define R_EXT_DMA_0_CMD__cnt__WIDTH 1 -#define R_EXT_DMA_0_CMD__cnt__enable 1 -#define R_EXT_DMA_0_CMD__cnt__disable 0 -#define R_EXT_DMA_0_CMD__rqpol__BITNR 22 -#define R_EXT_DMA_0_CMD__rqpol__WIDTH 1 -#define R_EXT_DMA_0_CMD__rqpol__ahigh 0 -#define R_EXT_DMA_0_CMD__rqpol__alow 1 -#define R_EXT_DMA_0_CMD__apol__BITNR 21 -#define R_EXT_DMA_0_CMD__apol__WIDTH 1 -#define R_EXT_DMA_0_CMD__apol__ahigh 0 -#define R_EXT_DMA_0_CMD__apol__alow 1 -#define R_EXT_DMA_0_CMD__rq_ack__BITNR 20 -#define R_EXT_DMA_0_CMD__rq_ack__WIDTH 1 -#define R_EXT_DMA_0_CMD__rq_ack__burst 0 -#define R_EXT_DMA_0_CMD__rq_ack__handsh 1 -#define R_EXT_DMA_0_CMD__wid__BITNR 18 -#define R_EXT_DMA_0_CMD__wid__WIDTH 2 -#define R_EXT_DMA_0_CMD__wid__byte 0 -#define R_EXT_DMA_0_CMD__wid__word 1 -#define R_EXT_DMA_0_CMD__wid__dword 2 -#define R_EXT_DMA_0_CMD__dir__BITNR 17 -#define R_EXT_DMA_0_CMD__dir__WIDTH 1 -#define R_EXT_DMA_0_CMD__dir__input 0 -#define R_EXT_DMA_0_CMD__dir__output 1 -#define R_EXT_DMA_0_CMD__run__BITNR 16 -#define R_EXT_DMA_0_CMD__run__WIDTH 1 -#define R_EXT_DMA_0_CMD__run__start 1 -#define R_EXT_DMA_0_CMD__run__stop 0 -#define R_EXT_DMA_0_CMD__trf_count__BITNR 0 -#define R_EXT_DMA_0_CMD__trf_count__WIDTH 16 - -#define R_EXT_DMA_0_STAT (IO_TYPECAST_RO_UDWORD 0xb0000010) -#define R_EXT_DMA_0_STAT__run__BITNR 16 -#define R_EXT_DMA_0_STAT__run__WIDTH 1 -#define R_EXT_DMA_0_STAT__run__start 1 -#define R_EXT_DMA_0_STAT__run__stop 0 -#define R_EXT_DMA_0_STAT__trf_count__BITNR 0 -#define R_EXT_DMA_0_STAT__trf_count__WIDTH 16 - -#define R_EXT_DMA_0_ADDR (IO_TYPECAST_UDWORD 0xb0000014) -#define R_EXT_DMA_0_ADDR__ext0_addr__BITNR 2 -#define R_EXT_DMA_0_ADDR__ext0_addr__WIDTH 28 - -#define R_EXT_DMA_1_CMD (IO_TYPECAST_UDWORD 0xb0000018) -#define R_EXT_DMA_1_CMD__cnt__BITNR 23 -#define R_EXT_DMA_1_CMD__cnt__WIDTH 1 -#define R_EXT_DMA_1_CMD__cnt__enable 1 -#define R_EXT_DMA_1_CMD__cnt__disable 0 -#define R_EXT_DMA_1_CMD__rqpol__BITNR 22 -#define R_EXT_DMA_1_CMD__rqpol__WIDTH 1 -#define R_EXT_DMA_1_CMD__rqpol__ahigh 0 -#define R_EXT_DMA_1_CMD__rqpol__alow 1 -#define R_EXT_DMA_1_CMD__apol__BITNR 21 -#define R_EXT_DMA_1_CMD__apol__WIDTH 1 -#define R_EXT_DMA_1_CMD__apol__ahigh 0 -#define R_EXT_DMA_1_CMD__apol__alow 1 -#define R_EXT_DMA_1_CMD__rq_ack__BITNR 20 -#define R_EXT_DMA_1_CMD__rq_ack__WIDTH 1 -#define R_EXT_DMA_1_CMD__rq_ack__burst 0 -#define R_EXT_DMA_1_CMD__rq_ack__handsh 1 -#define R_EXT_DMA_1_CMD__wid__BITNR 18 -#define R_EXT_DMA_1_CMD__wid__WIDTH 2 -#define R_EXT_DMA_1_CMD__wid__byte 0 -#define R_EXT_DMA_1_CMD__wid__word 1 -#define R_EXT_DMA_1_CMD__wid__dword 2 -#define R_EXT_DMA_1_CMD__dir__BITNR 17 -#define R_EXT_DMA_1_CMD__dir__WIDTH 1 -#define R_EXT_DMA_1_CMD__dir__input 0 -#define R_EXT_DMA_1_CMD__dir__output 1 -#define R_EXT_DMA_1_CMD__run__BITNR 16 -#define R_EXT_DMA_1_CMD__run__WIDTH 1 -#define R_EXT_DMA_1_CMD__run__start 1 -#define R_EXT_DMA_1_CMD__run__stop 0 -#define R_EXT_DMA_1_CMD__trf_count__BITNR 0 -#define R_EXT_DMA_1_CMD__trf_count__WIDTH 16 - -#define R_EXT_DMA_1_STAT (IO_TYPECAST_RO_UDWORD 0xb0000018) -#define R_EXT_DMA_1_STAT__run__BITNR 16 -#define R_EXT_DMA_1_STAT__run__WIDTH 1 -#define R_EXT_DMA_1_STAT__run__start 1 -#define R_EXT_DMA_1_STAT__run__stop 0 -#define R_EXT_DMA_1_STAT__trf_count__BITNR 0 -#define R_EXT_DMA_1_STAT__trf_count__WIDTH 16 - -#define R_EXT_DMA_1_ADDR (IO_TYPECAST_UDWORD 0xb000001c) -#define R_EXT_DMA_1_ADDR__ext0_addr__BITNR 2 -#define R_EXT_DMA_1_ADDR__ext0_addr__WIDTH 28 - -/* -!* Timer registers -!*/ - -#define R_TIMER_CTRL (IO_TYPECAST_UDWORD 0xb0000020) -#define R_TIMER_CTRL__timerdiv1__BITNR 24 -#define R_TIMER_CTRL__timerdiv1__WIDTH 8 -#define R_TIMER_CTRL__timerdiv0__BITNR 16 -#define R_TIMER_CTRL__timerdiv0__WIDTH 8 -#define R_TIMER_CTRL__presc_timer1__BITNR 15 -#define R_TIMER_CTRL__presc_timer1__WIDTH 1 -#define R_TIMER_CTRL__presc_timer1__normal 0 -#define R_TIMER_CTRL__presc_timer1__prescale 1 -#define R_TIMER_CTRL__i1__BITNR 14 -#define R_TIMER_CTRL__i1__WIDTH 1 -#define R_TIMER_CTRL__i1__clr 1 -#define R_TIMER_CTRL__i1__nop 0 -#define R_TIMER_CTRL__tm1__BITNR 12 -#define R_TIMER_CTRL__tm1__WIDTH 2 -#define R_TIMER_CTRL__tm1__stop_ld 0 -#define R_TIMER_CTRL__tm1__freeze 1 -#define R_TIMER_CTRL__tm1__run 2 -#define R_TIMER_CTRL__tm1__reserved 3 -#define R_TIMER_CTRL__clksel1__BITNR 8 -#define R_TIMER_CTRL__clksel1__WIDTH 4 -#define R_TIMER_CTRL__clksel1__c300Hz 0 -#define R_TIMER_CTRL__clksel1__c600Hz 1 -#define R_TIMER_CTRL__clksel1__c1200Hz 2 -#define R_TIMER_CTRL__clksel1__c2400Hz 3 -#define R_TIMER_CTRL__clksel1__c4800Hz 4 -#define R_TIMER_CTRL__clksel1__c9600Hz 5 -#define R_TIMER_CTRL__clksel1__c19k2Hz 6 -#define R_TIMER_CTRL__clksel1__c38k4Hz 7 -#define R_TIMER_CTRL__clksel1__c57k6Hz 8 -#define R_TIMER_CTRL__clksel1__c115k2Hz 9 -#define R_TIMER_CTRL__clksel1__c230k4Hz 10 -#define R_TIMER_CTRL__clksel1__c460k8Hz 11 -#define R_TIMER_CTRL__clksel1__c921k6Hz 12 -#define R_TIMER_CTRL__clksel1__c1843k2Hz 13 -#define R_TIMER_CTRL__clksel1__c6250kHz 14 -#define R_TIMER_CTRL__clksel1__cascade0 15 -#define R_TIMER_CTRL__presc_ext__BITNR 7 -#define R_TIMER_CTRL__presc_ext__WIDTH 1 -#define R_TIMER_CTRL__presc_ext__prescale 0 -#define R_TIMER_CTRL__presc_ext__external 1 -#define R_TIMER_CTRL__i0__BITNR 6 -#define R_TIMER_CTRL__i0__WIDTH 1 -#define R_TIMER_CTRL__i0__clr 1 -#define R_TIMER_CTRL__i0__nop 0 -#define R_TIMER_CTRL__tm0__BITNR 4 -#define R_TIMER_CTRL__tm0__WIDTH 2 -#define R_TIMER_CTRL__tm0__stop_ld 0 -#define R_TIMER_CTRL__tm0__freeze 1 -#define R_TIMER_CTRL__tm0__run 2 -#define R_TIMER_CTRL__tm0__reserved 3 -#define R_TIMER_CTRL__clksel0__BITNR 0 -#define R_TIMER_CTRL__clksel0__WIDTH 4 -#define R_TIMER_CTRL__clksel0__c300Hz 0 -#define R_TIMER_CTRL__clksel0__c600Hz 1 -#define R_TIMER_CTRL__clksel0__c1200Hz 2 -#define R_TIMER_CTRL__clksel0__c2400Hz 3 -#define R_TIMER_CTRL__clksel0__c4800Hz 4 -#define R_TIMER_CTRL__clksel0__c9600Hz 5 -#define R_TIMER_CTRL__clksel0__c19k2Hz 6 -#define R_TIMER_CTRL__clksel0__c38k4Hz 7 -#define R_TIMER_CTRL__clksel0__c57k6Hz 8 -#define R_TIMER_CTRL__clksel0__c115k2Hz 9 -#define R_TIMER_CTRL__clksel0__c230k4Hz 10 -#define R_TIMER_CTRL__clksel0__c460k8Hz 11 -#define R_TIMER_CTRL__clksel0__c921k6Hz 12 -#define R_TIMER_CTRL__clksel0__c1843k2Hz 13 -#define R_TIMER_CTRL__clksel0__c6250kHz 14 -#define R_TIMER_CTRL__clksel0__flexible 15 - -#define R_TIMER_DATA (IO_TYPECAST_RO_UDWORD 0xb0000020) -#define R_TIMER_DATA__timer1__BITNR 24 -#define R_TIMER_DATA__timer1__WIDTH 8 -#define R_TIMER_DATA__timer0__BITNR 16 -#define R_TIMER_DATA__timer0__WIDTH 8 -#define R_TIMER_DATA__clkdiv_high__BITNR 8 -#define R_TIMER_DATA__clkdiv_high__WIDTH 8 -#define R_TIMER_DATA__clkdiv_low__BITNR 0 -#define R_TIMER_DATA__clkdiv_low__WIDTH 8 - -#define R_TIMER01_DATA (IO_TYPECAST_RO_UWORD 0xb0000022) -#define R_TIMER01_DATA__count__BITNR 0 -#define R_TIMER01_DATA__count__WIDTH 16 - -#define R_TIMER0_DATA (IO_TYPECAST_RO_BYTE 0xb0000022) -#define R_TIMER0_DATA__count__BITNR 0 -#define R_TIMER0_DATA__count__WIDTH 8 - -#define R_TIMER1_DATA (IO_TYPECAST_RO_BYTE 0xb0000023) -#define R_TIMER1_DATA__count__BITNR 0 -#define R_TIMER1_DATA__count__WIDTH 8 - -#define R_WATCHDOG (IO_TYPECAST_UDWORD 0xb0000024) -#define R_WATCHDOG__key__BITNR 1 -#define R_WATCHDOG__key__WIDTH 3 -#define R_WATCHDOG__enable__BITNR 0 -#define R_WATCHDOG__enable__WIDTH 1 -#define R_WATCHDOG__enable__stop 0 -#define R_WATCHDOG__enable__start 1 - -#define R_CLOCK_PRESCALE (IO_TYPECAST_UDWORD 0xb00000f0) -#define R_CLOCK_PRESCALE__ser_presc__BITNR 16 -#define R_CLOCK_PRESCALE__ser_presc__WIDTH 16 -#define R_CLOCK_PRESCALE__tim_presc__BITNR 0 -#define R_CLOCK_PRESCALE__tim_presc__WIDTH 16 - -#define R_SERIAL_PRESCALE (IO_TYPECAST_UWORD 0xb00000f2) -#define R_SERIAL_PRESCALE__ser_presc__BITNR 0 -#define R_SERIAL_PRESCALE__ser_presc__WIDTH 16 - -#define R_TIMER_PRESCALE (IO_TYPECAST_UWORD 0xb00000f0) -#define R_TIMER_PRESCALE__tim_presc__BITNR 0 -#define R_TIMER_PRESCALE__tim_presc__WIDTH 16 - -#define R_PRESCALE_STATUS (IO_TYPECAST_RO_UDWORD 0xb00000f0) -#define R_PRESCALE_STATUS__ser_status__BITNR 16 -#define R_PRESCALE_STATUS__ser_status__WIDTH 16 -#define R_PRESCALE_STATUS__tim_status__BITNR 0 -#define R_PRESCALE_STATUS__tim_status__WIDTH 16 - -#define R_SER_PRESC_STATUS (IO_TYPECAST_RO_UWORD 0xb00000f2) -#define R_SER_PRESC_STATUS__ser_status__BITNR 0 -#define R_SER_PRESC_STATUS__ser_status__WIDTH 16 - -#define R_TIM_PRESC_STATUS (IO_TYPECAST_RO_UWORD 0xb00000f0) -#define R_TIM_PRESC_STATUS__tim_status__BITNR 0 -#define R_TIM_PRESC_STATUS__tim_status__WIDTH 16 - -#define R_SYNC_SERIAL_PRESCALE (IO_TYPECAST_UDWORD 0xb00000f4) -#define R_SYNC_SERIAL_PRESCALE__clk_sel_u3__BITNR 23 -#define R_SYNC_SERIAL_PRESCALE__clk_sel_u3__WIDTH 1 -#define R_SYNC_SERIAL_PRESCALE__clk_sel_u3__codec 0 -#define R_SYNC_SERIAL_PRESCALE__clk_sel_u3__baudrate 1 -#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u3__BITNR 22 -#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u3__WIDTH 1 -#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u3__external 0 -#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u3__internal 1 -#define R_SYNC_SERIAL_PRESCALE__clk_sel_u1__BITNR 21 -#define R_SYNC_SERIAL_PRESCALE__clk_sel_u1__WIDTH 1 -#define R_SYNC_SERIAL_PRESCALE__clk_sel_u1__codec 0 -#define R_SYNC_SERIAL_PRESCALE__clk_sel_u1__baudrate 1 -#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u1__BITNR 20 -#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u1__WIDTH 1 -#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u1__external 0 -#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u1__internal 1 -#define R_SYNC_SERIAL_PRESCALE__prescaler__BITNR 16 -#define R_SYNC_SERIAL_PRESCALE__prescaler__WIDTH 3 -#define R_SYNC_SERIAL_PRESCALE__prescaler__div1 0 -#define R_SYNC_SERIAL_PRESCALE__prescaler__div2 1 -#define R_SYNC_SERIAL_PRESCALE__prescaler__div4 2 -#define R_SYNC_SERIAL_PRESCALE__prescaler__div8 3 -#define R_SYNC_SERIAL_PRESCALE__prescaler__div16 4 -#define R_SYNC_SERIAL_PRESCALE__prescaler__div32 5 -#define R_SYNC_SERIAL_PRESCALE__prescaler__div64 6 -#define R_SYNC_SERIAL_PRESCALE__prescaler__div128 7 -#define R_SYNC_SERIAL_PRESCALE__warp_mode__BITNR 15 -#define R_SYNC_SERIAL_PRESCALE__warp_mode__WIDTH 1 -#define R_SYNC_SERIAL_PRESCALE__warp_mode__normal 0 -#define R_SYNC_SERIAL_PRESCALE__warp_mode__enabled 1 -#define R_SYNC_SERIAL_PRESCALE__frame_rate__BITNR 11 -#define R_SYNC_SERIAL_PRESCALE__frame_rate__WIDTH 4 -#define R_SYNC_SERIAL_PRESCALE__word_rate__BITNR 0 -#define R_SYNC_SERIAL_PRESCALE__word_rate__WIDTH 10 - -/* -!* Shared RAM interface registers -!*/ - -#define R_SHARED_RAM_CONFIG (IO_TYPECAST_UDWORD 0xb0000040) -#define R_SHARED_RAM_CONFIG__width__BITNR 3 -#define R_SHARED_RAM_CONFIG__width__WIDTH 1 -#define R_SHARED_RAM_CONFIG__width__byte 0 -#define R_SHARED_RAM_CONFIG__width__word 1 -#define R_SHARED_RAM_CONFIG__enable__BITNR 2 -#define R_SHARED_RAM_CONFIG__enable__WIDTH 1 -#define R_SHARED_RAM_CONFIG__enable__yes 1 -#define R_SHARED_RAM_CONFIG__enable__no 0 -#define R_SHARED_RAM_CONFIG__pint__BITNR 1 -#define R_SHARED_RAM_CONFIG__pint__WIDTH 1 -#define R_SHARED_RAM_CONFIG__pint__int 1 -#define R_SHARED_RAM_CONFIG__pint__nop 0 -#define R_SHARED_RAM_CONFIG__clri__BITNR 0 -#define R_SHARED_RAM_CONFIG__clri__WIDTH 1 -#define R_SHARED_RAM_CONFIG__clri__clr 1 -#define R_SHARED_RAM_CONFIG__clri__nop 0 - -#define R_SHARED_RAM_ADDR (IO_TYPECAST_UDWORD 0xb0000044) -#define R_SHARED_RAM_ADDR__base_addr__BITNR 8 -#define R_SHARED_RAM_ADDR__base_addr__WIDTH 22 - -/* -!* General config registers -!*/ - -#define R_GEN_CONFIG (IO_TYPECAST_UDWORD 0xb000002c) -#define R_GEN_CONFIG__par_w__BITNR 31 -#define R_GEN_CONFIG__par_w__WIDTH 1 -#define R_GEN_CONFIG__par_w__select 1 -#define R_GEN_CONFIG__par_w__disable 0 -#define R_GEN_CONFIG__usb2__BITNR 30 -#define R_GEN_CONFIG__usb2__WIDTH 1 -#define R_GEN_CONFIG__usb2__select 1 -#define R_GEN_CONFIG__usb2__disable 0 -#define R_GEN_CONFIG__usb1__BITNR 29 -#define R_GEN_CONFIG__usb1__WIDTH 1 -#define R_GEN_CONFIG__usb1__select 1 -#define R_GEN_CONFIG__usb1__disable 0 -#define R_GEN_CONFIG__g24dir__BITNR 27 -#define R_GEN_CONFIG__g24dir__WIDTH 1 -#define R_GEN_CONFIG__g24dir__in 0 -#define R_GEN_CONFIG__g24dir__out 1 -#define R_GEN_CONFIG__g16_23dir__BITNR 26 -#define R_GEN_CONFIG__g16_23dir__WIDTH 1 -#define R_GEN_CONFIG__g16_23dir__in 0 -#define R_GEN_CONFIG__g16_23dir__out 1 -#define R_GEN_CONFIG__g8_15dir__BITNR 25 -#define R_GEN_CONFIG__g8_15dir__WIDTH 1 -#define R_GEN_CONFIG__g8_15dir__in 0 -#define R_GEN_CONFIG__g8_15dir__out 1 -#define R_GEN_CONFIG__g0dir__BITNR 24 -#define R_GEN_CONFIG__g0dir__WIDTH 1 -#define R_GEN_CONFIG__g0dir__in 0 -#define R_GEN_CONFIG__g0dir__out 1 -#define R_GEN_CONFIG__dma9__BITNR 23 -#define R_GEN_CONFIG__dma9__WIDTH 1 -#define R_GEN_CONFIG__dma9__usb 0 -#define R_GEN_CONFIG__dma9__serial1 1 -#define R_GEN_CONFIG__dma8__BITNR 22 -#define R_GEN_CONFIG__dma8__WIDTH 1 -#define R_GEN_CONFIG__dma8__usb 0 -#define R_GEN_CONFIG__dma8__serial1 1 -#define R_GEN_CONFIG__dma7__BITNR 20 -#define R_GEN_CONFIG__dma7__WIDTH 2 -#define R_GEN_CONFIG__dma7__unused 0 -#define R_GEN_CONFIG__dma7__serial0 1 -#define R_GEN_CONFIG__dma7__extdma1 2 -#define R_GEN_CONFIG__dma7__intdma6 3 -#define R_GEN_CONFIG__dma6__BITNR 18 -#define R_GEN_CONFIG__dma6__WIDTH 2 -#define R_GEN_CONFIG__dma6__unused 0 -#define R_GEN_CONFIG__dma6__serial0 1 -#define R_GEN_CONFIG__dma6__extdma1 2 -#define R_GEN_CONFIG__dma6__intdma7 3 -#define R_GEN_CONFIG__dma5__BITNR 16 -#define R_GEN_CONFIG__dma5__WIDTH 2 -#define R_GEN_CONFIG__dma5__par1 0 -#define R_GEN_CONFIG__dma5__scsi1 1 -#define R_GEN_CONFIG__dma5__serial3 2 -#define R_GEN_CONFIG__dma5__extdma0 3 -#define R_GEN_CONFIG__dma4__BITNR 14 -#define R_GEN_CONFIG__dma4__WIDTH 2 -#define R_GEN_CONFIG__dma4__par1 0 -#define R_GEN_CONFIG__dma4__scsi1 1 -#define R_GEN_CONFIG__dma4__serial3 2 -#define R_GEN_CONFIG__dma4__extdma0 3 -#define R_GEN_CONFIG__dma3__BITNR 12 -#define R_GEN_CONFIG__dma3__WIDTH 2 -#define R_GEN_CONFIG__dma3__par0 0 -#define R_GEN_CONFIG__dma3__scsi0 1 -#define R_GEN_CONFIG__dma3__serial2 2 -#define R_GEN_CONFIG__dma3__ata 3 -#define R_GEN_CONFIG__dma2__BITNR 10 -#define R_GEN_CONFIG__dma2__WIDTH 2 -#define R_GEN_CONFIG__dma2__par0 0 -#define R_GEN_CONFIG__dma2__scsi0 1 -#define R_GEN_CONFIG__dma2__serial2 2 -#define R_GEN_CONFIG__dma2__ata 3 -#define R_GEN_CONFIG__mio_w__BITNR 9 -#define R_GEN_CONFIG__mio_w__WIDTH 1 -#define R_GEN_CONFIG__mio_w__select 1 -#define R_GEN_CONFIG__mio_w__disable 0 -#define R_GEN_CONFIG__ser3__BITNR 8 -#define R_GEN_CONFIG__ser3__WIDTH 1 -#define R_GEN_CONFIG__ser3__select 1 -#define R_GEN_CONFIG__ser3__disable 0 -#define R_GEN_CONFIG__par1__BITNR 7 -#define R_GEN_CONFIG__par1__WIDTH 1 -#define R_GEN_CONFIG__par1__select 1 -#define R_GEN_CONFIG__par1__disable 0 -#define R_GEN_CONFIG__scsi0w__BITNR 6 -#define R_GEN_CONFIG__scsi0w__WIDTH 1 -#define R_GEN_CONFIG__scsi0w__select 1 -#define R_GEN_CONFIG__scsi0w__disable 0 -#define R_GEN_CONFIG__scsi1__BITNR 5 -#define R_GEN_CONFIG__scsi1__WIDTH 1 -#define R_GEN_CONFIG__scsi1__select 1 -#define R_GEN_CONFIG__scsi1__disable 0 -#define R_GEN_CONFIG__mio__BITNR 4 -#define R_GEN_CONFIG__mio__WIDTH 1 -#define R_GEN_CONFIG__mio__select 1 -#define R_GEN_CONFIG__mio__disable 0 -#define R_GEN_CONFIG__ser2__BITNR 3 -#define R_GEN_CONFIG__ser2__WIDTH 1 -#define R_GEN_CONFIG__ser2__select 1 -#define R_GEN_CONFIG__ser2__disable 0 -#define R_GEN_CONFIG__par0__BITNR 2 -#define R_GEN_CONFIG__par0__WIDTH 1 -#define R_GEN_CONFIG__par0__select 1 -#define R_GEN_CONFIG__par0__disable 0 -#define R_GEN_CONFIG__ata__BITNR 1 -#define R_GEN_CONFIG__ata__WIDTH 1 -#define R_GEN_CONFIG__ata__select 1 -#define R_GEN_CONFIG__ata__disable 0 -#define R_GEN_CONFIG__scsi0__BITNR 0 -#define R_GEN_CONFIG__scsi0__WIDTH 1 -#define R_GEN_CONFIG__scsi0__select 1 -#define R_GEN_CONFIG__scsi0__disable 0 - -#define R_GEN_CONFIG_II (IO_TYPECAST_UDWORD 0xb0000034) -#define R_GEN_CONFIG_II__sermode3__BITNR 6 -#define R_GEN_CONFIG_II__sermode3__WIDTH 1 -#define R_GEN_CONFIG_II__sermode3__async 0 -#define R_GEN_CONFIG_II__sermode3__sync 1 -#define R_GEN_CONFIG_II__sermode1__BITNR 4 -#define R_GEN_CONFIG_II__sermode1__WIDTH 1 -#define R_GEN_CONFIG_II__sermode1__async 0 -#define R_GEN_CONFIG_II__sermode1__sync 1 -#define R_GEN_CONFIG_II__ext_clk__BITNR 2 -#define R_GEN_CONFIG_II__ext_clk__WIDTH 1 -#define R_GEN_CONFIG_II__ext_clk__select 1 -#define R_GEN_CONFIG_II__ext_clk__disable 0 -#define R_GEN_CONFIG_II__ser2__BITNR 1 -#define R_GEN_CONFIG_II__ser2__WIDTH 1 -#define R_GEN_CONFIG_II__ser2__select 1 -#define R_GEN_CONFIG_II__ser2__disable 0 -#define R_GEN_CONFIG_II__ser3__BITNR 0 -#define R_GEN_CONFIG_II__ser3__WIDTH 1 -#define R_GEN_CONFIG_II__ser3__select 1 -#define R_GEN_CONFIG_II__ser3__disable 0 - -#define R_PORT_G_DATA (IO_TYPECAST_UDWORD 0xb0000028) -#define R_PORT_G_DATA__data__BITNR 0 -#define R_PORT_G_DATA__data__WIDTH 32 - -/* -!* General port configuration registers -!*/ - -#define R_PORT_PA_SET (IO_TYPECAST_UDWORD 0xb0000030) -#define R_PORT_PA_SET__dir7__BITNR 15 -#define R_PORT_PA_SET__dir7__WIDTH 1 -#define R_PORT_PA_SET__dir7__input 0 -#define R_PORT_PA_SET__dir7__output 1 -#define R_PORT_PA_SET__dir6__BITNR 14 -#define R_PORT_PA_SET__dir6__WIDTH 1 -#define R_PORT_PA_SET__dir6__input 0 -#define R_PORT_PA_SET__dir6__output 1 -#define R_PORT_PA_SET__dir5__BITNR 13 -#define R_PORT_PA_SET__dir5__WIDTH 1 -#define R_PORT_PA_SET__dir5__input 0 -#define R_PORT_PA_SET__dir5__output 1 -#define R_PORT_PA_SET__dir4__BITNR 12 -#define R_PORT_PA_SET__dir4__WIDTH 1 -#define R_PORT_PA_SET__dir4__input 0 -#define R_PORT_PA_SET__dir4__output 1 -#define R_PORT_PA_SET__dir3__BITNR 11 -#define R_PORT_PA_SET__dir3__WIDTH 1 -#define R_PORT_PA_SET__dir3__input 0 -#define R_PORT_PA_SET__dir3__output 1 -#define R_PORT_PA_SET__dir2__BITNR 10 -#define R_PORT_PA_SET__dir2__WIDTH 1 -#define R_PORT_PA_SET__dir2__input 0 -#define R_PORT_PA_SET__dir2__output 1 -#define R_PORT_PA_SET__dir1__BITNR 9 -#define R_PORT_PA_SET__dir1__WIDTH 1 -#define R_PORT_PA_SET__dir1__input 0 -#define R_PORT_PA_SET__dir1__output 1 -#define R_PORT_PA_SET__dir0__BITNR 8 -#define R_PORT_PA_SET__dir0__WIDTH 1 -#define R_PORT_PA_SET__dir0__input 0 -#define R_PORT_PA_SET__dir0__output 1 -#define R_PORT_PA_SET__data_out__BITNR 0 -#define R_PORT_PA_SET__data_out__WIDTH 8 - -#define R_PORT_PA_DATA (IO_TYPECAST_BYTE 0xb0000030) -#define R_PORT_PA_DATA__data_out__BITNR 0 -#define R_PORT_PA_DATA__data_out__WIDTH 8 - -#define R_PORT_PA_DIR (IO_TYPECAST_BYTE 0xb0000031) -#define R_PORT_PA_DIR__dir7__BITNR 7 -#define R_PORT_PA_DIR__dir7__WIDTH 1 -#define R_PORT_PA_DIR__dir7__input 0 -#define R_PORT_PA_DIR__dir7__output 1 -#define R_PORT_PA_DIR__dir6__BITNR 6 -#define R_PORT_PA_DIR__dir6__WIDTH 1 -#define R_PORT_PA_DIR__dir6__input 0 -#define R_PORT_PA_DIR__dir6__output 1 -#define R_PORT_PA_DIR__dir5__BITNR 5 -#define R_PORT_PA_DIR__dir5__WIDTH 1 -#define R_PORT_PA_DIR__dir5__input 0 -#define R_PORT_PA_DIR__dir5__output 1 -#define R_PORT_PA_DIR__dir4__BITNR 4 -#define R_PORT_PA_DIR__dir4__WIDTH 1 -#define R_PORT_PA_DIR__dir4__input 0 -#define R_PORT_PA_DIR__dir4__output 1 -#define R_PORT_PA_DIR__dir3__BITNR 3 -#define R_PORT_PA_DIR__dir3__WIDTH 1 -#define R_PORT_PA_DIR__dir3__input 0 -#define R_PORT_PA_DIR__dir3__output 1 -#define R_PORT_PA_DIR__dir2__BITNR 2 -#define R_PORT_PA_DIR__dir2__WIDTH 1 -#define R_PORT_PA_DIR__dir2__input 0 -#define R_PORT_PA_DIR__dir2__output 1 -#define R_PORT_PA_DIR__dir1__BITNR 1 -#define R_PORT_PA_DIR__dir1__WIDTH 1 -#define R_PORT_PA_DIR__dir1__input 0 -#define R_PORT_PA_DIR__dir1__output 1 -#define R_PORT_PA_DIR__dir0__BITNR 0 -#define R_PORT_PA_DIR__dir0__WIDTH 1 -#define R_PORT_PA_DIR__dir0__input 0 -#define R_PORT_PA_DIR__dir0__output 1 - -#define R_PORT_PA_READ (IO_TYPECAST_RO_UDWORD 0xb0000030) -#define R_PORT_PA_READ__data_in__BITNR 0 -#define R_PORT_PA_READ__data_in__WIDTH 8 - -#define R_PORT_PB_SET (IO_TYPECAST_UDWORD 0xb0000038) -#define R_PORT_PB_SET__syncser3__BITNR 29 -#define R_PORT_PB_SET__syncser3__WIDTH 1 -#define R_PORT_PB_SET__syncser3__port_cs 0 -#define R_PORT_PB_SET__syncser3__ss3extra 1 -#define R_PORT_PB_SET__syncser1__BITNR 28 -#define R_PORT_PB_SET__syncser1__WIDTH 1 -#define R_PORT_PB_SET__syncser1__port_cs 0 -#define R_PORT_PB_SET__syncser1__ss1extra 1 -#define R_PORT_PB_SET__i2c_en__BITNR 27 -#define R_PORT_PB_SET__i2c_en__WIDTH 1 -#define R_PORT_PB_SET__i2c_en__off 0 -#define R_PORT_PB_SET__i2c_en__on 1 -#define R_PORT_PB_SET__i2c_d__BITNR 26 -#define R_PORT_PB_SET__i2c_d__WIDTH 1 -#define R_PORT_PB_SET__i2c_clk__BITNR 25 -#define R_PORT_PB_SET__i2c_clk__WIDTH 1 -#define R_PORT_PB_SET__i2c_oe___BITNR 24 -#define R_PORT_PB_SET__i2c_oe___WIDTH 1 -#define R_PORT_PB_SET__i2c_oe___enable 0 -#define R_PORT_PB_SET__i2c_oe___disable 1 -#define R_PORT_PB_SET__cs7__BITNR 23 -#define R_PORT_PB_SET__cs7__WIDTH 1 -#define R_PORT_PB_SET__cs7__port 0 -#define R_PORT_PB_SET__cs7__cs 1 -#define R_PORT_PB_SET__cs6__BITNR 22 -#define R_PORT_PB_SET__cs6__WIDTH 1 -#define R_PORT_PB_SET__cs6__port 0 -#define R_PORT_PB_SET__cs6__cs 1 -#define R_PORT_PB_SET__cs5__BITNR 21 -#define R_PORT_PB_SET__cs5__WIDTH 1 -#define R_PORT_PB_SET__cs5__port 0 -#define R_PORT_PB_SET__cs5__cs 1 -#define R_PORT_PB_SET__cs4__BITNR 20 -#define R_PORT_PB_SET__cs4__WIDTH 1 -#define R_PORT_PB_SET__cs4__port 0 -#define R_PORT_PB_SET__cs4__cs 1 -#define R_PORT_PB_SET__cs3__BITNR 19 -#define R_PORT_PB_SET__cs3__WIDTH 1 -#define R_PORT_PB_SET__cs3__port 0 -#define R_PORT_PB_SET__cs3__cs 1 -#define R_PORT_PB_SET__cs2__BITNR 18 -#define R_PORT_PB_SET__cs2__WIDTH 1 -#define R_PORT_PB_SET__cs2__port 0 -#define R_PORT_PB_SET__cs2__cs 1 -#define R_PORT_PB_SET__scsi1__BITNR 17 -#define R_PORT_PB_SET__scsi1__WIDTH 1 -#define R_PORT_PB_SET__scsi1__port_cs 0 -#define R_PORT_PB_SET__scsi1__enph 1 -#define R_PORT_PB_SET__scsi0__BITNR 16 -#define R_PORT_PB_SET__scsi0__WIDTH 1 -#define R_PORT_PB_SET__scsi0__port_cs 0 -#define R_PORT_PB_SET__scsi0__enph 1 -#define R_PORT_PB_SET__dir7__BITNR 15 -#define R_PORT_PB_SET__dir7__WIDTH 1 -#define R_PORT_PB_SET__dir7__input 0 -#define R_PORT_PB_SET__dir7__output 1 -#define R_PORT_PB_SET__dir6__BITNR 14 -#define R_PORT_PB_SET__dir6__WIDTH 1 -#define R_PORT_PB_SET__dir6__input 0 -#define R_PORT_PB_SET__dir6__output 1 -#define R_PORT_PB_SET__dir5__BITNR 13 -#define R_PORT_PB_SET__dir5__WIDTH 1 -#define R_PORT_PB_SET__dir5__input 0 -#define R_PORT_PB_SET__dir5__output 1 -#define R_PORT_PB_SET__dir4__BITNR 12 -#define R_PORT_PB_SET__dir4__WIDTH 1 -#define R_PORT_PB_SET__dir4__input 0 -#define R_PORT_PB_SET__dir4__output 1 -#define R_PORT_PB_SET__dir3__BITNR 11 -#define R_PORT_PB_SET__dir3__WIDTH 1 -#define R_PORT_PB_SET__dir3__input 0 -#define R_PORT_PB_SET__dir3__output 1 -#define R_PORT_PB_SET__dir2__BITNR 10 -#define R_PORT_PB_SET__dir2__WIDTH 1 -#define R_PORT_PB_SET__dir2__input 0 -#define R_PORT_PB_SET__dir2__output 1 -#define R_PORT_PB_SET__dir1__BITNR 9 -#define R_PORT_PB_SET__dir1__WIDTH 1 -#define R_PORT_PB_SET__dir1__input 0 -#define R_PORT_PB_SET__dir1__output 1 -#define R_PORT_PB_SET__dir0__BITNR 8 -#define R_PORT_PB_SET__dir0__WIDTH 1 -#define R_PORT_PB_SET__dir0__input 0 -#define R_PORT_PB_SET__dir0__output 1 -#define R_PORT_PB_SET__data_out__BITNR 0 -#define R_PORT_PB_SET__data_out__WIDTH 8 - -#define R_PORT_PB_DATA (IO_TYPECAST_BYTE 0xb0000038) -#define R_PORT_PB_DATA__data_out__BITNR 0 -#define R_PORT_PB_DATA__data_out__WIDTH 8 - -#define R_PORT_PB_DIR (IO_TYPECAST_BYTE 0xb0000039) -#define R_PORT_PB_DIR__dir7__BITNR 7 -#define R_PORT_PB_DIR__dir7__WIDTH 1 -#define R_PORT_PB_DIR__dir7__input 0 -#define R_PORT_PB_DIR__dir7__output 1 -#define R_PORT_PB_DIR__dir6__BITNR 6 -#define R_PORT_PB_DIR__dir6__WIDTH 1 -#define R_PORT_PB_DIR__dir6__input 0 -#define R_PORT_PB_DIR__dir6__output 1 -#define R_PORT_PB_DIR__dir5__BITNR 5 -#define R_PORT_PB_DIR__dir5__WIDTH 1 -#define R_PORT_PB_DIR__dir5__input 0 -#define R_PORT_PB_DIR__dir5__output 1 -#define R_PORT_PB_DIR__dir4__BITNR 4 -#define R_PORT_PB_DIR__dir4__WIDTH 1 -#define R_PORT_PB_DIR__dir4__input 0 -#define R_PORT_PB_DIR__dir4__output 1 -#define R_PORT_PB_DIR__dir3__BITNR 3 -#define R_PORT_PB_DIR__dir3__WIDTH 1 -#define R_PORT_PB_DIR__dir3__input 0 -#define R_PORT_PB_DIR__dir3__output 1 -#define R_PORT_PB_DIR__dir2__BITNR 2 -#define R_PORT_PB_DIR__dir2__WIDTH 1 -#define R_PORT_PB_DIR__dir2__input 0 -#define R_PORT_PB_DIR__dir2__output 1 -#define R_PORT_PB_DIR__dir1__BITNR 1 -#define R_PORT_PB_DIR__dir1__WIDTH 1 -#define R_PORT_PB_DIR__dir1__input 0 -#define R_PORT_PB_DIR__dir1__output 1 -#define R_PORT_PB_DIR__dir0__BITNR 0 -#define R_PORT_PB_DIR__dir0__WIDTH 1 -#define R_PORT_PB_DIR__dir0__input 0 -#define R_PORT_PB_DIR__dir0__output 1 - -#define R_PORT_PB_CONFIG (IO_TYPECAST_BYTE 0xb000003a) -#define R_PORT_PB_CONFIG__cs7__BITNR 7 -#define R_PORT_PB_CONFIG__cs7__WIDTH 1 -#define R_PORT_PB_CONFIG__cs7__port 0 -#define R_PORT_PB_CONFIG__cs7__cs 1 -#define R_PORT_PB_CONFIG__cs6__BITNR 6 -#define R_PORT_PB_CONFIG__cs6__WIDTH 1 -#define R_PORT_PB_CONFIG__cs6__port 0 -#define R_PORT_PB_CONFIG__cs6__cs 1 -#define R_PORT_PB_CONFIG__cs5__BITNR 5 -#define R_PORT_PB_CONFIG__cs5__WIDTH 1 -#define R_PORT_PB_CONFIG__cs5__port 0 -#define R_PORT_PB_CONFIG__cs5__cs 1 -#define R_PORT_PB_CONFIG__cs4__BITNR 4 -#define R_PORT_PB_CONFIG__cs4__WIDTH 1 -#define R_PORT_PB_CONFIG__cs4__port 0 -#define R_PORT_PB_CONFIG__cs4__cs 1 -#define R_PORT_PB_CONFIG__cs3__BITNR 3 -#define R_PORT_PB_CONFIG__cs3__WIDTH 1 -#define R_PORT_PB_CONFIG__cs3__port 0 -#define R_PORT_PB_CONFIG__cs3__cs 1 -#define R_PORT_PB_CONFIG__cs2__BITNR 2 -#define R_PORT_PB_CONFIG__cs2__WIDTH 1 -#define R_PORT_PB_CONFIG__cs2__port 0 -#define R_PORT_PB_CONFIG__cs2__cs 1 -#define R_PORT_PB_CONFIG__scsi1__BITNR 1 -#define R_PORT_PB_CONFIG__scsi1__WIDTH 1 -#define R_PORT_PB_CONFIG__scsi1__port_cs 0 -#define R_PORT_PB_CONFIG__scsi1__enph 1 -#define R_PORT_PB_CONFIG__scsi0__BITNR 0 -#define R_PORT_PB_CONFIG__scsi0__WIDTH 1 -#define R_PORT_PB_CONFIG__scsi0__port_cs 0 -#define R_PORT_PB_CONFIG__scsi0__enph 1 - -#define R_PORT_PB_I2C (IO_TYPECAST_BYTE 0xb000003b) -#define R_PORT_PB_I2C__syncser3__BITNR 5 -#define R_PORT_PB_I2C__syncser3__WIDTH 1 -#define R_PORT_PB_I2C__syncser3__port_cs 0 -#define R_PORT_PB_I2C__syncser3__ss3extra 1 -#define R_PORT_PB_I2C__syncser1__BITNR 4 -#define R_PORT_PB_I2C__syncser1__WIDTH 1 -#define R_PORT_PB_I2C__syncser1__port_cs 0 -#define R_PORT_PB_I2C__syncser1__ss1extra 1 -#define R_PORT_PB_I2C__i2c_en__BITNR 3 -#define R_PORT_PB_I2C__i2c_en__WIDTH 1 -#define R_PORT_PB_I2C__i2c_en__off 0 -#define R_PORT_PB_I2C__i2c_en__on 1 -#define R_PORT_PB_I2C__i2c_d__BITNR 2 -#define R_PORT_PB_I2C__i2c_d__WIDTH 1 -#define R_PORT_PB_I2C__i2c_clk__BITNR 1 -#define R_PORT_PB_I2C__i2c_clk__WIDTH 1 -#define R_PORT_PB_I2C__i2c_oe___BITNR 0 -#define R_PORT_PB_I2C__i2c_oe___WIDTH 1 -#define R_PORT_PB_I2C__i2c_oe___enable 0 -#define R_PORT_PB_I2C__i2c_oe___disable 1 - -#define R_PORT_PB_READ (IO_TYPECAST_RO_UDWORD 0xb0000038) -#define R_PORT_PB_READ__data_in__BITNR 0 -#define R_PORT_PB_READ__data_in__WIDTH 8 - -/* -!* Serial port registers -!*/ - -#define R_SERIAL0_CTRL (IO_TYPECAST_UDWORD 0xb0000060) -#define R_SERIAL0_CTRL__tr_baud__BITNR 28 -#define R_SERIAL0_CTRL__tr_baud__WIDTH 4 -#define R_SERIAL0_CTRL__tr_baud__c300Hz 0 -#define R_SERIAL0_CTRL__tr_baud__c600Hz 1 -#define R_SERIAL0_CTRL__tr_baud__c1200Hz 2 -#define R_SERIAL0_CTRL__tr_baud__c2400Hz 3 -#define R_SERIAL0_CTRL__tr_baud__c4800Hz 4 -#define R_SERIAL0_CTRL__tr_baud__c9600Hz 5 -#define R_SERIAL0_CTRL__tr_baud__c19k2Hz 6 -#define R_SERIAL0_CTRL__tr_baud__c38k4Hz 7 -#define R_SERIAL0_CTRL__tr_baud__c57k6Hz 8 -#define R_SERIAL0_CTRL__tr_baud__c115k2Hz 9 -#define R_SERIAL0_CTRL__tr_baud__c230k4Hz 10 -#define R_SERIAL0_CTRL__tr_baud__c460k8Hz 11 -#define R_SERIAL0_CTRL__tr_baud__c921k6Hz 12 -#define R_SERIAL0_CTRL__tr_baud__c1843k2Hz 13 -#define R_SERIAL0_CTRL__tr_baud__c6250kHz 14 -#define R_SERIAL0_CTRL__tr_baud__reserved 15 -#define R_SERIAL0_CTRL__rec_baud__BITNR 24 -#define R_SERIAL0_CTRL__rec_baud__WIDTH 4 -#define R_SERIAL0_CTRL__rec_baud__c300Hz 0 -#define R_SERIAL0_CTRL__rec_baud__c600Hz 1 -#define R_SERIAL0_CTRL__rec_baud__c1200Hz 2 -#define R_SERIAL0_CTRL__rec_baud__c2400Hz 3 -#define R_SERIAL0_CTRL__rec_baud__c4800Hz 4 -#define R_SERIAL0_CTRL__rec_baud__c9600Hz 5 -#define R_SERIAL0_CTRL__rec_baud__c19k2Hz 6 -#define R_SERIAL0_CTRL__rec_baud__c38k4Hz 7 -#define R_SERIAL0_CTRL__rec_baud__c57k6Hz 8 -#define R_SERIAL0_CTRL__rec_baud__c115k2Hz 9 -#define R_SERIAL0_CTRL__rec_baud__c230k4Hz 10 -#define R_SERIAL0_CTRL__rec_baud__c460k8Hz 11 -#define R_SERIAL0_CTRL__rec_baud__c921k6Hz 12 -#define R_SERIAL0_CTRL__rec_baud__c1843k2Hz 13 -#define R_SERIAL0_CTRL__rec_baud__c6250kHz 14 -#define R_SERIAL0_CTRL__rec_baud__reserved 15 -#define R_SERIAL0_CTRL__dma_err__BITNR 23 -#define R_SERIAL0_CTRL__dma_err__WIDTH 1 -#define R_SERIAL0_CTRL__dma_err__stop 0 -#define R_SERIAL0_CTRL__dma_err__ignore 1 -#define R_SERIAL0_CTRL__rec_enable__BITNR 22 -#define R_SERIAL0_CTRL__rec_enable__WIDTH 1 -#define R_SERIAL0_CTRL__rec_enable__disable 0 -#define R_SERIAL0_CTRL__rec_enable__enable 1 -#define R_SERIAL0_CTRL__rts___BITNR 21 -#define R_SERIAL0_CTRL__rts___WIDTH 1 -#define R_SERIAL0_CTRL__rts___active 0 -#define R_SERIAL0_CTRL__rts___inactive 1 -#define R_SERIAL0_CTRL__sampling__BITNR 20 -#define R_SERIAL0_CTRL__sampling__WIDTH 1 -#define R_SERIAL0_CTRL__sampling__middle 0 -#define R_SERIAL0_CTRL__sampling__majority 1 -#define R_SERIAL0_CTRL__rec_stick_par__BITNR 19 -#define R_SERIAL0_CTRL__rec_stick_par__WIDTH 1 -#define R_SERIAL0_CTRL__rec_stick_par__normal 0 -#define R_SERIAL0_CTRL__rec_stick_par__stick 1 -#define R_SERIAL0_CTRL__rec_par__BITNR 18 -#define R_SERIAL0_CTRL__rec_par__WIDTH 1 -#define R_SERIAL0_CTRL__rec_par__even 0 -#define R_SERIAL0_CTRL__rec_par__odd 1 -#define R_SERIAL0_CTRL__rec_par_en__BITNR 17 -#define R_SERIAL0_CTRL__rec_par_en__WIDTH 1 -#define R_SERIAL0_CTRL__rec_par_en__disable 0 -#define R_SERIAL0_CTRL__rec_par_en__enable 1 -#define R_SERIAL0_CTRL__rec_bitnr__BITNR 16 -#define R_SERIAL0_CTRL__rec_bitnr__WIDTH 1 -#define R_SERIAL0_CTRL__rec_bitnr__rec_8bit 0 -#define R_SERIAL0_CTRL__rec_bitnr__rec_7bit 1 -#define R_SERIAL0_CTRL__txd__BITNR 15 -#define R_SERIAL0_CTRL__txd__WIDTH 1 -#define R_SERIAL0_CTRL__tr_enable__BITNR 14 -#define R_SERIAL0_CTRL__tr_enable__WIDTH 1 -#define R_SERIAL0_CTRL__tr_enable__disable 0 -#define R_SERIAL0_CTRL__tr_enable__enable 1 -#define R_SERIAL0_CTRL__auto_cts__BITNR 13 -#define R_SERIAL0_CTRL__auto_cts__WIDTH 1 -#define R_SERIAL0_CTRL__auto_cts__disabled 0 -#define R_SERIAL0_CTRL__auto_cts__active 1 -#define R_SERIAL0_CTRL__stop_bits__BITNR 12 -#define R_SERIAL0_CTRL__stop_bits__WIDTH 1 -#define R_SERIAL0_CTRL__stop_bits__one_bit 0 -#define R_SERIAL0_CTRL__stop_bits__two_bits 1 -#define R_SERIAL0_CTRL__tr_stick_par__BITNR 11 -#define R_SERIAL0_CTRL__tr_stick_par__WIDTH 1 -#define R_SERIAL0_CTRL__tr_stick_par__normal 0 -#define R_SERIAL0_CTRL__tr_stick_par__stick 1 -#define R_SERIAL0_CTRL__tr_par__BITNR 10 -#define R_SERIAL0_CTRL__tr_par__WIDTH 1 -#define R_SERIAL0_CTRL__tr_par__even 0 -#define R_SERIAL0_CTRL__tr_par__odd 1 -#define R_SERIAL0_CTRL__tr_par_en__BITNR 9 -#define R_SERIAL0_CTRL__tr_par_en__WIDTH 1 -#define R_SERIAL0_CTRL__tr_par_en__disable 0 -#define R_SERIAL0_CTRL__tr_par_en__enable 1 -#define R_SERIAL0_CTRL__tr_bitnr__BITNR 8 -#define R_SERIAL0_CTRL__tr_bitnr__WIDTH 1 -#define R_SERIAL0_CTRL__tr_bitnr__tr_8bit 0 -#define R_SERIAL0_CTRL__tr_bitnr__tr_7bit 1 -#define R_SERIAL0_CTRL__data_out__BITNR 0 -#define R_SERIAL0_CTRL__data_out__WIDTH 8 - -#define R_SERIAL0_BAUD (IO_TYPECAST_BYTE 0xb0000063) -#define R_SERIAL0_BAUD__tr_baud__BITNR 4 -#define R_SERIAL0_BAUD__tr_baud__WIDTH 4 -#define R_SERIAL0_BAUD__tr_baud__c300Hz 0 -#define R_SERIAL0_BAUD__tr_baud__c600Hz 1 -#define R_SERIAL0_BAUD__tr_baud__c1200Hz 2 -#define R_SERIAL0_BAUD__tr_baud__c2400Hz 3 -#define R_SERIAL0_BAUD__tr_baud__c4800Hz 4 -#define R_SERIAL0_BAUD__tr_baud__c9600Hz 5 -#define R_SERIAL0_BAUD__tr_baud__c19k2Hz 6 -#define R_SERIAL0_BAUD__tr_baud__c38k4Hz 7 -#define R_SERIAL0_BAUD__tr_baud__c57k6Hz 8 -#define R_SERIAL0_BAUD__tr_baud__c115k2Hz 9 -#define R_SERIAL0_BAUD__tr_baud__c230k4Hz 10 -#define R_SERIAL0_BAUD__tr_baud__c460k8Hz 11 -#define R_SERIAL0_BAUD__tr_baud__c921k6Hz 12 -#define R_SERIAL0_BAUD__tr_baud__c1843k2Hz 13 -#define R_SERIAL0_BAUD__tr_baud__c6250kHz 14 -#define R_SERIAL0_BAUD__tr_baud__reserved 15 -#define R_SERIAL0_BAUD__rec_baud__BITNR 0 -#define R_SERIAL0_BAUD__rec_baud__WIDTH 4 -#define R_SERIAL0_BAUD__rec_baud__c300Hz 0 -#define R_SERIAL0_BAUD__rec_baud__c600Hz 1 -#define R_SERIAL0_BAUD__rec_baud__c1200Hz 2 -#define R_SERIAL0_BAUD__rec_baud__c2400Hz 3 -#define R_SERIAL0_BAUD__rec_baud__c4800Hz 4 -#define R_SERIAL0_BAUD__rec_baud__c9600Hz 5 -#define R_SERIAL0_BAUD__rec_baud__c19k2Hz 6 -#define R_SERIAL0_BAUD__rec_baud__c38k4Hz 7 -#define R_SERIAL0_BAUD__rec_baud__c57k6Hz 8 -#define R_SERIAL0_BAUD__rec_baud__c115k2Hz 9 -#define R_SERIAL0_BAUD__rec_baud__c230k4Hz 10 -#define R_SERIAL0_BAUD__rec_baud__c460k8Hz 11 -#define R_SERIAL0_BAUD__rec_baud__c921k6Hz 12 -#define R_SERIAL0_BAUD__rec_baud__c1843k2Hz 13 -#define R_SERIAL0_BAUD__rec_baud__c6250kHz 14 -#define R_SERIAL0_BAUD__rec_baud__reserved 15 - -#define R_SERIAL0_REC_CTRL (IO_TYPECAST_BYTE 0xb0000062) -#define R_SERIAL0_REC_CTRL__dma_err__BITNR 7 -#define R_SERIAL0_REC_CTRL__dma_err__WIDTH 1 -#define R_SERIAL0_REC_CTRL__dma_err__stop 0 -#define R_SERIAL0_REC_CTRL__dma_err__ignore 1 -#define R_SERIAL0_REC_CTRL__rec_enable__BITNR 6 -#define R_SERIAL0_REC_CTRL__rec_enable__WIDTH 1 -#define R_SERIAL0_REC_CTRL__rec_enable__disable 0 -#define R_SERIAL0_REC_CTRL__rec_enable__enable 1 -#define R_SERIAL0_REC_CTRL__rts___BITNR 5 -#define R_SERIAL0_REC_CTRL__rts___WIDTH 1 -#define R_SERIAL0_REC_CTRL__rts___active 0 -#define R_SERIAL0_REC_CTRL__rts___inactive 1 -#define R_SERIAL0_REC_CTRL__sampling__BITNR 4 -#define R_SERIAL0_REC_CTRL__sampling__WIDTH 1 -#define R_SERIAL0_REC_CTRL__sampling__middle 0 -#define R_SERIAL0_REC_CTRL__sampling__majority 1 -#define R_SERIAL0_REC_CTRL__rec_stick_par__BITNR 3 -#define R_SERIAL0_REC_CTRL__rec_stick_par__WIDTH 1 -#define R_SERIAL0_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL0_REC_CTRL__rec_stick_par__stick 1 -#define R_SERIAL0_REC_CTRL__rec_par__BITNR 2 -#define R_SERIAL0_REC_CTRL__rec_par__WIDTH 1 -#define R_SERIAL0_REC_CTRL__rec_par__even 0 -#define R_SERIAL0_REC_CTRL__rec_par__odd 1 -#define R_SERIAL0_REC_CTRL__rec_par_en__BITNR 1 -#define R_SERIAL0_REC_CTRL__rec_par_en__WIDTH 1 -#define R_SERIAL0_REC_CTRL__rec_par_en__disable 0 -#define R_SERIAL0_REC_CTRL__rec_par_en__enable 1 -#define R_SERIAL0_REC_CTRL__rec_bitnr__BITNR 0 -#define R_SERIAL0_REC_CTRL__rec_bitnr__WIDTH 1 -#define R_SERIAL0_REC_CTRL__rec_bitnr__rec_8bit 0 -#define R_SERIAL0_REC_CTRL__rec_bitnr__rec_7bit 1 - -#define R_SERIAL0_TR_CTRL (IO_TYPECAST_BYTE 0xb0000061) -#define R_SERIAL0_TR_CTRL__txd__BITNR 7 -#define R_SERIAL0_TR_CTRL__txd__WIDTH 1 -#define R_SERIAL0_TR_CTRL__tr_enable__BITNR 6 -#define R_SERIAL0_TR_CTRL__tr_enable__WIDTH 1 -#define R_SERIAL0_TR_CTRL__tr_enable__disable 0 -#define R_SERIAL0_TR_CTRL__tr_enable__enable 1 -#define R_SERIAL0_TR_CTRL__auto_cts__BITNR 5 -#define R_SERIAL0_TR_CTRL__auto_cts__WIDTH 1 -#define R_SERIAL0_TR_CTRL__auto_cts__disabled 0 -#define R_SERIAL0_TR_CTRL__auto_cts__active 1 -#define R_SERIAL0_TR_CTRL__stop_bits__BITNR 4 -#define R_SERIAL0_TR_CTRL__stop_bits__WIDTH 1 -#define R_SERIAL0_TR_CTRL__stop_bits__one_bit 0 -#define R_SERIAL0_TR_CTRL__stop_bits__two_bits 1 -#define R_SERIAL0_TR_CTRL__tr_stick_par__BITNR 3 -#define R_SERIAL0_TR_CTRL__tr_stick_par__WIDTH 1 -#define R_SERIAL0_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL0_TR_CTRL__tr_stick_par__stick 1 -#define R_SERIAL0_TR_CTRL__tr_par__BITNR 2 -#define R_SERIAL0_TR_CTRL__tr_par__WIDTH 1 -#define R_SERIAL0_TR_CTRL__tr_par__even 0 -#define R_SERIAL0_TR_CTRL__tr_par__odd 1 -#define R_SERIAL0_TR_CTRL__tr_par_en__BITNR 1 -#define R_SERIAL0_TR_CTRL__tr_par_en__WIDTH 1 -#define R_SERIAL0_TR_CTRL__tr_par_en__disable 0 -#define R_SERIAL0_TR_CTRL__tr_par_en__enable 1 -#define R_SERIAL0_TR_CTRL__tr_bitnr__BITNR 0 -#define R_SERIAL0_TR_CTRL__tr_bitnr__WIDTH 1 -#define R_SERIAL0_TR_CTRL__tr_bitnr__tr_8bit 0 -#define R_SERIAL0_TR_CTRL__tr_bitnr__tr_7bit 1 - -#define R_SERIAL0_TR_DATA (IO_TYPECAST_BYTE 0xb0000060) -#define R_SERIAL0_TR_DATA__data_out__BITNR 0 -#define R_SERIAL0_TR_DATA__data_out__WIDTH 8 - -#define R_SERIAL0_READ (IO_TYPECAST_RO_UDWORD 0xb0000060) -#define R_SERIAL0_READ__xoff_detect__BITNR 15 -#define R_SERIAL0_READ__xoff_detect__WIDTH 1 -#define R_SERIAL0_READ__xoff_detect__no_xoff 0 -#define R_SERIAL0_READ__xoff_detect__xoff 1 -#define R_SERIAL0_READ__cts___BITNR 14 -#define R_SERIAL0_READ__cts___WIDTH 1 -#define R_SERIAL0_READ__cts___active 0 -#define R_SERIAL0_READ__cts___inactive 1 -#define R_SERIAL0_READ__tr_ready__BITNR 13 -#define R_SERIAL0_READ__tr_ready__WIDTH 1 -#define R_SERIAL0_READ__tr_ready__full 0 -#define R_SERIAL0_READ__tr_ready__ready 1 -#define R_SERIAL0_READ__rxd__BITNR 12 -#define R_SERIAL0_READ__rxd__WIDTH 1 -#define R_SERIAL0_READ__overrun__BITNR 11 -#define R_SERIAL0_READ__overrun__WIDTH 1 -#define R_SERIAL0_READ__overrun__no 0 -#define R_SERIAL0_READ__overrun__yes 1 -#define R_SERIAL0_READ__par_err__BITNR 10 -#define R_SERIAL0_READ__par_err__WIDTH 1 -#define R_SERIAL0_READ__par_err__no 0 -#define R_SERIAL0_READ__par_err__yes 1 -#define R_SERIAL0_READ__framing_err__BITNR 9 -#define R_SERIAL0_READ__framing_err__WIDTH 1 -#define R_SERIAL0_READ__framing_err__no 0 -#define R_SERIAL0_READ__framing_err__yes 1 -#define R_SERIAL0_READ__data_avail__BITNR 8 -#define R_SERIAL0_READ__data_avail__WIDTH 1 -#define R_SERIAL0_READ__data_avail__no 0 -#define R_SERIAL0_READ__data_avail__yes 1 -#define R_SERIAL0_READ__data_in__BITNR 0 -#define R_SERIAL0_READ__data_in__WIDTH 8 - -#define R_SERIAL0_STATUS (IO_TYPECAST_RO_BYTE 0xb0000061) -#define R_SERIAL0_STATUS__xoff_detect__BITNR 7 -#define R_SERIAL0_STATUS__xoff_detect__WIDTH 1 -#define R_SERIAL0_STATUS__xoff_detect__no_xoff 0 -#define R_SERIAL0_STATUS__xoff_detect__xoff 1 -#define R_SERIAL0_STATUS__cts___BITNR 6 -#define R_SERIAL0_STATUS__cts___WIDTH 1 -#define R_SERIAL0_STATUS__cts___active 0 -#define R_SERIAL0_STATUS__cts___inactive 1 -#define R_SERIAL0_STATUS__tr_ready__BITNR 5 -#define R_SERIAL0_STATUS__tr_ready__WIDTH 1 -#define R_SERIAL0_STATUS__tr_ready__full 0 -#define R_SERIAL0_STATUS__tr_ready__ready 1 -#define R_SERIAL0_STATUS__rxd__BITNR 4 -#define R_SERIAL0_STATUS__rxd__WIDTH 1 -#define R_SERIAL0_STATUS__overrun__BITNR 3 -#define R_SERIAL0_STATUS__overrun__WIDTH 1 -#define R_SERIAL0_STATUS__overrun__no 0 -#define R_SERIAL0_STATUS__overrun__yes 1 -#define R_SERIAL0_STATUS__par_err__BITNR 2 -#define R_SERIAL0_STATUS__par_err__WIDTH 1 -#define R_SERIAL0_STATUS__par_err__no 0 -#define R_SERIAL0_STATUS__par_err__yes 1 -#define R_SERIAL0_STATUS__framing_err__BITNR 1 -#define R_SERIAL0_STATUS__framing_err__WIDTH 1 -#define R_SERIAL0_STATUS__framing_err__no 0 -#define R_SERIAL0_STATUS__framing_err__yes 1 -#define R_SERIAL0_STATUS__data_avail__BITNR 0 -#define R_SERIAL0_STATUS__data_avail__WIDTH 1 -#define R_SERIAL0_STATUS__data_avail__no 0 -#define R_SERIAL0_STATUS__data_avail__yes 1 - -#define R_SERIAL0_REC_DATA (IO_TYPECAST_RO_BYTE 0xb0000060) -#define R_SERIAL0_REC_DATA__data_in__BITNR 0 -#define R_SERIAL0_REC_DATA__data_in__WIDTH 8 - -#define R_SERIAL0_XOFF (IO_TYPECAST_UDWORD 0xb0000064) -#define R_SERIAL0_XOFF__tx_stop__BITNR 9 -#define R_SERIAL0_XOFF__tx_stop__WIDTH 1 -#define R_SERIAL0_XOFF__tx_stop__enable 0 -#define R_SERIAL0_XOFF__tx_stop__stop 1 -#define R_SERIAL0_XOFF__auto_xoff__BITNR 8 -#define R_SERIAL0_XOFF__auto_xoff__WIDTH 1 -#define R_SERIAL0_XOFF__auto_xoff__disable 0 -#define R_SERIAL0_XOFF__auto_xoff__enable 1 -#define R_SERIAL0_XOFF__xoff_char__BITNR 0 -#define R_SERIAL0_XOFF__xoff_char__WIDTH 8 - -#define R_SERIAL1_CTRL (IO_TYPECAST_UDWORD 0xb0000068) -#define R_SERIAL1_CTRL__tr_baud__BITNR 28 -#define R_SERIAL1_CTRL__tr_baud__WIDTH 4 -#define R_SERIAL1_CTRL__tr_baud__c300Hz 0 -#define R_SERIAL1_CTRL__tr_baud__c600Hz 1 -#define R_SERIAL1_CTRL__tr_baud__c1200Hz 2 -#define R_SERIAL1_CTRL__tr_baud__c2400Hz 3 -#define R_SERIAL1_CTRL__tr_baud__c4800Hz 4 -#define R_SERIAL1_CTRL__tr_baud__c9600Hz 5 -#define R_SERIAL1_CTRL__tr_baud__c19k2Hz 6 -#define R_SERIAL1_CTRL__tr_baud__c38k4Hz 7 -#define R_SERIAL1_CTRL__tr_baud__c57k6Hz 8 -#define R_SERIAL1_CTRL__tr_baud__c115k2Hz 9 -#define R_SERIAL1_CTRL__tr_baud__c230k4Hz 10 -#define R_SERIAL1_CTRL__tr_baud__c460k8Hz 11 -#define R_SERIAL1_CTRL__tr_baud__c921k6Hz 12 -#define R_SERIAL1_CTRL__tr_baud__c1843k2Hz 13 -#define R_SERIAL1_CTRL__tr_baud__c6250kHz 14 -#define R_SERIAL1_CTRL__tr_baud__reserved 15 -#define R_SERIAL1_CTRL__rec_baud__BITNR 24 -#define R_SERIAL1_CTRL__rec_baud__WIDTH 4 -#define R_SERIAL1_CTRL__rec_baud__c300Hz 0 -#define R_SERIAL1_CTRL__rec_baud__c600Hz 1 -#define R_SERIAL1_CTRL__rec_baud__c1200Hz 2 -#define R_SERIAL1_CTRL__rec_baud__c2400Hz 3 -#define R_SERIAL1_CTRL__rec_baud__c4800Hz 4 -#define R_SERIAL1_CTRL__rec_baud__c9600Hz 5 -#define R_SERIAL1_CTRL__rec_baud__c19k2Hz 6 -#define R_SERIAL1_CTRL__rec_baud__c38k4Hz 7 -#define R_SERIAL1_CTRL__rec_baud__c57k6Hz 8 -#define R_SERIAL1_CTRL__rec_baud__c115k2Hz 9 -#define R_SERIAL1_CTRL__rec_baud__c230k4Hz 10 -#define R_SERIAL1_CTRL__rec_baud__c460k8Hz 11 -#define R_SERIAL1_CTRL__rec_baud__c921k6Hz 12 -#define R_SERIAL1_CTRL__rec_baud__c1843k2Hz 13 -#define R_SERIAL1_CTRL__rec_baud__c6250kHz 14 -#define R_SERIAL1_CTRL__rec_baud__reserved 15 -#define R_SERIAL1_CTRL__dma_err__BITNR 23 -#define R_SERIAL1_CTRL__dma_err__WIDTH 1 -#define R_SERIAL1_CTRL__dma_err__stop 0 -#define R_SERIAL1_CTRL__dma_err__ignore 1 -#define R_SERIAL1_CTRL__rec_enable__BITNR 22 -#define R_SERIAL1_CTRL__rec_enable__WIDTH 1 -#define R_SERIAL1_CTRL__rec_enable__disable 0 -#define R_SERIAL1_CTRL__rec_enable__enable 1 -#define R_SERIAL1_CTRL__rts___BITNR 21 -#define R_SERIAL1_CTRL__rts___WIDTH 1 -#define R_SERIAL1_CTRL__rts___active 0 -#define R_SERIAL1_CTRL__rts___inactive 1 -#define R_SERIAL1_CTRL__sampling__BITNR 20 -#define R_SERIAL1_CTRL__sampling__WIDTH 1 -#define R_SERIAL1_CTRL__sampling__middle 0 -#define R_SERIAL1_CTRL__sampling__majority 1 -#define R_SERIAL1_CTRL__rec_stick_par__BITNR 19 -#define R_SERIAL1_CTRL__rec_stick_par__WIDTH 1 -#define R_SERIAL1_CTRL__rec_stick_par__normal 0 -#define R_SERIAL1_CTRL__rec_stick_par__stick 1 -#define R_SERIAL1_CTRL__rec_par__BITNR 18 -#define R_SERIAL1_CTRL__rec_par__WIDTH 1 -#define R_SERIAL1_CTRL__rec_par__even 0 -#define R_SERIAL1_CTRL__rec_par__odd 1 -#define R_SERIAL1_CTRL__rec_par_en__BITNR 17 -#define R_SERIAL1_CTRL__rec_par_en__WIDTH 1 -#define R_SERIAL1_CTRL__rec_par_en__disable 0 -#define R_SERIAL1_CTRL__rec_par_en__enable 1 -#define R_SERIAL1_CTRL__rec_bitnr__BITNR 16 -#define R_SERIAL1_CTRL__rec_bitnr__WIDTH 1 -#define R_SERIAL1_CTRL__rec_bitnr__rec_8bit 0 -#define R_SERIAL1_CTRL__rec_bitnr__rec_7bit 1 -#define R_SERIAL1_CTRL__txd__BITNR 15 -#define R_SERIAL1_CTRL__txd__WIDTH 1 -#define R_SERIAL1_CTRL__tr_enable__BITNR 14 -#define R_SERIAL1_CTRL__tr_enable__WIDTH 1 -#define R_SERIAL1_CTRL__tr_enable__disable 0 -#define R_SERIAL1_CTRL__tr_enable__enable 1 -#define R_SERIAL1_CTRL__auto_cts__BITNR 13 -#define R_SERIAL1_CTRL__auto_cts__WIDTH 1 -#define R_SERIAL1_CTRL__auto_cts__disabled 0 -#define R_SERIAL1_CTRL__auto_cts__active 1 -#define R_SERIAL1_CTRL__stop_bits__BITNR 12 -#define R_SERIAL1_CTRL__stop_bits__WIDTH 1 -#define R_SERIAL1_CTRL__stop_bits__one_bit 0 -#define R_SERIAL1_CTRL__stop_bits__two_bits 1 -#define R_SERIAL1_CTRL__tr_stick_par__BITNR 11 -#define R_SERIAL1_CTRL__tr_stick_par__WIDTH 1 -#define R_SERIAL1_CTRL__tr_stick_par__normal 0 -#define R_SERIAL1_CTRL__tr_stick_par__stick 1 -#define R_SERIAL1_CTRL__tr_par__BITNR 10 -#define R_SERIAL1_CTRL__tr_par__WIDTH 1 -#define R_SERIAL1_CTRL__tr_par__even 0 -#define R_SERIAL1_CTRL__tr_par__odd 1 -#define R_SERIAL1_CTRL__tr_par_en__BITNR 9 -#define R_SERIAL1_CTRL__tr_par_en__WIDTH 1 -#define R_SERIAL1_CTRL__tr_par_en__disable 0 -#define R_SERIAL1_CTRL__tr_par_en__enable 1 -#define R_SERIAL1_CTRL__tr_bitnr__BITNR 8 -#define R_SERIAL1_CTRL__tr_bitnr__WIDTH 1 -#define R_SERIAL1_CTRL__tr_bitnr__tr_8bit 0 -#define R_SERIAL1_CTRL__tr_bitnr__tr_7bit 1 -#define R_SERIAL1_CTRL__data_out__BITNR 0 -#define R_SERIAL1_CTRL__data_out__WIDTH 8 - -#define R_SERIAL1_BAUD (IO_TYPECAST_BYTE 0xb000006b) -#define R_SERIAL1_BAUD__tr_baud__BITNR 4 -#define R_SERIAL1_BAUD__tr_baud__WIDTH 4 -#define R_SERIAL1_BAUD__tr_baud__c300Hz 0 -#define R_SERIAL1_BAUD__tr_baud__c600Hz 1 -#define R_SERIAL1_BAUD__tr_baud__c1200Hz 2 -#define R_SERIAL1_BAUD__tr_baud__c2400Hz 3 -#define R_SERIAL1_BAUD__tr_baud__c4800Hz 4 -#define R_SERIAL1_BAUD__tr_baud__c9600Hz 5 -#define R_SERIAL1_BAUD__tr_baud__c19k2Hz 6 -#define R_SERIAL1_BAUD__tr_baud__c38k4Hz 7 -#define R_SERIAL1_BAUD__tr_baud__c57k6Hz 8 -#define R_SERIAL1_BAUD__tr_baud__c115k2Hz 9 -#define R_SERIAL1_BAUD__tr_baud__c230k4Hz 10 -#define R_SERIAL1_BAUD__tr_baud__c460k8Hz 11 -#define R_SERIAL1_BAUD__tr_baud__c921k6Hz 12 -#define R_SERIAL1_BAUD__tr_baud__c1843k2Hz 13 -#define R_SERIAL1_BAUD__tr_baud__c6250kHz 14 -#define R_SERIAL1_BAUD__tr_baud__reserved 15 -#define R_SERIAL1_BAUD__rec_baud__BITNR 0 -#define R_SERIAL1_BAUD__rec_baud__WIDTH 4 -#define R_SERIAL1_BAUD__rec_baud__c300Hz 0 -#define R_SERIAL1_BAUD__rec_baud__c600Hz 1 -#define R_SERIAL1_BAUD__rec_baud__c1200Hz 2 -#define R_SERIAL1_BAUD__rec_baud__c2400Hz 3 -#define R_SERIAL1_BAUD__rec_baud__c4800Hz 4 -#define R_SERIAL1_BAUD__rec_baud__c9600Hz 5 -#define R_SERIAL1_BAUD__rec_baud__c19k2Hz 6 -#define R_SERIAL1_BAUD__rec_baud__c38k4Hz 7 -#define R_SERIAL1_BAUD__rec_baud__c57k6Hz 8 -#define R_SERIAL1_BAUD__rec_baud__c115k2Hz 9 -#define R_SERIAL1_BAUD__rec_baud__c230k4Hz 10 -#define R_SERIAL1_BAUD__rec_baud__c460k8Hz 11 -#define R_SERIAL1_BAUD__rec_baud__c921k6Hz 12 -#define R_SERIAL1_BAUD__rec_baud__c1843k2Hz 13 -#define R_SERIAL1_BAUD__rec_baud__c6250kHz 14 -#define R_SERIAL1_BAUD__rec_baud__reserved 15 - -#define R_SERIAL1_REC_CTRL (IO_TYPECAST_BYTE 0xb000006a) -#define R_SERIAL1_REC_CTRL__dma_err__BITNR 7 -#define R_SERIAL1_REC_CTRL__dma_err__WIDTH 1 -#define R_SERIAL1_REC_CTRL__dma_err__stop 0 -#define R_SERIAL1_REC_CTRL__dma_err__ignore 1 -#define R_SERIAL1_REC_CTRL__rec_enable__BITNR 6 -#define R_SERIAL1_REC_CTRL__rec_enable__WIDTH 1 -#define R_SERIAL1_REC_CTRL__rec_enable__disable 0 -#define R_SERIAL1_REC_CTRL__rec_enable__enable 1 -#define R_SERIAL1_REC_CTRL__rts___BITNR 5 -#define R_SERIAL1_REC_CTRL__rts___WIDTH 1 -#define R_SERIAL1_REC_CTRL__rts___active 0 -#define R_SERIAL1_REC_CTRL__rts___inactive 1 -#define R_SERIAL1_REC_CTRL__sampling__BITNR 4 -#define R_SERIAL1_REC_CTRL__sampling__WIDTH 1 -#define R_SERIAL1_REC_CTRL__sampling__middle 0 -#define R_SERIAL1_REC_CTRL__sampling__majority 1 -#define R_SERIAL1_REC_CTRL__rec_stick_par__BITNR 3 -#define R_SERIAL1_REC_CTRL__rec_stick_par__WIDTH 1 -#define R_SERIAL1_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL1_REC_CTRL__rec_stick_par__stick 1 -#define R_SERIAL1_REC_CTRL__rec_par__BITNR 2 -#define R_SERIAL1_REC_CTRL__rec_par__WIDTH 1 -#define R_SERIAL1_REC_CTRL__rec_par__even 0 -#define R_SERIAL1_REC_CTRL__rec_par__odd 1 -#define R_SERIAL1_REC_CTRL__rec_par_en__BITNR 1 -#define R_SERIAL1_REC_CTRL__rec_par_en__WIDTH 1 -#define R_SERIAL1_REC_CTRL__rec_par_en__disable 0 -#define R_SERIAL1_REC_CTRL__rec_par_en__enable 1 -#define R_SERIAL1_REC_CTRL__rec_bitnr__BITNR 0 -#define R_SERIAL1_REC_CTRL__rec_bitnr__WIDTH 1 -#define R_SERIAL1_REC_CTRL__rec_bitnr__rec_8bit 0 -#define R_SERIAL1_REC_CTRL__rec_bitnr__rec_7bit 1 - -#define R_SERIAL1_TR_CTRL (IO_TYPECAST_BYTE 0xb0000069) -#define R_SERIAL1_TR_CTRL__txd__BITNR 7 -#define R_SERIAL1_TR_CTRL__txd__WIDTH 1 -#define R_SERIAL1_TR_CTRL__tr_enable__BITNR 6 -#define R_SERIAL1_TR_CTRL__tr_enable__WIDTH 1 -#define R_SERIAL1_TR_CTRL__tr_enable__disable 0 -#define R_SERIAL1_TR_CTRL__tr_enable__enable 1 -#define R_SERIAL1_TR_CTRL__auto_cts__BITNR 5 -#define R_SERIAL1_TR_CTRL__auto_cts__WIDTH 1 -#define R_SERIAL1_TR_CTRL__auto_cts__disabled 0 -#define R_SERIAL1_TR_CTRL__auto_cts__active 1 -#define R_SERIAL1_TR_CTRL__stop_bits__BITNR 4 -#define R_SERIAL1_TR_CTRL__stop_bits__WIDTH 1 -#define R_SERIAL1_TR_CTRL__stop_bits__one_bit 0 -#define R_SERIAL1_TR_CTRL__stop_bits__two_bits 1 -#define R_SERIAL1_TR_CTRL__tr_stick_par__BITNR 3 -#define R_SERIAL1_TR_CTRL__tr_stick_par__WIDTH 1 -#define R_SERIAL1_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL1_TR_CTRL__tr_stick_par__stick 1 -#define R_SERIAL1_TR_CTRL__tr_par__BITNR 2 -#define R_SERIAL1_TR_CTRL__tr_par__WIDTH 1 -#define R_SERIAL1_TR_CTRL__tr_par__even 0 -#define R_SERIAL1_TR_CTRL__tr_par__odd 1 -#define R_SERIAL1_TR_CTRL__tr_par_en__BITNR 1 -#define R_SERIAL1_TR_CTRL__tr_par_en__WIDTH 1 -#define R_SERIAL1_TR_CTRL__tr_par_en__disable 0 -#define R_SERIAL1_TR_CTRL__tr_par_en__enable 1 -#define R_SERIAL1_TR_CTRL__tr_bitnr__BITNR 0 -#define R_SERIAL1_TR_CTRL__tr_bitnr__WIDTH 1 -#define R_SERIAL1_TR_CTRL__tr_bitnr__tr_8bit 0 -#define R_SERIAL1_TR_CTRL__tr_bitnr__tr_7bit 1 - -#define R_SERIAL1_TR_DATA (IO_TYPECAST_BYTE 0xb0000068) -#define R_SERIAL1_TR_DATA__data_out__BITNR 0 -#define R_SERIAL1_TR_DATA__data_out__WIDTH 8 - -#define R_SERIAL1_READ (IO_TYPECAST_RO_UDWORD 0xb0000068) -#define R_SERIAL1_READ__xoff_detect__BITNR 15 -#define R_SERIAL1_READ__xoff_detect__WIDTH 1 -#define R_SERIAL1_READ__xoff_detect__no_xoff 0 -#define R_SERIAL1_READ__xoff_detect__xoff 1 -#define R_SERIAL1_READ__cts___BITNR 14 -#define R_SERIAL1_READ__cts___WIDTH 1 -#define R_SERIAL1_READ__cts___active 0 -#define R_SERIAL1_READ__cts___inactive 1 -#define R_SERIAL1_READ__tr_ready__BITNR 13 -#define R_SERIAL1_READ__tr_ready__WIDTH 1 -#define R_SERIAL1_READ__tr_ready__full 0 -#define R_SERIAL1_READ__tr_ready__ready 1 -#define R_SERIAL1_READ__rxd__BITNR 12 -#define R_SERIAL1_READ__rxd__WIDTH 1 -#define R_SERIAL1_READ__overrun__BITNR 11 -#define R_SERIAL1_READ__overrun__WIDTH 1 -#define R_SERIAL1_READ__overrun__no 0 -#define R_SERIAL1_READ__overrun__yes 1 -#define R_SERIAL1_READ__par_err__BITNR 10 -#define R_SERIAL1_READ__par_err__WIDTH 1 -#define R_SERIAL1_READ__par_err__no 0 -#define R_SERIAL1_READ__par_err__yes 1 -#define R_SERIAL1_READ__framing_err__BITNR 9 -#define R_SERIAL1_READ__framing_err__WIDTH 1 -#define R_SERIAL1_READ__framing_err__no 0 -#define R_SERIAL1_READ__framing_err__yes 1 -#define R_SERIAL1_READ__data_avail__BITNR 8 -#define R_SERIAL1_READ__data_avail__WIDTH 1 -#define R_SERIAL1_READ__data_avail__no 0 -#define R_SERIAL1_READ__data_avail__yes 1 -#define R_SERIAL1_READ__data_in__BITNR 0 -#define R_SERIAL1_READ__data_in__WIDTH 8 - -#define R_SERIAL1_STATUS (IO_TYPECAST_RO_BYTE 0xb0000069) -#define R_SERIAL1_STATUS__xoff_detect__BITNR 7 -#define R_SERIAL1_STATUS__xoff_detect__WIDTH 1 -#define R_SERIAL1_STATUS__xoff_detect__no_xoff 0 -#define R_SERIAL1_STATUS__xoff_detect__xoff 1 -#define R_SERIAL1_STATUS__cts___BITNR 6 -#define R_SERIAL1_STATUS__cts___WIDTH 1 -#define R_SERIAL1_STATUS__cts___active 0 -#define R_SERIAL1_STATUS__cts___inactive 1 -#define R_SERIAL1_STATUS__tr_ready__BITNR 5 -#define R_SERIAL1_STATUS__tr_ready__WIDTH 1 -#define R_SERIAL1_STATUS__tr_ready__full 0 -#define R_SERIAL1_STATUS__tr_ready__ready 1 -#define R_SERIAL1_STATUS__rxd__BITNR 4 -#define R_SERIAL1_STATUS__rxd__WIDTH 1 -#define R_SERIAL1_STATUS__overrun__BITNR 3 -#define R_SERIAL1_STATUS__overrun__WIDTH 1 -#define R_SERIAL1_STATUS__overrun__no 0 -#define R_SERIAL1_STATUS__overrun__yes 1 -#define R_SERIAL1_STATUS__par_err__BITNR 2 -#define R_SERIAL1_STATUS__par_err__WIDTH 1 -#define R_SERIAL1_STATUS__par_err__no 0 -#define R_SERIAL1_STATUS__par_err__yes 1 -#define R_SERIAL1_STATUS__framing_err__BITNR 1 -#define R_SERIAL1_STATUS__framing_err__WIDTH 1 -#define R_SERIAL1_STATUS__framing_err__no 0 -#define R_SERIAL1_STATUS__framing_err__yes 1 -#define R_SERIAL1_STATUS__data_avail__BITNR 0 -#define R_SERIAL1_STATUS__data_avail__WIDTH 1 -#define R_SERIAL1_STATUS__data_avail__no 0 -#define R_SERIAL1_STATUS__data_avail__yes 1 - -#define R_SERIAL1_REC_DATA (IO_TYPECAST_RO_BYTE 0xb0000068) -#define R_SERIAL1_REC_DATA__data_in__BITNR 0 -#define R_SERIAL1_REC_DATA__data_in__WIDTH 8 - -#define R_SERIAL1_XOFF (IO_TYPECAST_UDWORD 0xb000006c) -#define R_SERIAL1_XOFF__tx_stop__BITNR 9 -#define R_SERIAL1_XOFF__tx_stop__WIDTH 1 -#define R_SERIAL1_XOFF__tx_stop__enable 0 -#define R_SERIAL1_XOFF__tx_stop__stop 1 -#define R_SERIAL1_XOFF__auto_xoff__BITNR 8 -#define R_SERIAL1_XOFF__auto_xoff__WIDTH 1 -#define R_SERIAL1_XOFF__auto_xoff__disable 0 -#define R_SERIAL1_XOFF__auto_xoff__enable 1 -#define R_SERIAL1_XOFF__xoff_char__BITNR 0 -#define R_SERIAL1_XOFF__xoff_char__WIDTH 8 - -#define R_SERIAL2_CTRL (IO_TYPECAST_UDWORD 0xb0000070) -#define R_SERIAL2_CTRL__tr_baud__BITNR 28 -#define R_SERIAL2_CTRL__tr_baud__WIDTH 4 -#define R_SERIAL2_CTRL__tr_baud__c300Hz 0 -#define R_SERIAL2_CTRL__tr_baud__c600Hz 1 -#define R_SERIAL2_CTRL__tr_baud__c1200Hz 2 -#define R_SERIAL2_CTRL__tr_baud__c2400Hz 3 -#define R_SERIAL2_CTRL__tr_baud__c4800Hz 4 -#define R_SERIAL2_CTRL__tr_baud__c9600Hz 5 -#define R_SERIAL2_CTRL__tr_baud__c19k2Hz 6 -#define R_SERIAL2_CTRL__tr_baud__c38k4Hz 7 -#define R_SERIAL2_CTRL__tr_baud__c57k6Hz 8 -#define R_SERIAL2_CTRL__tr_baud__c115k2Hz 9 -#define R_SERIAL2_CTRL__tr_baud__c230k4Hz 10 -#define R_SERIAL2_CTRL__tr_baud__c460k8Hz 11 -#define R_SERIAL2_CTRL__tr_baud__c921k6Hz 12 -#define R_SERIAL2_CTRL__tr_baud__c1843k2Hz 13 -#define R_SERIAL2_CTRL__tr_baud__c6250kHz 14 -#define R_SERIAL2_CTRL__tr_baud__reserved 15 -#define R_SERIAL2_CTRL__rec_baud__BITNR 24 -#define R_SERIAL2_CTRL__rec_baud__WIDTH 4 -#define R_SERIAL2_CTRL__rec_baud__c300Hz 0 -#define R_SERIAL2_CTRL__rec_baud__c600Hz 1 -#define R_SERIAL2_CTRL__rec_baud__c1200Hz 2 -#define R_SERIAL2_CTRL__rec_baud__c2400Hz 3 -#define R_SERIAL2_CTRL__rec_baud__c4800Hz 4 -#define R_SERIAL2_CTRL__rec_baud__c9600Hz 5 -#define R_SERIAL2_CTRL__rec_baud__c19k2Hz 6 -#define R_SERIAL2_CTRL__rec_baud__c38k4Hz 7 -#define R_SERIAL2_CTRL__rec_baud__c57k6Hz 8 -#define R_SERIAL2_CTRL__rec_baud__c115k2Hz 9 -#define R_SERIAL2_CTRL__rec_baud__c230k4Hz 10 -#define R_SERIAL2_CTRL__rec_baud__c460k8Hz 11 -#define R_SERIAL2_CTRL__rec_baud__c921k6Hz 12 -#define R_SERIAL2_CTRL__rec_baud__c1843k2Hz 13 -#define R_SERIAL2_CTRL__rec_baud__c6250kHz 14 -#define R_SERIAL2_CTRL__rec_baud__reserved 15 -#define R_SERIAL2_CTRL__dma_err__BITNR 23 -#define R_SERIAL2_CTRL__dma_err__WIDTH 1 -#define R_SERIAL2_CTRL__dma_err__stop 0 -#define R_SERIAL2_CTRL__dma_err__ignore 1 -#define R_SERIAL2_CTRL__rec_enable__BITNR 22 -#define R_SERIAL2_CTRL__rec_enable__WIDTH 1 -#define R_SERIAL2_CTRL__rec_enable__disable 0 -#define R_SERIAL2_CTRL__rec_enable__enable 1 -#define R_SERIAL2_CTRL__rts___BITNR 21 -#define R_SERIAL2_CTRL__rts___WIDTH 1 -#define R_SERIAL2_CTRL__rts___active 0 -#define R_SERIAL2_CTRL__rts___inactive 1 -#define R_SERIAL2_CTRL__sampling__BITNR 20 -#define R_SERIAL2_CTRL__sampling__WIDTH 1 -#define R_SERIAL2_CTRL__sampling__middle 0 -#define R_SERIAL2_CTRL__sampling__majority 1 -#define R_SERIAL2_CTRL__rec_stick_par__BITNR 19 -#define R_SERIAL2_CTRL__rec_stick_par__WIDTH 1 -#define R_SERIAL2_CTRL__rec_stick_par__normal 0 -#define R_SERIAL2_CTRL__rec_stick_par__stick 1 -#define R_SERIAL2_CTRL__rec_par__BITNR 18 -#define R_SERIAL2_CTRL__rec_par__WIDTH 1 -#define R_SERIAL2_CTRL__rec_par__even 0 -#define R_SERIAL2_CTRL__rec_par__odd 1 -#define R_SERIAL2_CTRL__rec_par_en__BITNR 17 -#define R_SERIAL2_CTRL__rec_par_en__WIDTH 1 -#define R_SERIAL2_CTRL__rec_par_en__disable 0 -#define R_SERIAL2_CTRL__rec_par_en__enable 1 -#define R_SERIAL2_CTRL__rec_bitnr__BITNR 16 -#define R_SERIAL2_CTRL__rec_bitnr__WIDTH 1 -#define R_SERIAL2_CTRL__rec_bitnr__rec_8bit 0 -#define R_SERIAL2_CTRL__rec_bitnr__rec_7bit 1 -#define R_SERIAL2_CTRL__txd__BITNR 15 -#define R_SERIAL2_CTRL__txd__WIDTH 1 -#define R_SERIAL2_CTRL__tr_enable__BITNR 14 -#define R_SERIAL2_CTRL__tr_enable__WIDTH 1 -#define R_SERIAL2_CTRL__tr_enable__disable 0 -#define R_SERIAL2_CTRL__tr_enable__enable 1 -#define R_SERIAL2_CTRL__auto_cts__BITNR 13 -#define R_SERIAL2_CTRL__auto_cts__WIDTH 1 -#define R_SERIAL2_CTRL__auto_cts__disabled 0 -#define R_SERIAL2_CTRL__auto_cts__active 1 -#define R_SERIAL2_CTRL__stop_bits__BITNR 12 -#define R_SERIAL2_CTRL__stop_bits__WIDTH 1 -#define R_SERIAL2_CTRL__stop_bits__one_bit 0 -#define R_SERIAL2_CTRL__stop_bits__two_bits 1 -#define R_SERIAL2_CTRL__tr_stick_par__BITNR 11 -#define R_SERIAL2_CTRL__tr_stick_par__WIDTH 1 -#define R_SERIAL2_CTRL__tr_stick_par__normal 0 -#define R_SERIAL2_CTRL__tr_stick_par__stick 1 -#define R_SERIAL2_CTRL__tr_par__BITNR 10 -#define R_SERIAL2_CTRL__tr_par__WIDTH 1 -#define R_SERIAL2_CTRL__tr_par__even 0 -#define R_SERIAL2_CTRL__tr_par__odd 1 -#define R_SERIAL2_CTRL__tr_par_en__BITNR 9 -#define R_SERIAL2_CTRL__tr_par_en__WIDTH 1 -#define R_SERIAL2_CTRL__tr_par_en__disable 0 -#define R_SERIAL2_CTRL__tr_par_en__enable 1 -#define R_SERIAL2_CTRL__tr_bitnr__BITNR 8 -#define R_SERIAL2_CTRL__tr_bitnr__WIDTH 1 -#define R_SERIAL2_CTRL__tr_bitnr__tr_8bit 0 -#define R_SERIAL2_CTRL__tr_bitnr__tr_7bit 1 -#define R_SERIAL2_CTRL__data_out__BITNR 0 -#define R_SERIAL2_CTRL__data_out__WIDTH 8 - -#define R_SERIAL2_BAUD (IO_TYPECAST_BYTE 0xb0000073) -#define R_SERIAL2_BAUD__tr_baud__BITNR 4 -#define R_SERIAL2_BAUD__tr_baud__WIDTH 4 -#define R_SERIAL2_BAUD__tr_baud__c300Hz 0 -#define R_SERIAL2_BAUD__tr_baud__c600Hz 1 -#define R_SERIAL2_BAUD__tr_baud__c1200Hz 2 -#define R_SERIAL2_BAUD__tr_baud__c2400Hz 3 -#define R_SERIAL2_BAUD__tr_baud__c4800Hz 4 -#define R_SERIAL2_BAUD__tr_baud__c9600Hz 5 -#define R_SERIAL2_BAUD__tr_baud__c19k2Hz 6 -#define R_SERIAL2_BAUD__tr_baud__c38k4Hz 7 -#define R_SERIAL2_BAUD__tr_baud__c57k6Hz 8 -#define R_SERIAL2_BAUD__tr_baud__c115k2Hz 9 -#define R_SERIAL2_BAUD__tr_baud__c230k4Hz 10 -#define R_SERIAL2_BAUD__tr_baud__c460k8Hz 11 -#define R_SERIAL2_BAUD__tr_baud__c921k6Hz 12 -#define R_SERIAL2_BAUD__tr_baud__c1843k2Hz 13 -#define R_SERIAL2_BAUD__tr_baud__c6250kHz 14 -#define R_SERIAL2_BAUD__tr_baud__reserved 15 -#define R_SERIAL2_BAUD__rec_baud__BITNR 0 -#define R_SERIAL2_BAUD__rec_baud__WIDTH 4 -#define R_SERIAL2_BAUD__rec_baud__c300Hz 0 -#define R_SERIAL2_BAUD__rec_baud__c600Hz 1 -#define R_SERIAL2_BAUD__rec_baud__c1200Hz 2 -#define R_SERIAL2_BAUD__rec_baud__c2400Hz 3 -#define R_SERIAL2_BAUD__rec_baud__c4800Hz 4 -#define R_SERIAL2_BAUD__rec_baud__c9600Hz 5 -#define R_SERIAL2_BAUD__rec_baud__c19k2Hz 6 -#define R_SERIAL2_BAUD__rec_baud__c38k4Hz 7 -#define R_SERIAL2_BAUD__rec_baud__c57k6Hz 8 -#define R_SERIAL2_BAUD__rec_baud__c115k2Hz 9 -#define R_SERIAL2_BAUD__rec_baud__c230k4Hz 10 -#define R_SERIAL2_BAUD__rec_baud__c460k8Hz 11 -#define R_SERIAL2_BAUD__rec_baud__c921k6Hz 12 -#define R_SERIAL2_BAUD__rec_baud__c1843k2Hz 13 -#define R_SERIAL2_BAUD__rec_baud__c6250kHz 14 -#define R_SERIAL2_BAUD__rec_baud__reserved 15 - -#define R_SERIAL2_REC_CTRL (IO_TYPECAST_BYTE 0xb0000072) -#define R_SERIAL2_REC_CTRL__dma_err__BITNR 7 -#define R_SERIAL2_REC_CTRL__dma_err__WIDTH 1 -#define R_SERIAL2_REC_CTRL__dma_err__stop 0 -#define R_SERIAL2_REC_CTRL__dma_err__ignore 1 -#define R_SERIAL2_REC_CTRL__rec_enable__BITNR 6 -#define R_SERIAL2_REC_CTRL__rec_enable__WIDTH 1 -#define R_SERIAL2_REC_CTRL__rec_enable__disable 0 -#define R_SERIAL2_REC_CTRL__rec_enable__enable 1 -#define R_SERIAL2_REC_CTRL__rts___BITNR 5 -#define R_SERIAL2_REC_CTRL__rts___WIDTH 1 -#define R_SERIAL2_REC_CTRL__rts___active 0 -#define R_SERIAL2_REC_CTRL__rts___inactive 1 -#define R_SERIAL2_REC_CTRL__sampling__BITNR 4 -#define R_SERIAL2_REC_CTRL__sampling__WIDTH 1 -#define R_SERIAL2_REC_CTRL__sampling__middle 0 -#define R_SERIAL2_REC_CTRL__sampling__majority 1 -#define R_SERIAL2_REC_CTRL__rec_stick_par__BITNR 3 -#define R_SERIAL2_REC_CTRL__rec_stick_par__WIDTH 1 -#define R_SERIAL2_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL2_REC_CTRL__rec_stick_par__stick 1 -#define R_SERIAL2_REC_CTRL__rec_par__BITNR 2 -#define R_SERIAL2_REC_CTRL__rec_par__WIDTH 1 -#define R_SERIAL2_REC_CTRL__rec_par__even 0 -#define R_SERIAL2_REC_CTRL__rec_par__odd 1 -#define R_SERIAL2_REC_CTRL__rec_par_en__BITNR 1 -#define R_SERIAL2_REC_CTRL__rec_par_en__WIDTH 1 -#define R_SERIAL2_REC_CTRL__rec_par_en__disable 0 -#define R_SERIAL2_REC_CTRL__rec_par_en__enable 1 -#define R_SERIAL2_REC_CTRL__rec_bitnr__BITNR 0 -#define R_SERIAL2_REC_CTRL__rec_bitnr__WIDTH 1 -#define R_SERIAL2_REC_CTRL__rec_bitnr__rec_8bit 0 -#define R_SERIAL2_REC_CTRL__rec_bitnr__rec_7bit 1 - -#define R_SERIAL2_TR_CTRL (IO_TYPECAST_BYTE 0xb0000071) -#define R_SERIAL2_TR_CTRL__txd__BITNR 7 -#define R_SERIAL2_TR_CTRL__txd__WIDTH 1 -#define R_SERIAL2_TR_CTRL__tr_enable__BITNR 6 -#define R_SERIAL2_TR_CTRL__tr_enable__WIDTH 1 -#define R_SERIAL2_TR_CTRL__tr_enable__disable 0 -#define R_SERIAL2_TR_CTRL__tr_enable__enable 1 -#define R_SERIAL2_TR_CTRL__auto_cts__BITNR 5 -#define R_SERIAL2_TR_CTRL__auto_cts__WIDTH 1 -#define R_SERIAL2_TR_CTRL__auto_cts__disabled 0 -#define R_SERIAL2_TR_CTRL__auto_cts__active 1 -#define R_SERIAL2_TR_CTRL__stop_bits__BITNR 4 -#define R_SERIAL2_TR_CTRL__stop_bits__WIDTH 1 -#define R_SERIAL2_TR_CTRL__stop_bits__one_bit 0 -#define R_SERIAL2_TR_CTRL__stop_bits__two_bits 1 -#define R_SERIAL2_TR_CTRL__tr_stick_par__BITNR 3 -#define R_SERIAL2_TR_CTRL__tr_stick_par__WIDTH 1 -#define R_SERIAL2_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL2_TR_CTRL__tr_stick_par__stick 1 -#define R_SERIAL2_TR_CTRL__tr_par__BITNR 2 -#define R_SERIAL2_TR_CTRL__tr_par__WIDTH 1 -#define R_SERIAL2_TR_CTRL__tr_par__even 0 -#define R_SERIAL2_TR_CTRL__tr_par__odd 1 -#define R_SERIAL2_TR_CTRL__tr_par_en__BITNR 1 -#define R_SERIAL2_TR_CTRL__tr_par_en__WIDTH 1 -#define R_SERIAL2_TR_CTRL__tr_par_en__disable 0 -#define R_SERIAL2_TR_CTRL__tr_par_en__enable 1 -#define R_SERIAL2_TR_CTRL__tr_bitnr__BITNR 0 -#define R_SERIAL2_TR_CTRL__tr_bitnr__WIDTH 1 -#define R_SERIAL2_TR_CTRL__tr_bitnr__tr_8bit 0 -#define R_SERIAL2_TR_CTRL__tr_bitnr__tr_7bit 1 - -#define R_SERIAL2_TR_DATA (IO_TYPECAST_BYTE 0xb0000070) -#define R_SERIAL2_TR_DATA__data_out__BITNR 0 -#define R_SERIAL2_TR_DATA__data_out__WIDTH 8 - -#define R_SERIAL2_READ (IO_TYPECAST_RO_UDWORD 0xb0000070) -#define R_SERIAL2_READ__xoff_detect__BITNR 15 -#define R_SERIAL2_READ__xoff_detect__WIDTH 1 -#define R_SERIAL2_READ__xoff_detect__no_xoff 0 -#define R_SERIAL2_READ__xoff_detect__xoff 1 -#define R_SERIAL2_READ__cts___BITNR 14 -#define R_SERIAL2_READ__cts___WIDTH 1 -#define R_SERIAL2_READ__cts___active 0 -#define R_SERIAL2_READ__cts___inactive 1 -#define R_SERIAL2_READ__tr_ready__BITNR 13 -#define R_SERIAL2_READ__tr_ready__WIDTH 1 -#define R_SERIAL2_READ__tr_ready__full 0 -#define R_SERIAL2_READ__tr_ready__ready 1 -#define R_SERIAL2_READ__rxd__BITNR 12 -#define R_SERIAL2_READ__rxd__WIDTH 1 -#define R_SERIAL2_READ__overrun__BITNR 11 -#define R_SERIAL2_READ__overrun__WIDTH 1 -#define R_SERIAL2_READ__overrun__no 0 -#define R_SERIAL2_READ__overrun__yes 1 -#define R_SERIAL2_READ__par_err__BITNR 10 -#define R_SERIAL2_READ__par_err__WIDTH 1 -#define R_SERIAL2_READ__par_err__no 0 -#define R_SERIAL2_READ__par_err__yes 1 -#define R_SERIAL2_READ__framing_err__BITNR 9 -#define R_SERIAL2_READ__framing_err__WIDTH 1 -#define R_SERIAL2_READ__framing_err__no 0 -#define R_SERIAL2_READ__framing_err__yes 1 -#define R_SERIAL2_READ__data_avail__BITNR 8 -#define R_SERIAL2_READ__data_avail__WIDTH 1 -#define R_SERIAL2_READ__data_avail__no 0 -#define R_SERIAL2_READ__data_avail__yes 1 -#define R_SERIAL2_READ__data_in__BITNR 0 -#define R_SERIAL2_READ__data_in__WIDTH 8 - -#define R_SERIAL2_STATUS (IO_TYPECAST_RO_BYTE 0xb0000071) -#define R_SERIAL2_STATUS__xoff_detect__BITNR 7 -#define R_SERIAL2_STATUS__xoff_detect__WIDTH 1 -#define R_SERIAL2_STATUS__xoff_detect__no_xoff 0 -#define R_SERIAL2_STATUS__xoff_detect__xoff 1 -#define R_SERIAL2_STATUS__cts___BITNR 6 -#define R_SERIAL2_STATUS__cts___WIDTH 1 -#define R_SERIAL2_STATUS__cts___active 0 -#define R_SERIAL2_STATUS__cts___inactive 1 -#define R_SERIAL2_STATUS__tr_ready__BITNR 5 -#define R_SERIAL2_STATUS__tr_ready__WIDTH 1 -#define R_SERIAL2_STATUS__tr_ready__full 0 -#define R_SERIAL2_STATUS__tr_ready__ready 1 -#define R_SERIAL2_STATUS__rxd__BITNR 4 -#define R_SERIAL2_STATUS__rxd__WIDTH 1 -#define R_SERIAL2_STATUS__overrun__BITNR 3 -#define R_SERIAL2_STATUS__overrun__WIDTH 1 -#define R_SERIAL2_STATUS__overrun__no 0 -#define R_SERIAL2_STATUS__overrun__yes 1 -#define R_SERIAL2_STATUS__par_err__BITNR 2 -#define R_SERIAL2_STATUS__par_err__WIDTH 1 -#define R_SERIAL2_STATUS__par_err__no 0 -#define R_SERIAL2_STATUS__par_err__yes 1 -#define R_SERIAL2_STATUS__framing_err__BITNR 1 -#define R_SERIAL2_STATUS__framing_err__WIDTH 1 -#define R_SERIAL2_STATUS__framing_err__no 0 -#define R_SERIAL2_STATUS__framing_err__yes 1 -#define R_SERIAL2_STATUS__data_avail__BITNR 0 -#define R_SERIAL2_STATUS__data_avail__WIDTH 1 -#define R_SERIAL2_STATUS__data_avail__no 0 -#define R_SERIAL2_STATUS__data_avail__yes 1 - -#define R_SERIAL2_REC_DATA (IO_TYPECAST_RO_BYTE 0xb0000070) -#define R_SERIAL2_REC_DATA__data_in__BITNR 0 -#define R_SERIAL2_REC_DATA__data_in__WIDTH 8 - -#define R_SERIAL2_XOFF (IO_TYPECAST_UDWORD 0xb0000074) -#define R_SERIAL2_XOFF__tx_stop__BITNR 9 -#define R_SERIAL2_XOFF__tx_stop__WIDTH 1 -#define R_SERIAL2_XOFF__tx_stop__enable 0 -#define R_SERIAL2_XOFF__tx_stop__stop 1 -#define R_SERIAL2_XOFF__auto_xoff__BITNR 8 -#define R_SERIAL2_XOFF__auto_xoff__WIDTH 1 -#define R_SERIAL2_XOFF__auto_xoff__disable 0 -#define R_SERIAL2_XOFF__auto_xoff__enable 1 -#define R_SERIAL2_XOFF__xoff_char__BITNR 0 -#define R_SERIAL2_XOFF__xoff_char__WIDTH 8 - -#define R_SERIAL3_CTRL (IO_TYPECAST_UDWORD 0xb0000078) -#define R_SERIAL3_CTRL__tr_baud__BITNR 28 -#define R_SERIAL3_CTRL__tr_baud__WIDTH 4 -#define R_SERIAL3_CTRL__tr_baud__c300Hz 0 -#define R_SERIAL3_CTRL__tr_baud__c600Hz 1 -#define R_SERIAL3_CTRL__tr_baud__c1200Hz 2 -#define R_SERIAL3_CTRL__tr_baud__c2400Hz 3 -#define R_SERIAL3_CTRL__tr_baud__c4800Hz 4 -#define R_SERIAL3_CTRL__tr_baud__c9600Hz 5 -#define R_SERIAL3_CTRL__tr_baud__c19k2Hz 6 -#define R_SERIAL3_CTRL__tr_baud__c38k4Hz 7 -#define R_SERIAL3_CTRL__tr_baud__c57k6Hz 8 -#define R_SERIAL3_CTRL__tr_baud__c115k2Hz 9 -#define R_SERIAL3_CTRL__tr_baud__c230k4Hz 10 -#define R_SERIAL3_CTRL__tr_baud__c460k8Hz 11 -#define R_SERIAL3_CTRL__tr_baud__c921k6Hz 12 -#define R_SERIAL3_CTRL__tr_baud__c1843k2Hz 13 -#define R_SERIAL3_CTRL__tr_baud__c6250kHz 14 -#define R_SERIAL3_CTRL__tr_baud__reserved 15 -#define R_SERIAL3_CTRL__rec_baud__BITNR 24 -#define R_SERIAL3_CTRL__rec_baud__WIDTH 4 -#define R_SERIAL3_CTRL__rec_baud__c300Hz 0 -#define R_SERIAL3_CTRL__rec_baud__c600Hz 1 -#define R_SERIAL3_CTRL__rec_baud__c1200Hz 2 -#define R_SERIAL3_CTRL__rec_baud__c2400Hz 3 -#define R_SERIAL3_CTRL__rec_baud__c4800Hz 4 -#define R_SERIAL3_CTRL__rec_baud__c9600Hz 5 -#define R_SERIAL3_CTRL__rec_baud__c19k2Hz 6 -#define R_SERIAL3_CTRL__rec_baud__c38k4Hz 7 -#define R_SERIAL3_CTRL__rec_baud__c57k6Hz 8 -#define R_SERIAL3_CTRL__rec_baud__c115k2Hz 9 -#define R_SERIAL3_CTRL__rec_baud__c230k4Hz 10 -#define R_SERIAL3_CTRL__rec_baud__c460k8Hz 11 -#define R_SERIAL3_CTRL__rec_baud__c921k6Hz 12 -#define R_SERIAL3_CTRL__rec_baud__c1843k2Hz 13 -#define R_SERIAL3_CTRL__rec_baud__c6250kHz 14 -#define R_SERIAL3_CTRL__rec_baud__reserved 15 -#define R_SERIAL3_CTRL__dma_err__BITNR 23 -#define R_SERIAL3_CTRL__dma_err__WIDTH 1 -#define R_SERIAL3_CTRL__dma_err__stop 0 -#define R_SERIAL3_CTRL__dma_err__ignore 1 -#define R_SERIAL3_CTRL__rec_enable__BITNR 22 -#define R_SERIAL3_CTRL__rec_enable__WIDTH 1 -#define R_SERIAL3_CTRL__rec_enable__disable 0 -#define R_SERIAL3_CTRL__rec_enable__enable 1 -#define R_SERIAL3_CTRL__rts___BITNR 21 -#define R_SERIAL3_CTRL__rts___WIDTH 1 -#define R_SERIAL3_CTRL__rts___active 0 -#define R_SERIAL3_CTRL__rts___inactive 1 -#define R_SERIAL3_CTRL__sampling__BITNR 20 -#define R_SERIAL3_CTRL__sampling__WIDTH 1 -#define R_SERIAL3_CTRL__sampling__middle 0 -#define R_SERIAL3_CTRL__sampling__majority 1 -#define R_SERIAL3_CTRL__rec_stick_par__BITNR 19 -#define R_SERIAL3_CTRL__rec_stick_par__WIDTH 1 -#define R_SERIAL3_CTRL__rec_stick_par__normal 0 -#define R_SERIAL3_CTRL__rec_stick_par__stick 1 -#define R_SERIAL3_CTRL__rec_par__BITNR 18 -#define R_SERIAL3_CTRL__rec_par__WIDTH 1 -#define R_SERIAL3_CTRL__rec_par__even 0 -#define R_SERIAL3_CTRL__rec_par__odd 1 -#define R_SERIAL3_CTRL__rec_par_en__BITNR 17 -#define R_SERIAL3_CTRL__rec_par_en__WIDTH 1 -#define R_SERIAL3_CTRL__rec_par_en__disable 0 -#define R_SERIAL3_CTRL__rec_par_en__enable 1 -#define R_SERIAL3_CTRL__rec_bitnr__BITNR 16 -#define R_SERIAL3_CTRL__rec_bitnr__WIDTH 1 -#define R_SERIAL3_CTRL__rec_bitnr__rec_8bit 0 -#define R_SERIAL3_CTRL__rec_bitnr__rec_7bit 1 -#define R_SERIAL3_CTRL__txd__BITNR 15 -#define R_SERIAL3_CTRL__txd__WIDTH 1 -#define R_SERIAL3_CTRL__tr_enable__BITNR 14 -#define R_SERIAL3_CTRL__tr_enable__WIDTH 1 -#define R_SERIAL3_CTRL__tr_enable__disable 0 -#define R_SERIAL3_CTRL__tr_enable__enable 1 -#define R_SERIAL3_CTRL__auto_cts__BITNR 13 -#define R_SERIAL3_CTRL__auto_cts__WIDTH 1 -#define R_SERIAL3_CTRL__auto_cts__disabled 0 -#define R_SERIAL3_CTRL__auto_cts__active 1 -#define R_SERIAL3_CTRL__stop_bits__BITNR 12 -#define R_SERIAL3_CTRL__stop_bits__WIDTH 1 -#define R_SERIAL3_CTRL__stop_bits__one_bit 0 -#define R_SERIAL3_CTRL__stop_bits__two_bits 1 -#define R_SERIAL3_CTRL__tr_stick_par__BITNR 11 -#define R_SERIAL3_CTRL__tr_stick_par__WIDTH 1 -#define R_SERIAL3_CTRL__tr_stick_par__normal 0 -#define R_SERIAL3_CTRL__tr_stick_par__stick 1 -#define R_SERIAL3_CTRL__tr_par__BITNR 10 -#define R_SERIAL3_CTRL__tr_par__WIDTH 1 -#define R_SERIAL3_CTRL__tr_par__even 0 -#define R_SERIAL3_CTRL__tr_par__odd 1 -#define R_SERIAL3_CTRL__tr_par_en__BITNR 9 -#define R_SERIAL3_CTRL__tr_par_en__WIDTH 1 -#define R_SERIAL3_CTRL__tr_par_en__disable 0 -#define R_SERIAL3_CTRL__tr_par_en__enable 1 -#define R_SERIAL3_CTRL__tr_bitnr__BITNR 8 -#define R_SERIAL3_CTRL__tr_bitnr__WIDTH 1 -#define R_SERIAL3_CTRL__tr_bitnr__tr_8bit 0 -#define R_SERIAL3_CTRL__tr_bitnr__tr_7bit 1 -#define R_SERIAL3_CTRL__data_out__BITNR 0 -#define R_SERIAL3_CTRL__data_out__WIDTH 8 - -#define R_SERIAL3_BAUD (IO_TYPECAST_BYTE 0xb000007b) -#define R_SERIAL3_BAUD__tr_baud__BITNR 4 -#define R_SERIAL3_BAUD__tr_baud__WIDTH 4 -#define R_SERIAL3_BAUD__tr_baud__c300Hz 0 -#define R_SERIAL3_BAUD__tr_baud__c600Hz 1 -#define R_SERIAL3_BAUD__tr_baud__c1200Hz 2 -#define R_SERIAL3_BAUD__tr_baud__c2400Hz 3 -#define R_SERIAL3_BAUD__tr_baud__c4800Hz 4 -#define R_SERIAL3_BAUD__tr_baud__c9600Hz 5 -#define R_SERIAL3_BAUD__tr_baud__c19k2Hz 6 -#define R_SERIAL3_BAUD__tr_baud__c38k4Hz 7 -#define R_SERIAL3_BAUD__tr_baud__c57k6Hz 8 -#define R_SERIAL3_BAUD__tr_baud__c115k2Hz 9 -#define R_SERIAL3_BAUD__tr_baud__c230k4Hz 10 -#define R_SERIAL3_BAUD__tr_baud__c460k8Hz 11 -#define R_SERIAL3_BAUD__tr_baud__c921k6Hz 12 -#define R_SERIAL3_BAUD__tr_baud__c1843k2Hz 13 -#define R_SERIAL3_BAUD__tr_baud__c6250kHz 14 -#define R_SERIAL3_BAUD__tr_baud__reserved 15 -#define R_SERIAL3_BAUD__rec_baud__BITNR 0 -#define R_SERIAL3_BAUD__rec_baud__WIDTH 4 -#define R_SERIAL3_BAUD__rec_baud__c300Hz 0 -#define R_SERIAL3_BAUD__rec_baud__c600Hz 1 -#define R_SERIAL3_BAUD__rec_baud__c1200Hz 2 -#define R_SERIAL3_BAUD__rec_baud__c2400Hz 3 -#define R_SERIAL3_BAUD__rec_baud__c4800Hz 4 -#define R_SERIAL3_BAUD__rec_baud__c9600Hz 5 -#define R_SERIAL3_BAUD__rec_baud__c19k2Hz 6 -#define R_SERIAL3_BAUD__rec_baud__c38k4Hz 7 -#define R_SERIAL3_BAUD__rec_baud__c57k6Hz 8 -#define R_SERIAL3_BAUD__rec_baud__c115k2Hz 9 -#define R_SERIAL3_BAUD__rec_baud__c230k4Hz 10 -#define R_SERIAL3_BAUD__rec_baud__c460k8Hz 11 -#define R_SERIAL3_BAUD__rec_baud__c921k6Hz 12 -#define R_SERIAL3_BAUD__rec_baud__c1843k2Hz 13 -#define R_SERIAL3_BAUD__rec_baud__c6250kHz 14 -#define R_SERIAL3_BAUD__rec_baud__reserved 15 - -#define R_SERIAL3_REC_CTRL (IO_TYPECAST_BYTE 0xb000007a) -#define R_SERIAL3_REC_CTRL__dma_err__BITNR 7 -#define R_SERIAL3_REC_CTRL__dma_err__WIDTH 1 -#define R_SERIAL3_REC_CTRL__dma_err__stop 0 -#define R_SERIAL3_REC_CTRL__dma_err__ignore 1 -#define R_SERIAL3_REC_CTRL__rec_enable__BITNR 6 -#define R_SERIAL3_REC_CTRL__rec_enable__WIDTH 1 -#define R_SERIAL3_REC_CTRL__rec_enable__disable 0 -#define R_SERIAL3_REC_CTRL__rec_enable__enable 1 -#define R_SERIAL3_REC_CTRL__rts___BITNR 5 -#define R_SERIAL3_REC_CTRL__rts___WIDTH 1 -#define R_SERIAL3_REC_CTRL__rts___active 0 -#define R_SERIAL3_REC_CTRL__rts___inactive 1 -#define R_SERIAL3_REC_CTRL__sampling__BITNR 4 -#define R_SERIAL3_REC_CTRL__sampling__WIDTH 1 -#define R_SERIAL3_REC_CTRL__sampling__middle 0 -#define R_SERIAL3_REC_CTRL__sampling__majority 1 -#define R_SERIAL3_REC_CTRL__rec_stick_par__BITNR 3 -#define R_SERIAL3_REC_CTRL__rec_stick_par__WIDTH 1 -#define R_SERIAL3_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL3_REC_CTRL__rec_stick_par__stick 1 -#define R_SERIAL3_REC_CTRL__rec_par__BITNR 2 -#define R_SERIAL3_REC_CTRL__rec_par__WIDTH 1 -#define R_SERIAL3_REC_CTRL__rec_par__even 0 -#define R_SERIAL3_REC_CTRL__rec_par__odd 1 -#define R_SERIAL3_REC_CTRL__rec_par_en__BITNR 1 -#define R_SERIAL3_REC_CTRL__rec_par_en__WIDTH 1 -#define R_SERIAL3_REC_CTRL__rec_par_en__disable 0 -#define R_SERIAL3_REC_CTRL__rec_par_en__enable 1 -#define R_SERIAL3_REC_CTRL__rec_bitnr__BITNR 0 -#define R_SERIAL3_REC_CTRL__rec_bitnr__WIDTH 1 -#define R_SERIAL3_REC_CTRL__rec_bitnr__rec_8bit 0 -#define R_SERIAL3_REC_CTRL__rec_bitnr__rec_7bit 1 - -#define R_SERIAL3_TR_CTRL (IO_TYPECAST_BYTE 0xb0000079) -#define R_SERIAL3_TR_CTRL__txd__BITNR 7 -#define R_SERIAL3_TR_CTRL__txd__WIDTH 1 -#define R_SERIAL3_TR_CTRL__tr_enable__BITNR 6 -#define R_SERIAL3_TR_CTRL__tr_enable__WIDTH 1 -#define R_SERIAL3_TR_CTRL__tr_enable__disable 0 -#define R_SERIAL3_TR_CTRL__tr_enable__enable 1 -#define R_SERIAL3_TR_CTRL__auto_cts__BITNR 5 -#define R_SERIAL3_TR_CTRL__auto_cts__WIDTH 1 -#define R_SERIAL3_TR_CTRL__auto_cts__disabled 0 -#define R_SERIAL3_TR_CTRL__auto_cts__active 1 -#define R_SERIAL3_TR_CTRL__stop_bits__BITNR 4 -#define R_SERIAL3_TR_CTRL__stop_bits__WIDTH 1 -#define R_SERIAL3_TR_CTRL__stop_bits__one_bit 0 -#define R_SERIAL3_TR_CTRL__stop_bits__two_bits 1 -#define R_SERIAL3_TR_CTRL__tr_stick_par__BITNR 3 -#define R_SERIAL3_TR_CTRL__tr_stick_par__WIDTH 1 -#define R_SERIAL3_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL3_TR_CTRL__tr_stick_par__stick 1 -#define R_SERIAL3_TR_CTRL__tr_par__BITNR 2 -#define R_SERIAL3_TR_CTRL__tr_par__WIDTH 1 -#define R_SERIAL3_TR_CTRL__tr_par__even 0 -#define R_SERIAL3_TR_CTRL__tr_par__odd 1 -#define R_SERIAL3_TR_CTRL__tr_par_en__BITNR 1 -#define R_SERIAL3_TR_CTRL__tr_par_en__WIDTH 1 -#define R_SERIAL3_TR_CTRL__tr_par_en__disable 0 -#define R_SERIAL3_TR_CTRL__tr_par_en__enable 1 -#define R_SERIAL3_TR_CTRL__tr_bitnr__BITNR 0 -#define R_SERIAL3_TR_CTRL__tr_bitnr__WIDTH 1 -#define R_SERIAL3_TR_CTRL__tr_bitnr__tr_8bit 0 -#define R_SERIAL3_TR_CTRL__tr_bitnr__tr_7bit 1 - -#define R_SERIAL3_TR_DATA (IO_TYPECAST_BYTE 0xb0000078) -#define R_SERIAL3_TR_DATA__data_out__BITNR 0 -#define R_SERIAL3_TR_DATA__data_out__WIDTH 8 - -#define R_SERIAL3_READ (IO_TYPECAST_RO_UDWORD 0xb0000078) -#define R_SERIAL3_READ__xoff_detect__BITNR 15 -#define R_SERIAL3_READ__xoff_detect__WIDTH 1 -#define R_SERIAL3_READ__xoff_detect__no_xoff 0 -#define R_SERIAL3_READ__xoff_detect__xoff 1 -#define R_SERIAL3_READ__cts___BITNR 14 -#define R_SERIAL3_READ__cts___WIDTH 1 -#define R_SERIAL3_READ__cts___active 0 -#define R_SERIAL3_READ__cts___inactive 1 -#define R_SERIAL3_READ__tr_ready__BITNR 13 -#define R_SERIAL3_READ__tr_ready__WIDTH 1 -#define R_SERIAL3_READ__tr_ready__full 0 -#define R_SERIAL3_READ__tr_ready__ready 1 -#define R_SERIAL3_READ__rxd__BITNR 12 -#define R_SERIAL3_READ__rxd__WIDTH 1 -#define R_SERIAL3_READ__overrun__BITNR 11 -#define R_SERIAL3_READ__overrun__WIDTH 1 -#define R_SERIAL3_READ__overrun__no 0 -#define R_SERIAL3_READ__overrun__yes 1 -#define R_SERIAL3_READ__par_err__BITNR 10 -#define R_SERIAL3_READ__par_err__WIDTH 1 -#define R_SERIAL3_READ__par_err__no 0 -#define R_SERIAL3_READ__par_err__yes 1 -#define R_SERIAL3_READ__framing_err__BITNR 9 -#define R_SERIAL3_READ__framing_err__WIDTH 1 -#define R_SERIAL3_READ__framing_err__no 0 -#define R_SERIAL3_READ__framing_err__yes 1 -#define R_SERIAL3_READ__data_avail__BITNR 8 -#define R_SERIAL3_READ__data_avail__WIDTH 1 -#define R_SERIAL3_READ__data_avail__no 0 -#define R_SERIAL3_READ__data_avail__yes 1 -#define R_SERIAL3_READ__data_in__BITNR 0 -#define R_SERIAL3_READ__data_in__WIDTH 8 - -#define R_SERIAL3_STATUS (IO_TYPECAST_RO_BYTE 0xb0000079) -#define R_SERIAL3_STATUS__xoff_detect__BITNR 7 -#define R_SERIAL3_STATUS__xoff_detect__WIDTH 1 -#define R_SERIAL3_STATUS__xoff_detect__no_xoff 0 -#define R_SERIAL3_STATUS__xoff_detect__xoff 1 -#define R_SERIAL3_STATUS__cts___BITNR 6 -#define R_SERIAL3_STATUS__cts___WIDTH 1 -#define R_SERIAL3_STATUS__cts___active 0 -#define R_SERIAL3_STATUS__cts___inactive 1 -#define R_SERIAL3_STATUS__tr_ready__BITNR 5 -#define R_SERIAL3_STATUS__tr_ready__WIDTH 1 -#define R_SERIAL3_STATUS__tr_ready__full 0 -#define R_SERIAL3_STATUS__tr_ready__ready 1 -#define R_SERIAL3_STATUS__rxd__BITNR 4 -#define R_SERIAL3_STATUS__rxd__WIDTH 1 -#define R_SERIAL3_STATUS__overrun__BITNR 3 -#define R_SERIAL3_STATUS__overrun__WIDTH 1 -#define R_SERIAL3_STATUS__overrun__no 0 -#define R_SERIAL3_STATUS__overrun__yes 1 -#define R_SERIAL3_STATUS__par_err__BITNR 2 -#define R_SERIAL3_STATUS__par_err__WIDTH 1 -#define R_SERIAL3_STATUS__par_err__no 0 -#define R_SERIAL3_STATUS__par_err__yes 1 -#define R_SERIAL3_STATUS__framing_err__BITNR 1 -#define R_SERIAL3_STATUS__framing_err__WIDTH 1 -#define R_SERIAL3_STATUS__framing_err__no 0 -#define R_SERIAL3_STATUS__framing_err__yes 1 -#define R_SERIAL3_STATUS__data_avail__BITNR 0 -#define R_SERIAL3_STATUS__data_avail__WIDTH 1 -#define R_SERIAL3_STATUS__data_avail__no 0 -#define R_SERIAL3_STATUS__data_avail__yes 1 - -#define R_SERIAL3_REC_DATA (IO_TYPECAST_RO_BYTE 0xb0000078) -#define R_SERIAL3_REC_DATA__data_in__BITNR 0 -#define R_SERIAL3_REC_DATA__data_in__WIDTH 8 - -#define R_SERIAL3_XOFF (IO_TYPECAST_UDWORD 0xb000007c) -#define R_SERIAL3_XOFF__tx_stop__BITNR 9 -#define R_SERIAL3_XOFF__tx_stop__WIDTH 1 -#define R_SERIAL3_XOFF__tx_stop__enable 0 -#define R_SERIAL3_XOFF__tx_stop__stop 1 -#define R_SERIAL3_XOFF__auto_xoff__BITNR 8 -#define R_SERIAL3_XOFF__auto_xoff__WIDTH 1 -#define R_SERIAL3_XOFF__auto_xoff__disable 0 -#define R_SERIAL3_XOFF__auto_xoff__enable 1 -#define R_SERIAL3_XOFF__xoff_char__BITNR 0 -#define R_SERIAL3_XOFF__xoff_char__WIDTH 8 - -#define R_ALT_SER_BAUDRATE (IO_TYPECAST_UDWORD 0xb000005c) -#define R_ALT_SER_BAUDRATE__ser3_tr__BITNR 28 -#define R_ALT_SER_BAUDRATE__ser3_tr__WIDTH 2 -#define R_ALT_SER_BAUDRATE__ser3_tr__normal 0 -#define R_ALT_SER_BAUDRATE__ser3_tr__prescale 1 -#define R_ALT_SER_BAUDRATE__ser3_tr__extern 2 -#define R_ALT_SER_BAUDRATE__ser3_tr__timer 3 -#define R_ALT_SER_BAUDRATE__ser3_rec__BITNR 24 -#define R_ALT_SER_BAUDRATE__ser3_rec__WIDTH 2 -#define R_ALT_SER_BAUDRATE__ser3_rec__normal 0 -#define R_ALT_SER_BAUDRATE__ser3_rec__prescale 1 -#define R_ALT_SER_BAUDRATE__ser3_rec__extern 2 -#define R_ALT_SER_BAUDRATE__ser3_rec__timer 3 -#define R_ALT_SER_BAUDRATE__ser2_tr__BITNR 20 -#define R_ALT_SER_BAUDRATE__ser2_tr__WIDTH 2 -#define R_ALT_SER_BAUDRATE__ser2_tr__normal 0 -#define R_ALT_SER_BAUDRATE__ser2_tr__prescale 1 -#define R_ALT_SER_BAUDRATE__ser2_tr__extern 2 -#define R_ALT_SER_BAUDRATE__ser2_tr__timer 3 -#define R_ALT_SER_BAUDRATE__ser2_rec__BITNR 16 -#define R_ALT_SER_BAUDRATE__ser2_rec__WIDTH 2 -#define R_ALT_SER_BAUDRATE__ser2_rec__normal 0 -#define R_ALT_SER_BAUDRATE__ser2_rec__prescale 1 -#define R_ALT_SER_BAUDRATE__ser2_rec__extern 2 -#define R_ALT_SER_BAUDRATE__ser2_rec__timer 3 -#define R_ALT_SER_BAUDRATE__ser1_tr__BITNR 12 -#define R_ALT_SER_BAUDRATE__ser1_tr__WIDTH 2 -#define R_ALT_SER_BAUDRATE__ser1_tr__normal 0 -#define R_ALT_SER_BAUDRATE__ser1_tr__prescale 1 -#define R_ALT_SER_BAUDRATE__ser1_tr__extern 2 -#define R_ALT_SER_BAUDRATE__ser1_tr__timer 3 -#define R_ALT_SER_BAUDRATE__ser1_rec__BITNR 8 -#define R_ALT_SER_BAUDRATE__ser1_rec__WIDTH 2 -#define R_ALT_SER_BAUDRATE__ser1_rec__normal 0 -#define R_ALT_SER_BAUDRATE__ser1_rec__prescale 1 -#define R_ALT_SER_BAUDRATE__ser1_rec__extern 2 -#define R_ALT_SER_BAUDRATE__ser1_rec__timer 3 -#define R_ALT_SER_BAUDRATE__ser0_tr__BITNR 4 -#define R_ALT_SER_BAUDRATE__ser0_tr__WIDTH 2 -#define R_ALT_SER_BAUDRATE__ser0_tr__normal 0 -#define R_ALT_SER_BAUDRATE__ser0_tr__prescale 1 -#define R_ALT_SER_BAUDRATE__ser0_tr__extern 2 -#define R_ALT_SER_BAUDRATE__ser0_tr__timer 3 -#define R_ALT_SER_BAUDRATE__ser0_rec__BITNR 0 -#define R_ALT_SER_BAUDRATE__ser0_rec__WIDTH 2 -#define R_ALT_SER_BAUDRATE__ser0_rec__normal 0 -#define R_ALT_SER_BAUDRATE__ser0_rec__prescale 1 -#define R_ALT_SER_BAUDRATE__ser0_rec__extern 2 -#define R_ALT_SER_BAUDRATE__ser0_rec__timer 3 - -/* -!* Network interface registers -!*/ - -#define R_NETWORK_SA_0 (IO_TYPECAST_UDWORD 0xb0000080) -#define R_NETWORK_SA_0__ma0_low__BITNR 0 -#define R_NETWORK_SA_0__ma0_low__WIDTH 32 - -#define R_NETWORK_SA_1 (IO_TYPECAST_UDWORD 0xb0000084) -#define R_NETWORK_SA_1__ma1_low__BITNR 16 -#define R_NETWORK_SA_1__ma1_low__WIDTH 16 -#define R_NETWORK_SA_1__ma0_high__BITNR 0 -#define R_NETWORK_SA_1__ma0_high__WIDTH 16 - -#define R_NETWORK_SA_2 (IO_TYPECAST_UDWORD 0xb0000088) -#define R_NETWORK_SA_2__ma1_high__BITNR 0 -#define R_NETWORK_SA_2__ma1_high__WIDTH 32 - -#define R_NETWORK_GA_0 (IO_TYPECAST_UDWORD 0xb000008c) -#define R_NETWORK_GA_0__ga_low__BITNR 0 -#define R_NETWORK_GA_0__ga_low__WIDTH 32 - -#define R_NETWORK_GA_1 (IO_TYPECAST_UDWORD 0xb0000090) -#define R_NETWORK_GA_1__ga_high__BITNR 0 -#define R_NETWORK_GA_1__ga_high__WIDTH 32 - -#define R_NETWORK_REC_CONFIG (IO_TYPECAST_UDWORD 0xb0000094) -#define R_NETWORK_REC_CONFIG__max_size__BITNR 10 -#define R_NETWORK_REC_CONFIG__max_size__WIDTH 1 -#define R_NETWORK_REC_CONFIG__max_size__size1518 0 -#define R_NETWORK_REC_CONFIG__max_size__size1522 1 -#define R_NETWORK_REC_CONFIG__duplex__BITNR 9 -#define R_NETWORK_REC_CONFIG__duplex__WIDTH 1 -#define R_NETWORK_REC_CONFIG__duplex__full 1 -#define R_NETWORK_REC_CONFIG__duplex__half 0 -#define R_NETWORK_REC_CONFIG__bad_crc__BITNR 8 -#define R_NETWORK_REC_CONFIG__bad_crc__WIDTH 1 -#define R_NETWORK_REC_CONFIG__bad_crc__receive 1 -#define R_NETWORK_REC_CONFIG__bad_crc__discard 0 -#define R_NETWORK_REC_CONFIG__oversize__BITNR 7 -#define R_NETWORK_REC_CONFIG__oversize__WIDTH 1 -#define R_NETWORK_REC_CONFIG__oversize__receive 1 -#define R_NETWORK_REC_CONFIG__oversize__discard 0 -#define R_NETWORK_REC_CONFIG__undersize__BITNR 6 -#define R_NETWORK_REC_CONFIG__undersize__WIDTH 1 -#define R_NETWORK_REC_CONFIG__undersize__receive 1 -#define R_NETWORK_REC_CONFIG__undersize__discard 0 -#define R_NETWORK_REC_CONFIG__all_roots__BITNR 5 -#define R_NETWORK_REC_CONFIG__all_roots__WIDTH 1 -#define R_NETWORK_REC_CONFIG__all_roots__receive 1 -#define R_NETWORK_REC_CONFIG__all_roots__discard 0 -#define R_NETWORK_REC_CONFIG__tr_broadcast__BITNR 4 -#define R_NETWORK_REC_CONFIG__tr_broadcast__WIDTH 1 -#define R_NETWORK_REC_CONFIG__tr_broadcast__receive 1 -#define R_NETWORK_REC_CONFIG__tr_broadcast__discard 0 -#define R_NETWORK_REC_CONFIG__broadcast__BITNR 3 -#define R_NETWORK_REC_CONFIG__broadcast__WIDTH 1 -#define R_NETWORK_REC_CONFIG__broadcast__receive 1 -#define R_NETWORK_REC_CONFIG__broadcast__discard 0 -#define R_NETWORK_REC_CONFIG__individual__BITNR 2 -#define R_NETWORK_REC_CONFIG__individual__WIDTH 1 -#define R_NETWORK_REC_CONFIG__individual__receive 1 -#define R_NETWORK_REC_CONFIG__individual__discard 0 -#define R_NETWORK_REC_CONFIG__ma1__BITNR 1 -#define R_NETWORK_REC_CONFIG__ma1__WIDTH 1 -#define R_NETWORK_REC_CONFIG__ma1__enable 1 -#define R_NETWORK_REC_CONFIG__ma1__disable 0 -#define R_NETWORK_REC_CONFIG__ma0__BITNR 0 -#define R_NETWORK_REC_CONFIG__ma0__WIDTH 1 -#define R_NETWORK_REC_CONFIG__ma0__enable 1 -#define R_NETWORK_REC_CONFIG__ma0__disable 0 - -#define R_NETWORK_GEN_CONFIG (IO_TYPECAST_UDWORD 0xb0000098) -#define R_NETWORK_GEN_CONFIG__loopback__BITNR 5 -#define R_NETWORK_GEN_CONFIG__loopback__WIDTH 1 -#define R_NETWORK_GEN_CONFIG__loopback__on 1 -#define R_NETWORK_GEN_CONFIG__loopback__off 0 -#define R_NETWORK_GEN_CONFIG__frame__BITNR 4 -#define R_NETWORK_GEN_CONFIG__frame__WIDTH 1 -#define R_NETWORK_GEN_CONFIG__frame__tokenr 1 -#define R_NETWORK_GEN_CONFIG__frame__ether 0 -#define R_NETWORK_GEN_CONFIG__vg__BITNR 3 -#define R_NETWORK_GEN_CONFIG__vg__WIDTH 1 -#define R_NETWORK_GEN_CONFIG__vg__on 1 -#define R_NETWORK_GEN_CONFIG__vg__off 0 -#define R_NETWORK_GEN_CONFIG__phy__BITNR 1 -#define R_NETWORK_GEN_CONFIG__phy__WIDTH 2 -#define R_NETWORK_GEN_CONFIG__phy__sni 0 -#define R_NETWORK_GEN_CONFIG__phy__mii_clk 1 -#define R_NETWORK_GEN_CONFIG__phy__mii_err 2 -#define R_NETWORK_GEN_CONFIG__phy__mii_req 3 -#define R_NETWORK_GEN_CONFIG__enable__BITNR 0 -#define R_NETWORK_GEN_CONFIG__enable__WIDTH 1 -#define R_NETWORK_GEN_CONFIG__enable__on 1 -#define R_NETWORK_GEN_CONFIG__enable__off 0 - -#define R_NETWORK_TR_CTRL (IO_TYPECAST_UDWORD 0xb000009c) -#define R_NETWORK_TR_CTRL__clr_error__BITNR 8 -#define R_NETWORK_TR_CTRL__clr_error__WIDTH 1 -#define R_NETWORK_TR_CTRL__clr_error__clr 1 -#define R_NETWORK_TR_CTRL__clr_error__nop 0 -#define R_NETWORK_TR_CTRL__delay__BITNR 5 -#define R_NETWORK_TR_CTRL__delay__WIDTH 1 -#define R_NETWORK_TR_CTRL__delay__d2us 1 -#define R_NETWORK_TR_CTRL__delay__none 0 -#define R_NETWORK_TR_CTRL__cancel__BITNR 4 -#define R_NETWORK_TR_CTRL__cancel__WIDTH 1 -#define R_NETWORK_TR_CTRL__cancel__do 1 -#define R_NETWORK_TR_CTRL__cancel__dont 0 -#define R_NETWORK_TR_CTRL__cd__BITNR 3 -#define R_NETWORK_TR_CTRL__cd__WIDTH 1 -#define R_NETWORK_TR_CTRL__cd__enable 0 -#define R_NETWORK_TR_CTRL__cd__disable 1 -#define R_NETWORK_TR_CTRL__cd__ack_col 0 -#define R_NETWORK_TR_CTRL__cd__ack_crs 1 -#define R_NETWORK_TR_CTRL__retry__BITNR 2 -#define R_NETWORK_TR_CTRL__retry__WIDTH 1 -#define R_NETWORK_TR_CTRL__retry__enable 0 -#define R_NETWORK_TR_CTRL__retry__disable 1 -#define R_NETWORK_TR_CTRL__pad__BITNR 1 -#define R_NETWORK_TR_CTRL__pad__WIDTH 1 -#define R_NETWORK_TR_CTRL__pad__enable 1 -#define R_NETWORK_TR_CTRL__pad__disable 0 -#define R_NETWORK_TR_CTRL__crc__BITNR 0 -#define R_NETWORK_TR_CTRL__crc__WIDTH 1 -#define R_NETWORK_TR_CTRL__crc__enable 0 -#define R_NETWORK_TR_CTRL__crc__disable 1 - -#define R_NETWORK_MGM_CTRL (IO_TYPECAST_UDWORD 0xb00000a0) -#define R_NETWORK_MGM_CTRL__txd_pins__BITNR 4 -#define R_NETWORK_MGM_CTRL__txd_pins__WIDTH 4 -#define R_NETWORK_MGM_CTRL__txer_pin__BITNR 3 -#define R_NETWORK_MGM_CTRL__txer_pin__WIDTH 1 -#define R_NETWORK_MGM_CTRL__mdck__BITNR 2 -#define R_NETWORK_MGM_CTRL__mdck__WIDTH 1 -#define R_NETWORK_MGM_CTRL__mdoe__BITNR 1 -#define R_NETWORK_MGM_CTRL__mdoe__WIDTH 1 -#define R_NETWORK_MGM_CTRL__mdoe__enable 1 -#define R_NETWORK_MGM_CTRL__mdoe__disable 0 -#define R_NETWORK_MGM_CTRL__mdio__BITNR 0 -#define R_NETWORK_MGM_CTRL__mdio__WIDTH 1 - -#define R_NETWORK_STAT (IO_TYPECAST_RO_UDWORD 0xb00000a0) -#define R_NETWORK_STAT__rxd_pins__BITNR 4 -#define R_NETWORK_STAT__rxd_pins__WIDTH 4 -#define R_NETWORK_STAT__rxer__BITNR 3 -#define R_NETWORK_STAT__rxer__WIDTH 1 -#define R_NETWORK_STAT__underrun__BITNR 2 -#define R_NETWORK_STAT__underrun__WIDTH 1 -#define R_NETWORK_STAT__underrun__yes 1 -#define R_NETWORK_STAT__underrun__no 0 -#define R_NETWORK_STAT__exc_col__BITNR 1 -#define R_NETWORK_STAT__exc_col__WIDTH 1 -#define R_NETWORK_STAT__exc_col__yes 1 -#define R_NETWORK_STAT__exc_col__no 0 -#define R_NETWORK_STAT__mdio__BITNR 0 -#define R_NETWORK_STAT__mdio__WIDTH 1 - -#define R_REC_COUNTERS (IO_TYPECAST_RO_UDWORD 0xb00000a4) -#define R_REC_COUNTERS__congestion__BITNR 24 -#define R_REC_COUNTERS__congestion__WIDTH 8 -#define R_REC_COUNTERS__oversize__BITNR 16 -#define R_REC_COUNTERS__oversize__WIDTH 8 -#define R_REC_COUNTERS__alignment_error__BITNR 8 -#define R_REC_COUNTERS__alignment_error__WIDTH 8 -#define R_REC_COUNTERS__crc_error__BITNR 0 -#define R_REC_COUNTERS__crc_error__WIDTH 8 - -#define R_TR_COUNTERS (IO_TYPECAST_RO_UDWORD 0xb00000a8) -#define R_TR_COUNTERS__deferred__BITNR 24 -#define R_TR_COUNTERS__deferred__WIDTH 8 -#define R_TR_COUNTERS__late_col__BITNR 16 -#define R_TR_COUNTERS__late_col__WIDTH 8 -#define R_TR_COUNTERS__multiple_col__BITNR 8 -#define R_TR_COUNTERS__multiple_col__WIDTH 8 -#define R_TR_COUNTERS__single_col__BITNR 0 -#define R_TR_COUNTERS__single_col__WIDTH 8 - -#define R_PHY_COUNTERS (IO_TYPECAST_RO_UDWORD 0xb00000ac) -#define R_PHY_COUNTERS__sqe_test_error__BITNR 8 -#define R_PHY_COUNTERS__sqe_test_error__WIDTH 8 -#define R_PHY_COUNTERS__carrier_loss__BITNR 0 -#define R_PHY_COUNTERS__carrier_loss__WIDTH 8 - -/* -!* Parallel printer port registers -!*/ - -#define R_PAR0_CTRL_DATA (IO_TYPECAST_UDWORD 0xb0000040) -#define R_PAR0_CTRL_DATA__peri_int__BITNR 24 -#define R_PAR0_CTRL_DATA__peri_int__WIDTH 1 -#define R_PAR0_CTRL_DATA__peri_int__ack 1 -#define R_PAR0_CTRL_DATA__peri_int__nop 0 -#define R_PAR0_CTRL_DATA__oe__BITNR 20 -#define R_PAR0_CTRL_DATA__oe__WIDTH 1 -#define R_PAR0_CTRL_DATA__oe__enable 1 -#define R_PAR0_CTRL_DATA__oe__disable 0 -#define R_PAR0_CTRL_DATA__seli__BITNR 19 -#define R_PAR0_CTRL_DATA__seli__WIDTH 1 -#define R_PAR0_CTRL_DATA__seli__active 1 -#define R_PAR0_CTRL_DATA__seli__inactive 0 -#define R_PAR0_CTRL_DATA__autofd__BITNR 18 -#define R_PAR0_CTRL_DATA__autofd__WIDTH 1 -#define R_PAR0_CTRL_DATA__autofd__active 1 -#define R_PAR0_CTRL_DATA__autofd__inactive 0 -#define R_PAR0_CTRL_DATA__strb__BITNR 17 -#define R_PAR0_CTRL_DATA__strb__WIDTH 1 -#define R_PAR0_CTRL_DATA__strb__active 1 -#define R_PAR0_CTRL_DATA__strb__inactive 0 -#define R_PAR0_CTRL_DATA__init__BITNR 16 -#define R_PAR0_CTRL_DATA__init__WIDTH 1 -#define R_PAR0_CTRL_DATA__init__active 1 -#define R_PAR0_CTRL_DATA__init__inactive 0 -#define R_PAR0_CTRL_DATA__ecp_cmd__BITNR 8 -#define R_PAR0_CTRL_DATA__ecp_cmd__WIDTH 1 -#define R_PAR0_CTRL_DATA__ecp_cmd__command 1 -#define R_PAR0_CTRL_DATA__ecp_cmd__data 0 -#define R_PAR0_CTRL_DATA__data__BITNR 0 -#define R_PAR0_CTRL_DATA__data__WIDTH 8 - -#define R_PAR0_CTRL (IO_TYPECAST_BYTE 0xb0000042) -#define R_PAR0_CTRL__ctrl__BITNR 0 -#define R_PAR0_CTRL__ctrl__WIDTH 5 - -#define R_PAR0_STATUS_DATA (IO_TYPECAST_RO_UDWORD 0xb0000040) -#define R_PAR0_STATUS_DATA__mode__BITNR 29 -#define R_PAR0_STATUS_DATA__mode__WIDTH 3 -#define R_PAR0_STATUS_DATA__mode__manual 0 -#define R_PAR0_STATUS_DATA__mode__centronics 1 -#define R_PAR0_STATUS_DATA__mode__fastbyte 2 -#define R_PAR0_STATUS_DATA__mode__nibble 3 -#define R_PAR0_STATUS_DATA__mode__byte 4 -#define R_PAR0_STATUS_DATA__mode__ecp_fwd 5 -#define R_PAR0_STATUS_DATA__mode__ecp_rev 6 -#define R_PAR0_STATUS_DATA__mode__off 7 -#define R_PAR0_STATUS_DATA__mode__epp_wr1 5 -#define R_PAR0_STATUS_DATA__mode__epp_wr2 6 -#define R_PAR0_STATUS_DATA__mode__epp_wr3 7 -#define R_PAR0_STATUS_DATA__mode__epp_rd 0 -#define R_PAR0_STATUS_DATA__perr__BITNR 28 -#define R_PAR0_STATUS_DATA__perr__WIDTH 1 -#define R_PAR0_STATUS_DATA__perr__active 1 -#define R_PAR0_STATUS_DATA__perr__inactive 0 -#define R_PAR0_STATUS_DATA__ack__BITNR 27 -#define R_PAR0_STATUS_DATA__ack__WIDTH 1 -#define R_PAR0_STATUS_DATA__ack__active 0 -#define R_PAR0_STATUS_DATA__ack__inactive 1 -#define R_PAR0_STATUS_DATA__busy__BITNR 26 -#define R_PAR0_STATUS_DATA__busy__WIDTH 1 -#define R_PAR0_STATUS_DATA__busy__active 1 -#define R_PAR0_STATUS_DATA__busy__inactive 0 -#define R_PAR0_STATUS_DATA__fault__BITNR 25 -#define R_PAR0_STATUS_DATA__fault__WIDTH 1 -#define R_PAR0_STATUS_DATA__fault__active 0 -#define R_PAR0_STATUS_DATA__fault__inactive 1 -#define R_PAR0_STATUS_DATA__sel__BITNR 24 -#define R_PAR0_STATUS_DATA__sel__WIDTH 1 -#define R_PAR0_STATUS_DATA__sel__active 1 -#define R_PAR0_STATUS_DATA__sel__inactive 0 -#define R_PAR0_STATUS_DATA__ext_mode__BITNR 23 -#define R_PAR0_STATUS_DATA__ext_mode__WIDTH 1 -#define R_PAR0_STATUS_DATA__ext_mode__enable 1 -#define R_PAR0_STATUS_DATA__ext_mode__disable 0 -#define R_PAR0_STATUS_DATA__ecp_16__BITNR 22 -#define R_PAR0_STATUS_DATA__ecp_16__WIDTH 1 -#define R_PAR0_STATUS_DATA__ecp_16__active 1 -#define R_PAR0_STATUS_DATA__ecp_16__inactive 0 -#define R_PAR0_STATUS_DATA__tr_rdy__BITNR 17 -#define R_PAR0_STATUS_DATA__tr_rdy__WIDTH 1 -#define R_PAR0_STATUS_DATA__tr_rdy__ready 1 -#define R_PAR0_STATUS_DATA__tr_rdy__busy 0 -#define R_PAR0_STATUS_DATA__dav__BITNR 16 -#define R_PAR0_STATUS_DATA__dav__WIDTH 1 -#define R_PAR0_STATUS_DATA__dav__data 1 -#define R_PAR0_STATUS_DATA__dav__nodata 0 -#define R_PAR0_STATUS_DATA__ecp_cmd__BITNR 8 -#define R_PAR0_STATUS_DATA__ecp_cmd__WIDTH 1 -#define R_PAR0_STATUS_DATA__ecp_cmd__command 1 -#define R_PAR0_STATUS_DATA__ecp_cmd__data 0 -#define R_PAR0_STATUS_DATA__data__BITNR 0 -#define R_PAR0_STATUS_DATA__data__WIDTH 8 - -#define R_PAR0_STATUS (IO_TYPECAST_RO_UWORD 0xb0000042) -#define R_PAR0_STATUS__mode__BITNR 13 -#define R_PAR0_STATUS__mode__WIDTH 3 -#define R_PAR0_STATUS__mode__manual 0 -#define R_PAR0_STATUS__mode__centronics 1 -#define R_PAR0_STATUS__mode__fastbyte 2 -#define R_PAR0_STATUS__mode__nibble 3 -#define R_PAR0_STATUS__mode__byte 4 -#define R_PAR0_STATUS__mode__ecp_fwd 5 -#define R_PAR0_STATUS__mode__ecp_rev 6 -#define R_PAR0_STATUS__mode__off 7 -#define R_PAR0_STATUS__mode__epp_wr1 5 -#define R_PAR0_STATUS__mode__epp_wr2 6 -#define R_PAR0_STATUS__mode__epp_wr3 7 -#define R_PAR0_STATUS__mode__epp_rd 0 -#define R_PAR0_STATUS__perr__BITNR 12 -#define R_PAR0_STATUS__perr__WIDTH 1 -#define R_PAR0_STATUS__perr__active 1 -#define R_PAR0_STATUS__perr__inactive 0 -#define R_PAR0_STATUS__ack__BITNR 11 -#define R_PAR0_STATUS__ack__WIDTH 1 -#define R_PAR0_STATUS__ack__active 0 -#define R_PAR0_STATUS__ack__inactive 1 -#define R_PAR0_STATUS__busy__BITNR 10 -#define R_PAR0_STATUS__busy__WIDTH 1 -#define R_PAR0_STATUS__busy__active 1 -#define R_PAR0_STATUS__busy__inactive 0 -#define R_PAR0_STATUS__fault__BITNR 9 -#define R_PAR0_STATUS__fault__WIDTH 1 -#define R_PAR0_STATUS__fault__active 0 -#define R_PAR0_STATUS__fault__inactive 1 -#define R_PAR0_STATUS__sel__BITNR 8 -#define R_PAR0_STATUS__sel__WIDTH 1 -#define R_PAR0_STATUS__sel__active 1 -#define R_PAR0_STATUS__sel__inactive 0 -#define R_PAR0_STATUS__ext_mode__BITNR 7 -#define R_PAR0_STATUS__ext_mode__WIDTH 1 -#define R_PAR0_STATUS__ext_mode__enable 1 -#define R_PAR0_STATUS__ext_mode__disable 0 -#define R_PAR0_STATUS__ecp_16__BITNR 6 -#define R_PAR0_STATUS__ecp_16__WIDTH 1 -#define R_PAR0_STATUS__ecp_16__active 1 -#define R_PAR0_STATUS__ecp_16__inactive 0 -#define R_PAR0_STATUS__tr_rdy__BITNR 1 -#define R_PAR0_STATUS__tr_rdy__WIDTH 1 -#define R_PAR0_STATUS__tr_rdy__ready 1 -#define R_PAR0_STATUS__tr_rdy__busy 0 -#define R_PAR0_STATUS__dav__BITNR 0 -#define R_PAR0_STATUS__dav__WIDTH 1 -#define R_PAR0_STATUS__dav__data 1 -#define R_PAR0_STATUS__dav__nodata 0 - -#define R_PAR_ECP16_DATA (IO_TYPECAST_UWORD 0xb0000040) -#define R_PAR_ECP16_DATA__data__BITNR 0 -#define R_PAR_ECP16_DATA__data__WIDTH 16 - -#define R_PAR0_CONFIG (IO_TYPECAST_UDWORD 0xb0000044) -#define R_PAR0_CONFIG__ioe__BITNR 25 -#define R_PAR0_CONFIG__ioe__WIDTH 1 -#define R_PAR0_CONFIG__ioe__inv 1 -#define R_PAR0_CONFIG__ioe__noninv 0 -#define R_PAR0_CONFIG__iseli__BITNR 24 -#define R_PAR0_CONFIG__iseli__WIDTH 1 -#define R_PAR0_CONFIG__iseli__inv 1 -#define R_PAR0_CONFIG__iseli__noninv 0 -#define R_PAR0_CONFIG__iautofd__BITNR 23 -#define R_PAR0_CONFIG__iautofd__WIDTH 1 -#define R_PAR0_CONFIG__iautofd__inv 1 -#define R_PAR0_CONFIG__iautofd__noninv 0 -#define R_PAR0_CONFIG__istrb__BITNR 22 -#define R_PAR0_CONFIG__istrb__WIDTH 1 -#define R_PAR0_CONFIG__istrb__inv 1 -#define R_PAR0_CONFIG__istrb__noninv 0 -#define R_PAR0_CONFIG__iinit__BITNR 21 -#define R_PAR0_CONFIG__iinit__WIDTH 1 -#define R_PAR0_CONFIG__iinit__inv 1 -#define R_PAR0_CONFIG__iinit__noninv 0 -#define R_PAR0_CONFIG__iperr__BITNR 20 -#define R_PAR0_CONFIG__iperr__WIDTH 1 -#define R_PAR0_CONFIG__iperr__inv 1 -#define R_PAR0_CONFIG__iperr__noninv 0 -#define R_PAR0_CONFIG__iack__BITNR 19 -#define R_PAR0_CONFIG__iack__WIDTH 1 -#define R_PAR0_CONFIG__iack__inv 1 -#define R_PAR0_CONFIG__iack__noninv 0 -#define R_PAR0_CONFIG__ibusy__BITNR 18 -#define R_PAR0_CONFIG__ibusy__WIDTH 1 -#define R_PAR0_CONFIG__ibusy__inv 1 -#define R_PAR0_CONFIG__ibusy__noninv 0 -#define R_PAR0_CONFIG__ifault__BITNR 17 -#define R_PAR0_CONFIG__ifault__WIDTH 1 -#define R_PAR0_CONFIG__ifault__inv 1 -#define R_PAR0_CONFIG__ifault__noninv 0 -#define R_PAR0_CONFIG__isel__BITNR 16 -#define R_PAR0_CONFIG__isel__WIDTH 1 -#define R_PAR0_CONFIG__isel__inv 1 -#define R_PAR0_CONFIG__isel__noninv 0 -#define R_PAR0_CONFIG__ext_mode__BITNR 11 -#define R_PAR0_CONFIG__ext_mode__WIDTH 1 -#define R_PAR0_CONFIG__ext_mode__enable 1 -#define R_PAR0_CONFIG__ext_mode__disable 0 -#define R_PAR0_CONFIG__wide__BITNR 10 -#define R_PAR0_CONFIG__wide__WIDTH 1 -#define R_PAR0_CONFIG__wide__enable 1 -#define R_PAR0_CONFIG__wide__disable 0 -#define R_PAR0_CONFIG__dma__BITNR 9 -#define R_PAR0_CONFIG__dma__WIDTH 1 -#define R_PAR0_CONFIG__dma__enable 1 -#define R_PAR0_CONFIG__dma__disable 0 -#define R_PAR0_CONFIG__rle_in__BITNR 8 -#define R_PAR0_CONFIG__rle_in__WIDTH 1 -#define R_PAR0_CONFIG__rle_in__enable 1 -#define R_PAR0_CONFIG__rle_in__disable 0 -#define R_PAR0_CONFIG__rle_out__BITNR 7 -#define R_PAR0_CONFIG__rle_out__WIDTH 1 -#define R_PAR0_CONFIG__rle_out__enable 1 -#define R_PAR0_CONFIG__rle_out__disable 0 -#define R_PAR0_CONFIG__enable__BITNR 6 -#define R_PAR0_CONFIG__enable__WIDTH 1 -#define R_PAR0_CONFIG__enable__on 1 -#define R_PAR0_CONFIG__enable__reset 0 -#define R_PAR0_CONFIG__force__BITNR 5 -#define R_PAR0_CONFIG__force__WIDTH 1 -#define R_PAR0_CONFIG__force__on 1 -#define R_PAR0_CONFIG__force__off 0 -#define R_PAR0_CONFIG__ign_ack__BITNR 4 -#define R_PAR0_CONFIG__ign_ack__WIDTH 1 -#define R_PAR0_CONFIG__ign_ack__ignore 1 -#define R_PAR0_CONFIG__ign_ack__wait 0 -#define R_PAR0_CONFIG__oe_ack__BITNR 3 -#define R_PAR0_CONFIG__oe_ack__WIDTH 1 -#define R_PAR0_CONFIG__oe_ack__wait_oe 1 -#define R_PAR0_CONFIG__oe_ack__dont_wait 0 -#define R_PAR0_CONFIG__oe_ack__epp_addr 1 -#define R_PAR0_CONFIG__oe_ack__epp_data 0 -#define R_PAR0_CONFIG__epp_addr_data__BITNR 3 -#define R_PAR0_CONFIG__epp_addr_data__WIDTH 1 -#define R_PAR0_CONFIG__epp_addr_data__wait_oe 1 -#define R_PAR0_CONFIG__epp_addr_data__dont_wait 0 -#define R_PAR0_CONFIG__epp_addr_data__epp_addr 1 -#define R_PAR0_CONFIG__epp_addr_data__epp_data 0 -#define R_PAR0_CONFIG__mode__BITNR 0 -#define R_PAR0_CONFIG__mode__WIDTH 3 -#define R_PAR0_CONFIG__mode__manual 0 -#define R_PAR0_CONFIG__mode__centronics 1 -#define R_PAR0_CONFIG__mode__fastbyte 2 -#define R_PAR0_CONFIG__mode__nibble 3 -#define R_PAR0_CONFIG__mode__byte 4 -#define R_PAR0_CONFIG__mode__ecp_fwd 5 -#define R_PAR0_CONFIG__mode__ecp_rev 6 -#define R_PAR0_CONFIG__mode__off 7 -#define R_PAR0_CONFIG__mode__epp_wr1 5 -#define R_PAR0_CONFIG__mode__epp_wr2 6 -#define R_PAR0_CONFIG__mode__epp_wr3 7 -#define R_PAR0_CONFIG__mode__epp_rd 0 - -#define R_PAR0_DELAY (IO_TYPECAST_UDWORD 0xb0000048) -#define R_PAR0_DELAY__fine_hold__BITNR 21 -#define R_PAR0_DELAY__fine_hold__WIDTH 3 -#define R_PAR0_DELAY__hold__BITNR 16 -#define R_PAR0_DELAY__hold__WIDTH 5 -#define R_PAR0_DELAY__fine_strb__BITNR 13 -#define R_PAR0_DELAY__fine_strb__WIDTH 3 -#define R_PAR0_DELAY__strobe__BITNR 8 -#define R_PAR0_DELAY__strobe__WIDTH 5 -#define R_PAR0_DELAY__fine_setup__BITNR 5 -#define R_PAR0_DELAY__fine_setup__WIDTH 3 -#define R_PAR0_DELAY__setup__BITNR 0 -#define R_PAR0_DELAY__setup__WIDTH 5 - -#define R_PAR1_CTRL_DATA (IO_TYPECAST_UDWORD 0xb0000050) -#define R_PAR1_CTRL_DATA__peri_int__BITNR 24 -#define R_PAR1_CTRL_DATA__peri_int__WIDTH 1 -#define R_PAR1_CTRL_DATA__peri_int__ack 1 -#define R_PAR1_CTRL_DATA__peri_int__nop 0 -#define R_PAR1_CTRL_DATA__oe__BITNR 20 -#define R_PAR1_CTRL_DATA__oe__WIDTH 1 -#define R_PAR1_CTRL_DATA__oe__enable 1 -#define R_PAR1_CTRL_DATA__oe__disable 0 -#define R_PAR1_CTRL_DATA__seli__BITNR 19 -#define R_PAR1_CTRL_DATA__seli__WIDTH 1 -#define R_PAR1_CTRL_DATA__seli__active 1 -#define R_PAR1_CTRL_DATA__seli__inactive 0 -#define R_PAR1_CTRL_DATA__autofd__BITNR 18 -#define R_PAR1_CTRL_DATA__autofd__WIDTH 1 -#define R_PAR1_CTRL_DATA__autofd__active 1 -#define R_PAR1_CTRL_DATA__autofd__inactive 0 -#define R_PAR1_CTRL_DATA__strb__BITNR 17 -#define R_PAR1_CTRL_DATA__strb__WIDTH 1 -#define R_PAR1_CTRL_DATA__strb__active 1 -#define R_PAR1_CTRL_DATA__strb__inactive 0 -#define R_PAR1_CTRL_DATA__init__BITNR 16 -#define R_PAR1_CTRL_DATA__init__WIDTH 1 -#define R_PAR1_CTRL_DATA__init__active 1 -#define R_PAR1_CTRL_DATA__init__inactive 0 -#define R_PAR1_CTRL_DATA__ecp_cmd__BITNR 8 -#define R_PAR1_CTRL_DATA__ecp_cmd__WIDTH 1 -#define R_PAR1_CTRL_DATA__ecp_cmd__command 1 -#define R_PAR1_CTRL_DATA__ecp_cmd__data 0 -#define R_PAR1_CTRL_DATA__data__BITNR 0 -#define R_PAR1_CTRL_DATA__data__WIDTH 8 - -#define R_PAR1_CTRL (IO_TYPECAST_BYTE 0xb0000052) -#define R_PAR1_CTRL__ctrl__BITNR 0 -#define R_PAR1_CTRL__ctrl__WIDTH 5 - -#define R_PAR1_STATUS_DATA (IO_TYPECAST_RO_UDWORD 0xb0000050) -#define R_PAR1_STATUS_DATA__mode__BITNR 29 -#define R_PAR1_STATUS_DATA__mode__WIDTH 3 -#define R_PAR1_STATUS_DATA__mode__manual 0 -#define R_PAR1_STATUS_DATA__mode__centronics 1 -#define R_PAR1_STATUS_DATA__mode__fastbyte 2 -#define R_PAR1_STATUS_DATA__mode__nibble 3 -#define R_PAR1_STATUS_DATA__mode__byte 4 -#define R_PAR1_STATUS_DATA__mode__ecp_fwd 5 -#define R_PAR1_STATUS_DATA__mode__ecp_rev 6 -#define R_PAR1_STATUS_DATA__mode__off 7 -#define R_PAR1_STATUS_DATA__mode__epp_wr1 5 -#define R_PAR1_STATUS_DATA__mode__epp_wr2 6 -#define R_PAR1_STATUS_DATA__mode__epp_wr3 7 -#define R_PAR1_STATUS_DATA__mode__epp_rd 0 -#define R_PAR1_STATUS_DATA__perr__BITNR 28 -#define R_PAR1_STATUS_DATA__perr__WIDTH 1 -#define R_PAR1_STATUS_DATA__perr__active 1 -#define R_PAR1_STATUS_DATA__perr__inactive 0 -#define R_PAR1_STATUS_DATA__ack__BITNR 27 -#define R_PAR1_STATUS_DATA__ack__WIDTH 1 -#define R_PAR1_STATUS_DATA__ack__active 0 -#define R_PAR1_STATUS_DATA__ack__inactive 1 -#define R_PAR1_STATUS_DATA__busy__BITNR 26 -#define R_PAR1_STATUS_DATA__busy__WIDTH 1 -#define R_PAR1_STATUS_DATA__busy__active 1 -#define R_PAR1_STATUS_DATA__busy__inactive 0 -#define R_PAR1_STATUS_DATA__fault__BITNR 25 -#define R_PAR1_STATUS_DATA__fault__WIDTH 1 -#define R_PAR1_STATUS_DATA__fault__active 0 -#define R_PAR1_STATUS_DATA__fault__inactive 1 -#define R_PAR1_STATUS_DATA__sel__BITNR 24 -#define R_PAR1_STATUS_DATA__sel__WIDTH 1 -#define R_PAR1_STATUS_DATA__sel__active 1 -#define R_PAR1_STATUS_DATA__sel__inactive 0 -#define R_PAR1_STATUS_DATA__ext_mode__BITNR 23 -#define R_PAR1_STATUS_DATA__ext_mode__WIDTH 1 -#define R_PAR1_STATUS_DATA__ext_mode__enable 1 -#define R_PAR1_STATUS_DATA__ext_mode__disable 0 -#define R_PAR1_STATUS_DATA__tr_rdy__BITNR 17 -#define R_PAR1_STATUS_DATA__tr_rdy__WIDTH 1 -#define R_PAR1_STATUS_DATA__tr_rdy__ready 1 -#define R_PAR1_STATUS_DATA__tr_rdy__busy 0 -#define R_PAR1_STATUS_DATA__dav__BITNR 16 -#define R_PAR1_STATUS_DATA__dav__WIDTH 1 -#define R_PAR1_STATUS_DATA__dav__data 1 -#define R_PAR1_STATUS_DATA__dav__nodata 0 -#define R_PAR1_STATUS_DATA__ecp_cmd__BITNR 8 -#define R_PAR1_STATUS_DATA__ecp_cmd__WIDTH 1 -#define R_PAR1_STATUS_DATA__ecp_cmd__command 1 -#define R_PAR1_STATUS_DATA__ecp_cmd__data 0 -#define R_PAR1_STATUS_DATA__data__BITNR 0 -#define R_PAR1_STATUS_DATA__data__WIDTH 8 - -#define R_PAR1_STATUS (IO_TYPECAST_RO_UWORD 0xb0000052) -#define R_PAR1_STATUS__mode__BITNR 13 -#define R_PAR1_STATUS__mode__WIDTH 3 -#define R_PAR1_STATUS__mode__manual 0 -#define R_PAR1_STATUS__mode__centronics 1 -#define R_PAR1_STATUS__mode__fastbyte 2 -#define R_PAR1_STATUS__mode__nibble 3 -#define R_PAR1_STATUS__mode__byte 4 -#define R_PAR1_STATUS__mode__ecp_fwd 5 -#define R_PAR1_STATUS__mode__ecp_rev 6 -#define R_PAR1_STATUS__mode__off 7 -#define R_PAR1_STATUS__mode__epp_wr1 5 -#define R_PAR1_STATUS__mode__epp_wr2 6 -#define R_PAR1_STATUS__mode__epp_wr3 7 -#define R_PAR1_STATUS__mode__epp_rd 0 -#define R_PAR1_STATUS__perr__BITNR 12 -#define R_PAR1_STATUS__perr__WIDTH 1 -#define R_PAR1_STATUS__perr__active 1 -#define R_PAR1_STATUS__perr__inactive 0 -#define R_PAR1_STATUS__ack__BITNR 11 -#define R_PAR1_STATUS__ack__WIDTH 1 -#define R_PAR1_STATUS__ack__active 0 -#define R_PAR1_STATUS__ack__inactive 1 -#define R_PAR1_STATUS__busy__BITNR 10 -#define R_PAR1_STATUS__busy__WIDTH 1 -#define R_PAR1_STATUS__busy__active 1 -#define R_PAR1_STATUS__busy__inactive 0 -#define R_PAR1_STATUS__fault__BITNR 9 -#define R_PAR1_STATUS__fault__WIDTH 1 -#define R_PAR1_STATUS__fault__active 0 -#define R_PAR1_STATUS__fault__inactive 1 -#define R_PAR1_STATUS__sel__BITNR 8 -#define R_PAR1_STATUS__sel__WIDTH 1 -#define R_PAR1_STATUS__sel__active 1 -#define R_PAR1_STATUS__sel__inactive 0 -#define R_PAR1_STATUS__ext_mode__BITNR 7 -#define R_PAR1_STATUS__ext_mode__WIDTH 1 -#define R_PAR1_STATUS__ext_mode__enable 1 -#define R_PAR1_STATUS__ext_mode__disable 0 -#define R_PAR1_STATUS__tr_rdy__BITNR 1 -#define R_PAR1_STATUS__tr_rdy__WIDTH 1 -#define R_PAR1_STATUS__tr_rdy__ready 1 -#define R_PAR1_STATUS__tr_rdy__busy 0 -#define R_PAR1_STATUS__dav__BITNR 0 -#define R_PAR1_STATUS__dav__WIDTH 1 -#define R_PAR1_STATUS__dav__data 1 -#define R_PAR1_STATUS__dav__nodata 0 - -#define R_PAR1_CONFIG (IO_TYPECAST_UDWORD 0xb0000054) -#define R_PAR1_CONFIG__ioe__BITNR 25 -#define R_PAR1_CONFIG__ioe__WIDTH 1 -#define R_PAR1_CONFIG__ioe__inv 1 -#define R_PAR1_CONFIG__ioe__noninv 0 -#define R_PAR1_CONFIG__iseli__BITNR 24 -#define R_PAR1_CONFIG__iseli__WIDTH 1 -#define R_PAR1_CONFIG__iseli__inv 1 -#define R_PAR1_CONFIG__iseli__noninv 0 -#define R_PAR1_CONFIG__iautofd__BITNR 23 -#define R_PAR1_CONFIG__iautofd__WIDTH 1 -#define R_PAR1_CONFIG__iautofd__inv 1 -#define R_PAR1_CONFIG__iautofd__noninv 0 -#define R_PAR1_CONFIG__istrb__BITNR 22 -#define R_PAR1_CONFIG__istrb__WIDTH 1 -#define R_PAR1_CONFIG__istrb__inv 1 -#define R_PAR1_CONFIG__istrb__noninv 0 -#define R_PAR1_CONFIG__iinit__BITNR 21 -#define R_PAR1_CONFIG__iinit__WIDTH 1 -#define R_PAR1_CONFIG__iinit__inv 1 -#define R_PAR1_CONFIG__iinit__noninv 0 -#define R_PAR1_CONFIG__iperr__BITNR 20 -#define R_PAR1_CONFIG__iperr__WIDTH 1 -#define R_PAR1_CONFIG__iperr__inv 1 -#define R_PAR1_CONFIG__iperr__noninv 0 -#define R_PAR1_CONFIG__iack__BITNR 19 -#define R_PAR1_CONFIG__iack__WIDTH 1 -#define R_PAR1_CONFIG__iack__inv 1 -#define R_PAR1_CONFIG__iack__noninv 0 -#define R_PAR1_CONFIG__ibusy__BITNR 18 -#define R_PAR1_CONFIG__ibusy__WIDTH 1 -#define R_PAR1_CONFIG__ibusy__inv 1 -#define R_PAR1_CONFIG__ibusy__noninv 0 -#define R_PAR1_CONFIG__ifault__BITNR 17 -#define R_PAR1_CONFIG__ifault__WIDTH 1 -#define R_PAR1_CONFIG__ifault__inv 1 -#define R_PAR1_CONFIG__ifault__noninv 0 -#define R_PAR1_CONFIG__isel__BITNR 16 -#define R_PAR1_CONFIG__isel__WIDTH 1 -#define R_PAR1_CONFIG__isel__inv 1 -#define R_PAR1_CONFIG__isel__noninv 0 -#define R_PAR1_CONFIG__ext_mode__BITNR 11 -#define R_PAR1_CONFIG__ext_mode__WIDTH 1 -#define R_PAR1_CONFIG__ext_mode__enable 1 -#define R_PAR1_CONFIG__ext_mode__disable 0 -#define R_PAR1_CONFIG__dma__BITNR 9 -#define R_PAR1_CONFIG__dma__WIDTH 1 -#define R_PAR1_CONFIG__dma__enable 1 -#define R_PAR1_CONFIG__dma__disable 0 -#define R_PAR1_CONFIG__rle_in__BITNR 8 -#define R_PAR1_CONFIG__rle_in__WIDTH 1 -#define R_PAR1_CONFIG__rle_in__enable 1 -#define R_PAR1_CONFIG__rle_in__disable 0 -#define R_PAR1_CONFIG__rle_out__BITNR 7 -#define R_PAR1_CONFIG__rle_out__WIDTH 1 -#define R_PAR1_CONFIG__rle_out__enable 1 -#define R_PAR1_CONFIG__rle_out__disable 0 -#define R_PAR1_CONFIG__enable__BITNR 6 -#define R_PAR1_CONFIG__enable__WIDTH 1 -#define R_PAR1_CONFIG__enable__on 1 -#define R_PAR1_CONFIG__enable__reset 0 -#define R_PAR1_CONFIG__force__BITNR 5 -#define R_PAR1_CONFIG__force__WIDTH 1 -#define R_PAR1_CONFIG__force__on 1 -#define R_PAR1_CONFIG__force__off 0 -#define R_PAR1_CONFIG__ign_ack__BITNR 4 -#define R_PAR1_CONFIG__ign_ack__WIDTH 1 -#define R_PAR1_CONFIG__ign_ack__ignore 1 -#define R_PAR1_CONFIG__ign_ack__wait 0 -#define R_PAR1_CONFIG__oe_ack__BITNR 3 -#define R_PAR1_CONFIG__oe_ack__WIDTH 1 -#define R_PAR1_CONFIG__oe_ack__wait_oe 1 -#define R_PAR1_CONFIG__oe_ack__dont_wait 0 -#define R_PAR1_CONFIG__oe_ack__epp_addr 1 -#define R_PAR1_CONFIG__oe_ack__epp_data 0 -#define R_PAR1_CONFIG__epp_addr_data__BITNR 3 -#define R_PAR1_CONFIG__epp_addr_data__WIDTH 1 -#define R_PAR1_CONFIG__epp_addr_data__wait_oe 1 -#define R_PAR1_CONFIG__epp_addr_data__dont_wait 0 -#define R_PAR1_CONFIG__epp_addr_data__epp_addr 1 -#define R_PAR1_CONFIG__epp_addr_data__epp_data 0 -#define R_PAR1_CONFIG__mode__BITNR 0 -#define R_PAR1_CONFIG__mode__WIDTH 3 -#define R_PAR1_CONFIG__mode__manual 0 -#define R_PAR1_CONFIG__mode__centronics 1 -#define R_PAR1_CONFIG__mode__fastbyte 2 -#define R_PAR1_CONFIG__mode__nibble 3 -#define R_PAR1_CONFIG__mode__byte 4 -#define R_PAR1_CONFIG__mode__ecp_fwd 5 -#define R_PAR1_CONFIG__mode__ecp_rev 6 -#define R_PAR1_CONFIG__mode__off 7 -#define R_PAR1_CONFIG__mode__epp_wr1 5 -#define R_PAR1_CONFIG__mode__epp_wr2 6 -#define R_PAR1_CONFIG__mode__epp_wr3 7 -#define R_PAR1_CONFIG__mode__epp_rd 0 - -#define R_PAR1_DELAY (IO_TYPECAST_UDWORD 0xb0000058) -#define R_PAR1_DELAY__fine_hold__BITNR 21 -#define R_PAR1_DELAY__fine_hold__WIDTH 3 -#define R_PAR1_DELAY__hold__BITNR 16 -#define R_PAR1_DELAY__hold__WIDTH 5 -#define R_PAR1_DELAY__fine_strb__BITNR 13 -#define R_PAR1_DELAY__fine_strb__WIDTH 3 -#define R_PAR1_DELAY__strobe__BITNR 8 -#define R_PAR1_DELAY__strobe__WIDTH 5 -#define R_PAR1_DELAY__fine_setup__BITNR 5 -#define R_PAR1_DELAY__fine_setup__WIDTH 3 -#define R_PAR1_DELAY__setup__BITNR 0 -#define R_PAR1_DELAY__setup__WIDTH 5 - -/* -!* ATA interface registers -!*/ - -#define R_ATA_CTRL_DATA (IO_TYPECAST_UDWORD 0xb0000040) -#define R_ATA_CTRL_DATA__sel__BITNR 30 -#define R_ATA_CTRL_DATA__sel__WIDTH 2 -#define R_ATA_CTRL_DATA__cs1__BITNR 29 -#define R_ATA_CTRL_DATA__cs1__WIDTH 1 -#define R_ATA_CTRL_DATA__cs1__active 1 -#define R_ATA_CTRL_DATA__cs1__inactive 0 -#define R_ATA_CTRL_DATA__cs0__BITNR 28 -#define R_ATA_CTRL_DATA__cs0__WIDTH 1 -#define R_ATA_CTRL_DATA__cs0__active 1 -#define R_ATA_CTRL_DATA__cs0__inactive 0 -#define R_ATA_CTRL_DATA__addr__BITNR 25 -#define R_ATA_CTRL_DATA__addr__WIDTH 3 -#define R_ATA_CTRL_DATA__rw__BITNR 24 -#define R_ATA_CTRL_DATA__rw__WIDTH 1 -#define R_ATA_CTRL_DATA__rw__read 1 -#define R_ATA_CTRL_DATA__rw__write 0 -#define R_ATA_CTRL_DATA__src_dst__BITNR 23 -#define R_ATA_CTRL_DATA__src_dst__WIDTH 1 -#define R_ATA_CTRL_DATA__src_dst__dma 1 -#define R_ATA_CTRL_DATA__src_dst__register 0 -#define R_ATA_CTRL_DATA__handsh__BITNR 22 -#define R_ATA_CTRL_DATA__handsh__WIDTH 1 -#define R_ATA_CTRL_DATA__handsh__dma 1 -#define R_ATA_CTRL_DATA__handsh__pio 0 -#define R_ATA_CTRL_DATA__multi__BITNR 21 -#define R_ATA_CTRL_DATA__multi__WIDTH 1 -#define R_ATA_CTRL_DATA__multi__on 1 -#define R_ATA_CTRL_DATA__multi__off 0 -#define R_ATA_CTRL_DATA__dma_size__BITNR 20 -#define R_ATA_CTRL_DATA__dma_size__WIDTH 1 -#define R_ATA_CTRL_DATA__dma_size__byte 1 -#define R_ATA_CTRL_DATA__dma_size__word 0 -#define R_ATA_CTRL_DATA__data__BITNR 0 -#define R_ATA_CTRL_DATA__data__WIDTH 16 - -#define R_ATA_STATUS_DATA (IO_TYPECAST_RO_UDWORD 0xb0000040) -#define R_ATA_STATUS_DATA__busy__BITNR 18 -#define R_ATA_STATUS_DATA__busy__WIDTH 1 -#define R_ATA_STATUS_DATA__busy__yes 1 -#define R_ATA_STATUS_DATA__busy__no 0 -#define R_ATA_STATUS_DATA__tr_rdy__BITNR 17 -#define R_ATA_STATUS_DATA__tr_rdy__WIDTH 1 -#define R_ATA_STATUS_DATA__tr_rdy__ready 1 -#define R_ATA_STATUS_DATA__tr_rdy__busy 0 -#define R_ATA_STATUS_DATA__dav__BITNR 16 -#define R_ATA_STATUS_DATA__dav__WIDTH 1 -#define R_ATA_STATUS_DATA__dav__data 1 -#define R_ATA_STATUS_DATA__dav__nodata 0 -#define R_ATA_STATUS_DATA__data__BITNR 0 -#define R_ATA_STATUS_DATA__data__WIDTH 16 - -#define R_ATA_CONFIG (IO_TYPECAST_UDWORD 0xb0000044) -#define R_ATA_CONFIG__enable__BITNR 25 -#define R_ATA_CONFIG__enable__WIDTH 1 -#define R_ATA_CONFIG__enable__on 1 -#define R_ATA_CONFIG__enable__off 0 -#define R_ATA_CONFIG__dma_strobe__BITNR 20 -#define R_ATA_CONFIG__dma_strobe__WIDTH 5 -#define R_ATA_CONFIG__dma_hold__BITNR 15 -#define R_ATA_CONFIG__dma_hold__WIDTH 5 -#define R_ATA_CONFIG__pio_setup__BITNR 10 -#define R_ATA_CONFIG__pio_setup__WIDTH 5 -#define R_ATA_CONFIG__pio_strobe__BITNR 5 -#define R_ATA_CONFIG__pio_strobe__WIDTH 5 -#define R_ATA_CONFIG__pio_hold__BITNR 0 -#define R_ATA_CONFIG__pio_hold__WIDTH 5 - -#define R_ATA_TRANSFER_CNT (IO_TYPECAST_UDWORD 0xb0000048) -#define R_ATA_TRANSFER_CNT__count__BITNR 0 -#define R_ATA_TRANSFER_CNT__count__WIDTH 17 - -/* -!* SCSI registers -!*/ - -#define R_SCSI0_CTRL (IO_TYPECAST_UDWORD 0xb0000044) -#define R_SCSI0_CTRL__id_type__BITNR 31 -#define R_SCSI0_CTRL__id_type__WIDTH 1 -#define R_SCSI0_CTRL__id_type__software 1 -#define R_SCSI0_CTRL__id_type__hardware 0 -#define R_SCSI0_CTRL__sel_timeout__BITNR 24 -#define R_SCSI0_CTRL__sel_timeout__WIDTH 7 -#define R_SCSI0_CTRL__synch_per__BITNR 16 -#define R_SCSI0_CTRL__synch_per__WIDTH 8 -#define R_SCSI0_CTRL__rst__BITNR 15 -#define R_SCSI0_CTRL__rst__WIDTH 1 -#define R_SCSI0_CTRL__rst__yes 1 -#define R_SCSI0_CTRL__rst__no 0 -#define R_SCSI0_CTRL__atn__BITNR 14 -#define R_SCSI0_CTRL__atn__WIDTH 1 -#define R_SCSI0_CTRL__atn__yes 1 -#define R_SCSI0_CTRL__atn__no 0 -#define R_SCSI0_CTRL__my_id__BITNR 9 -#define R_SCSI0_CTRL__my_id__WIDTH 4 -#define R_SCSI0_CTRL__target_id__BITNR 4 -#define R_SCSI0_CTRL__target_id__WIDTH 4 -#define R_SCSI0_CTRL__fast_20__BITNR 3 -#define R_SCSI0_CTRL__fast_20__WIDTH 1 -#define R_SCSI0_CTRL__fast_20__yes 1 -#define R_SCSI0_CTRL__fast_20__no 0 -#define R_SCSI0_CTRL__bus_width__BITNR 2 -#define R_SCSI0_CTRL__bus_width__WIDTH 1 -#define R_SCSI0_CTRL__bus_width__wide 1 -#define R_SCSI0_CTRL__bus_width__narrow 0 -#define R_SCSI0_CTRL__synch__BITNR 1 -#define R_SCSI0_CTRL__synch__WIDTH 1 -#define R_SCSI0_CTRL__synch__synch 1 -#define R_SCSI0_CTRL__synch__asynch 0 -#define R_SCSI0_CTRL__enable__BITNR 0 -#define R_SCSI0_CTRL__enable__WIDTH 1 -#define R_SCSI0_CTRL__enable__on 1 -#define R_SCSI0_CTRL__enable__off 0 - -#define R_SCSI0_CMD_DATA (IO_TYPECAST_UDWORD 0xb0000040) -#define R_SCSI0_CMD_DATA__parity_in__BITNR 26 -#define R_SCSI0_CMD_DATA__parity_in__WIDTH 1 -#define R_SCSI0_CMD_DATA__parity_in__on 0 -#define R_SCSI0_CMD_DATA__parity_in__off 1 -#define R_SCSI0_CMD_DATA__skip__BITNR 25 -#define R_SCSI0_CMD_DATA__skip__WIDTH 1 -#define R_SCSI0_CMD_DATA__skip__on 1 -#define R_SCSI0_CMD_DATA__skip__off 0 -#define R_SCSI0_CMD_DATA__clr_status__BITNR 24 -#define R_SCSI0_CMD_DATA__clr_status__WIDTH 1 -#define R_SCSI0_CMD_DATA__clr_status__yes 1 -#define R_SCSI0_CMD_DATA__clr_status__nop 0 -#define R_SCSI0_CMD_DATA__asynch_setup__BITNR 20 -#define R_SCSI0_CMD_DATA__asynch_setup__WIDTH 4 -#define R_SCSI0_CMD_DATA__command__BITNR 16 -#define R_SCSI0_CMD_DATA__command__WIDTH 4 -#define R_SCSI0_CMD_DATA__command__full_din_1 0 -#define R_SCSI0_CMD_DATA__command__full_dout_1 1 -#define R_SCSI0_CMD_DATA__command__full_stat_1 2 -#define R_SCSI0_CMD_DATA__command__resel_din 3 -#define R_SCSI0_CMD_DATA__command__resel_dout 4 -#define R_SCSI0_CMD_DATA__command__resel_stat 5 -#define R_SCSI0_CMD_DATA__command__arb_only 6 -#define R_SCSI0_CMD_DATA__command__full_din_3 8 -#define R_SCSI0_CMD_DATA__command__full_dout_3 9 -#define R_SCSI0_CMD_DATA__command__full_stat_3 10 -#define R_SCSI0_CMD_DATA__command__man_data_in 11 -#define R_SCSI0_CMD_DATA__command__man_data_out 12 -#define R_SCSI0_CMD_DATA__command__man_rat 13 -#define R_SCSI0_CMD_DATA__data_out__BITNR 0 -#define R_SCSI0_CMD_DATA__data_out__WIDTH 16 - -#define R_SCSI0_DATA (IO_TYPECAST_UWORD 0xb0000040) -#define R_SCSI0_DATA__data_out__BITNR 0 -#define R_SCSI0_DATA__data_out__WIDTH 16 - -#define R_SCSI0_CMD (IO_TYPECAST_BYTE 0xb0000042) -#define R_SCSI0_CMD__asynch_setup__BITNR 4 -#define R_SCSI0_CMD__asynch_setup__WIDTH 4 -#define R_SCSI0_CMD__command__BITNR 0 -#define R_SCSI0_CMD__command__WIDTH 4 -#define R_SCSI0_CMD__command__full_din_1 0 -#define R_SCSI0_CMD__command__full_dout_1 1 -#define R_SCSI0_CMD__command__full_stat_1 2 -#define R_SCSI0_CMD__command__resel_din 3 -#define R_SCSI0_CMD__command__resel_dout 4 -#define R_SCSI0_CMD__command__resel_stat 5 -#define R_SCSI0_CMD__command__arb_only 6 -#define R_SCSI0_CMD__command__full_din_3 8 -#define R_SCSI0_CMD__command__full_dout_3 9 -#define R_SCSI0_CMD__command__full_stat_3 10 -#define R_SCSI0_CMD__command__man_data_in 11 -#define R_SCSI0_CMD__command__man_data_out 12 -#define R_SCSI0_CMD__command__man_rat 13 - -#define R_SCSI0_STATUS_CTRL (IO_TYPECAST_BYTE 0xb0000043) -#define R_SCSI0_STATUS_CTRL__parity_in__BITNR 2 -#define R_SCSI0_STATUS_CTRL__parity_in__WIDTH 1 -#define R_SCSI0_STATUS_CTRL__parity_in__on 0 -#define R_SCSI0_STATUS_CTRL__parity_in__off 1 -#define R_SCSI0_STATUS_CTRL__skip__BITNR 1 -#define R_SCSI0_STATUS_CTRL__skip__WIDTH 1 -#define R_SCSI0_STATUS_CTRL__skip__on 1 -#define R_SCSI0_STATUS_CTRL__skip__off 0 -#define R_SCSI0_STATUS_CTRL__clr_status__BITNR 0 -#define R_SCSI0_STATUS_CTRL__clr_status__WIDTH 1 -#define R_SCSI0_STATUS_CTRL__clr_status__yes 1 -#define R_SCSI0_STATUS_CTRL__clr_status__nop 0 - -#define R_SCSI0_STATUS (IO_TYPECAST_RO_UDWORD 0xb0000048) -#define R_SCSI0_STATUS__tst_arb_won__BITNR 23 -#define R_SCSI0_STATUS__tst_arb_won__WIDTH 1 -#define R_SCSI0_STATUS__tst_resel__BITNR 22 -#define R_SCSI0_STATUS__tst_resel__WIDTH 1 -#define R_SCSI0_STATUS__parity_error__BITNR 21 -#define R_SCSI0_STATUS__parity_error__WIDTH 1 -#define R_SCSI0_STATUS__bus_reset__BITNR 20 -#define R_SCSI0_STATUS__bus_reset__WIDTH 1 -#define R_SCSI0_STATUS__bus_reset__yes 1 -#define R_SCSI0_STATUS__bus_reset__no 0 -#define R_SCSI0_STATUS__resel_target__BITNR 15 -#define R_SCSI0_STATUS__resel_target__WIDTH 4 -#define R_SCSI0_STATUS__resel__BITNR 14 -#define R_SCSI0_STATUS__resel__WIDTH 1 -#define R_SCSI0_STATUS__resel__yes 1 -#define R_SCSI0_STATUS__resel__no 0 -#define R_SCSI0_STATUS__curr_phase__BITNR 11 -#define R_SCSI0_STATUS__curr_phase__WIDTH 3 -#define R_SCSI0_STATUS__curr_phase__ph_undef 0 -#define R_SCSI0_STATUS__curr_phase__ph_msg_in 7 -#define R_SCSI0_STATUS__curr_phase__ph_msg_out 6 -#define R_SCSI0_STATUS__curr_phase__ph_status 3 -#define R_SCSI0_STATUS__curr_phase__ph_command 2 -#define R_SCSI0_STATUS__curr_phase__ph_data_in 5 -#define R_SCSI0_STATUS__curr_phase__ph_data_out 4 -#define R_SCSI0_STATUS__curr_phase__ph_resel 1 -#define R_SCSI0_STATUS__last_seq_step__BITNR 6 -#define R_SCSI0_STATUS__last_seq_step__WIDTH 5 -#define R_SCSI0_STATUS__last_seq_step__st_bus_free 24 -#define R_SCSI0_STATUS__last_seq_step__st_arbitrate 8 -#define R_SCSI0_STATUS__last_seq_step__st_resel_req 29 -#define R_SCSI0_STATUS__last_seq_step__st_msg_1 2 -#define R_SCSI0_STATUS__last_seq_step__st_manual 28 -#define R_SCSI0_STATUS__last_seq_step__st_transf_cmd 30 -#define R_SCSI0_STATUS__last_seq_step__st_msg_2 6 -#define R_SCSI0_STATUS__last_seq_step__st_msg_3 22 -#define R_SCSI0_STATUS__last_seq_step__st_answer 3 -#define R_SCSI0_STATUS__last_seq_step__st_synch_din_perr 1 -#define R_SCSI0_STATUS__last_seq_step__st_transfer_done 15 -#define R_SCSI0_STATUS__last_seq_step__st_synch_dout 0 -#define R_SCSI0_STATUS__last_seq_step__st_asynch_dout 25 -#define R_SCSI0_STATUS__last_seq_step__st_synch_din 13 -#define R_SCSI0_STATUS__last_seq_step__st_asynch_din 9 -#define R_SCSI0_STATUS__last_seq_step__st_synch_dout_ack 4 -#define R_SCSI0_STATUS__last_seq_step__st_synch_din_ack 12 -#define R_SCSI0_STATUS__last_seq_step__st_synch_din_ack_perr 5 -#define R_SCSI0_STATUS__last_seq_step__st_asynch_dout_end 11 -#define R_SCSI0_STATUS__last_seq_step__st_iwr 27 -#define R_SCSI0_STATUS__last_seq_step__st_wait_free_disc 21 -#define R_SCSI0_STATUS__last_seq_step__st_sdp_disc 7 -#define R_SCSI0_STATUS__last_seq_step__st_cc 31 -#define R_SCSI0_STATUS__last_seq_step__st_iwr_good 14 -#define R_SCSI0_STATUS__last_seq_step__st_iwr_cc 23 -#define R_SCSI0_STATUS__last_seq_step__st_wait_free_iwr_cc 17 -#define R_SCSI0_STATUS__last_seq_step__st_wait_free_cc 20 -#define R_SCSI0_STATUS__last_seq_step__st_wait_free_sdp_disc 16 -#define R_SCSI0_STATUS__last_seq_step__st_manual_req 10 -#define R_SCSI0_STATUS__last_seq_step__st_manual_din_prot 18 -#define R_SCSI0_STATUS__valid_status__BITNR 5 -#define R_SCSI0_STATUS__valid_status__WIDTH 1 -#define R_SCSI0_STATUS__valid_status__yes 1 -#define R_SCSI0_STATUS__valid_status__no 0 -#define R_SCSI0_STATUS__seq_status__BITNR 0 -#define R_SCSI0_STATUS__seq_status__WIDTH 5 -#define R_SCSI0_STATUS__seq_status__info_seq_complete 0 -#define R_SCSI0_STATUS__seq_status__info_parity_error 1 -#define R_SCSI0_STATUS__seq_status__info_unhandled_msg_in 2 -#define R_SCSI0_STATUS__seq_status__info_unexp_ph_change 3 -#define R_SCSI0_STATUS__seq_status__info_arb_lost 4 -#define R_SCSI0_STATUS__seq_status__info_sel_timeout 5 -#define R_SCSI0_STATUS__seq_status__info_unexp_bf 6 -#define R_SCSI0_STATUS__seq_status__info_illegal_op 7 -#define R_SCSI0_STATUS__seq_status__info_rec_recvd 8 -#define R_SCSI0_STATUS__seq_status__info_reselected 9 -#define R_SCSI0_STATUS__seq_status__info_unhandled_status 10 -#define R_SCSI0_STATUS__seq_status__info_bus_reset 11 -#define R_SCSI0_STATUS__seq_status__info_illegal_bf 12 -#define R_SCSI0_STATUS__seq_status__info_bus_free 13 - -#define R_SCSI0_DATA_IN (IO_TYPECAST_RO_UWORD 0xb0000040) -#define R_SCSI0_DATA_IN__data_in__BITNR 0 -#define R_SCSI0_DATA_IN__data_in__WIDTH 16 - -#define R_SCSI1_CTRL (IO_TYPECAST_UDWORD 0xb0000054) -#define R_SCSI1_CTRL__id_type__BITNR 31 -#define R_SCSI1_CTRL__id_type__WIDTH 1 -#define R_SCSI1_CTRL__id_type__software 1 -#define R_SCSI1_CTRL__id_type__hardware 0 -#define R_SCSI1_CTRL__sel_timeout__BITNR 24 -#define R_SCSI1_CTRL__sel_timeout__WIDTH 7 -#define R_SCSI1_CTRL__synch_per__BITNR 16 -#define R_SCSI1_CTRL__synch_per__WIDTH 8 -#define R_SCSI1_CTRL__rst__BITNR 15 -#define R_SCSI1_CTRL__rst__WIDTH 1 -#define R_SCSI1_CTRL__rst__yes 1 -#define R_SCSI1_CTRL__rst__no 0 -#define R_SCSI1_CTRL__atn__BITNR 14 -#define R_SCSI1_CTRL__atn__WIDTH 1 -#define R_SCSI1_CTRL__atn__yes 1 -#define R_SCSI1_CTRL__atn__no 0 -#define R_SCSI1_CTRL__my_id__BITNR 9 -#define R_SCSI1_CTRL__my_id__WIDTH 4 -#define R_SCSI1_CTRL__target_id__BITNR 4 -#define R_SCSI1_CTRL__target_id__WIDTH 4 -#define R_SCSI1_CTRL__fast_20__BITNR 3 -#define R_SCSI1_CTRL__fast_20__WIDTH 1 -#define R_SCSI1_CTRL__fast_20__yes 1 -#define R_SCSI1_CTRL__fast_20__no 0 -#define R_SCSI1_CTRL__bus_width__BITNR 2 -#define R_SCSI1_CTRL__bus_width__WIDTH 1 -#define R_SCSI1_CTRL__bus_width__wide 1 -#define R_SCSI1_CTRL__bus_width__narrow 0 -#define R_SCSI1_CTRL__synch__BITNR 1 -#define R_SCSI1_CTRL__synch__WIDTH 1 -#define R_SCSI1_CTRL__synch__synch 1 -#define R_SCSI1_CTRL__synch__asynch 0 -#define R_SCSI1_CTRL__enable__BITNR 0 -#define R_SCSI1_CTRL__enable__WIDTH 1 -#define R_SCSI1_CTRL__enable__on 1 -#define R_SCSI1_CTRL__enable__off 0 - -#define R_SCSI1_CMD_DATA (IO_TYPECAST_UDWORD 0xb0000050) -#define R_SCSI1_CMD_DATA__parity_in__BITNR 26 -#define R_SCSI1_CMD_DATA__parity_in__WIDTH 1 -#define R_SCSI1_CMD_DATA__parity_in__on 0 -#define R_SCSI1_CMD_DATA__parity_in__off 1 -#define R_SCSI1_CMD_DATA__skip__BITNR 25 -#define R_SCSI1_CMD_DATA__skip__WIDTH 1 -#define R_SCSI1_CMD_DATA__skip__on 1 -#define R_SCSI1_CMD_DATA__skip__off 0 -#define R_SCSI1_CMD_DATA__clr_status__BITNR 24 -#define R_SCSI1_CMD_DATA__clr_status__WIDTH 1 -#define R_SCSI1_CMD_DATA__clr_status__yes 1 -#define R_SCSI1_CMD_DATA__clr_status__nop 0 -#define R_SCSI1_CMD_DATA__asynch_setup__BITNR 20 -#define R_SCSI1_CMD_DATA__asynch_setup__WIDTH 4 -#define R_SCSI1_CMD_DATA__command__BITNR 16 -#define R_SCSI1_CMD_DATA__command__WIDTH 4 -#define R_SCSI1_CMD_DATA__command__full_din_1 0 -#define R_SCSI1_CMD_DATA__command__full_dout_1 1 -#define R_SCSI1_CMD_DATA__command__full_stat_1 2 -#define R_SCSI1_CMD_DATA__command__resel_din 3 -#define R_SCSI1_CMD_DATA__command__resel_dout 4 -#define R_SCSI1_CMD_DATA__command__resel_stat 5 -#define R_SCSI1_CMD_DATA__command__arb_only 6 -#define R_SCSI1_CMD_DATA__command__full_din_3 8 -#define R_SCSI1_CMD_DATA__command__full_dout_3 9 -#define R_SCSI1_CMD_DATA__command__full_stat_3 10 -#define R_SCSI1_CMD_DATA__command__man_data_in 11 -#define R_SCSI1_CMD_DATA__command__man_data_out 12 -#define R_SCSI1_CMD_DATA__command__man_rat 13 -#define R_SCSI1_CMD_DATA__data_out__BITNR 0 -#define R_SCSI1_CMD_DATA__data_out__WIDTH 16 - -#define R_SCSI1_DATA (IO_TYPECAST_UWORD 0xb0000050) -#define R_SCSI1_DATA__data_out__BITNR 0 -#define R_SCSI1_DATA__data_out__WIDTH 16 - -#define R_SCSI1_CMD (IO_TYPECAST_BYTE 0xb0000052) -#define R_SCSI1_CMD__asynch_setup__BITNR 4 -#define R_SCSI1_CMD__asynch_setup__WIDTH 4 -#define R_SCSI1_CMD__command__BITNR 0 -#define R_SCSI1_CMD__command__WIDTH 4 -#define R_SCSI1_CMD__command__full_din_1 0 -#define R_SCSI1_CMD__command__full_dout_1 1 -#define R_SCSI1_CMD__command__full_stat_1 2 -#define R_SCSI1_CMD__command__resel_din 3 -#define R_SCSI1_CMD__command__resel_dout 4 -#define R_SCSI1_CMD__command__resel_stat 5 -#define R_SCSI1_CMD__command__arb_only 6 -#define R_SCSI1_CMD__command__full_din_3 8 -#define R_SCSI1_CMD__command__full_dout_3 9 -#define R_SCSI1_CMD__command__full_stat_3 10 -#define R_SCSI1_CMD__command__man_data_in 11 -#define R_SCSI1_CMD__command__man_data_out 12 -#define R_SCSI1_CMD__command__man_rat 13 - -#define R_SCSI1_STATUS_CTRL (IO_TYPECAST_BYTE 0xb0000053) -#define R_SCSI1_STATUS_CTRL__parity_in__BITNR 2 -#define R_SCSI1_STATUS_CTRL__parity_in__WIDTH 1 -#define R_SCSI1_STATUS_CTRL__parity_in__on 0 -#define R_SCSI1_STATUS_CTRL__parity_in__off 1 -#define R_SCSI1_STATUS_CTRL__skip__BITNR 1 -#define R_SCSI1_STATUS_CTRL__skip__WIDTH 1 -#define R_SCSI1_STATUS_CTRL__skip__on 1 -#define R_SCSI1_STATUS_CTRL__skip__off 0 -#define R_SCSI1_STATUS_CTRL__clr_status__BITNR 0 -#define R_SCSI1_STATUS_CTRL__clr_status__WIDTH 1 -#define R_SCSI1_STATUS_CTRL__clr_status__yes 1 -#define R_SCSI1_STATUS_CTRL__clr_status__nop 0 - -#define R_SCSI1_STATUS (IO_TYPECAST_RO_UDWORD 0xb0000058) -#define R_SCSI1_STATUS__tst_arb_won__BITNR 23 -#define R_SCSI1_STATUS__tst_arb_won__WIDTH 1 -#define R_SCSI1_STATUS__tst_resel__BITNR 22 -#define R_SCSI1_STATUS__tst_resel__WIDTH 1 -#define R_SCSI1_STATUS__parity_error__BITNR 21 -#define R_SCSI1_STATUS__parity_error__WIDTH 1 -#define R_SCSI1_STATUS__bus_reset__BITNR 20 -#define R_SCSI1_STATUS__bus_reset__WIDTH 1 -#define R_SCSI1_STATUS__bus_reset__yes 1 -#define R_SCSI1_STATUS__bus_reset__no 0 -#define R_SCSI1_STATUS__resel_target__BITNR 15 -#define R_SCSI1_STATUS__resel_target__WIDTH 4 -#define R_SCSI1_STATUS__resel__BITNR 14 -#define R_SCSI1_STATUS__resel__WIDTH 1 -#define R_SCSI1_STATUS__resel__yes 1 -#define R_SCSI1_STATUS__resel__no 0 -#define R_SCSI1_STATUS__curr_phase__BITNR 11 -#define R_SCSI1_STATUS__curr_phase__WIDTH 3 -#define R_SCSI1_STATUS__curr_phase__ph_undef 0 -#define R_SCSI1_STATUS__curr_phase__ph_msg_in 7 -#define R_SCSI1_STATUS__curr_phase__ph_msg_out 6 -#define R_SCSI1_STATUS__curr_phase__ph_status 3 -#define R_SCSI1_STATUS__curr_phase__ph_command 2 -#define R_SCSI1_STATUS__curr_phase__ph_data_in 5 -#define R_SCSI1_STATUS__curr_phase__ph_data_out 4 -#define R_SCSI1_STATUS__curr_phase__ph_resel 1 -#define R_SCSI1_STATUS__last_seq_step__BITNR 6 -#define R_SCSI1_STATUS__last_seq_step__WIDTH 5 -#define R_SCSI1_STATUS__last_seq_step__st_bus_free 24 -#define R_SCSI1_STATUS__last_seq_step__st_arbitrate 8 -#define R_SCSI1_STATUS__last_seq_step__st_resel_req 29 -#define R_SCSI1_STATUS__last_seq_step__st_msg_1 2 -#define R_SCSI1_STATUS__last_seq_step__st_manual 28 -#define R_SCSI1_STATUS__last_seq_step__st_transf_cmd 30 -#define R_SCSI1_STATUS__last_seq_step__st_msg_2 6 -#define R_SCSI1_STATUS__last_seq_step__st_msg_3 22 -#define R_SCSI1_STATUS__last_seq_step__st_answer 3 -#define R_SCSI1_STATUS__last_seq_step__st_synch_din_perr 1 -#define R_SCSI1_STATUS__last_seq_step__st_transfer_done 15 -#define R_SCSI1_STATUS__last_seq_step__st_synch_dout 0 -#define R_SCSI1_STATUS__last_seq_step__st_asynch_dout 25 -#define R_SCSI1_STATUS__last_seq_step__st_synch_din 13 -#define R_SCSI1_STATUS__last_seq_step__st_asynch_din 9 -#define R_SCSI1_STATUS__last_seq_step__st_synch_dout_ack 4 -#define R_SCSI1_STATUS__last_seq_step__st_synch_din_ack 12 -#define R_SCSI1_STATUS__last_seq_step__st_synch_din_ack_perr 5 -#define R_SCSI1_STATUS__last_seq_step__st_asynch_dout_end 11 -#define R_SCSI1_STATUS__last_seq_step__st_iwr 27 -#define R_SCSI1_STATUS__last_seq_step__st_wait_free_disc 21 -#define R_SCSI1_STATUS__last_seq_step__st_sdp_disc 7 -#define R_SCSI1_STATUS__last_seq_step__st_cc 31 -#define R_SCSI1_STATUS__last_seq_step__st_iwr_good 14 -#define R_SCSI1_STATUS__last_seq_step__st_iwr_cc 23 -#define R_SCSI1_STATUS__last_seq_step__st_wait_free_iwr_cc 17 -#define R_SCSI1_STATUS__last_seq_step__st_wait_free_cc 20 -#define R_SCSI1_STATUS__last_seq_step__st_wait_free_sdp_disc 16 -#define R_SCSI1_STATUS__last_seq_step__st_manual_req 10 -#define R_SCSI1_STATUS__last_seq_step__st_manual_din_prot 18 -#define R_SCSI1_STATUS__valid_status__BITNR 5 -#define R_SCSI1_STATUS__valid_status__WIDTH 1 -#define R_SCSI1_STATUS__valid_status__yes 1 -#define R_SCSI1_STATUS__valid_status__no 0 -#define R_SCSI1_STATUS__seq_status__BITNR 0 -#define R_SCSI1_STATUS__seq_status__WIDTH 5 -#define R_SCSI1_STATUS__seq_status__info_seq_complete 0 -#define R_SCSI1_STATUS__seq_status__info_parity_error 1 -#define R_SCSI1_STATUS__seq_status__info_unhandled_msg_in 2 -#define R_SCSI1_STATUS__seq_status__info_unexp_ph_change 3 -#define R_SCSI1_STATUS__seq_status__info_arb_lost 4 -#define R_SCSI1_STATUS__seq_status__info_sel_timeout 5 -#define R_SCSI1_STATUS__seq_status__info_unexp_bf 6 -#define R_SCSI1_STATUS__seq_status__info_illegal_op 7 -#define R_SCSI1_STATUS__seq_status__info_rec_recvd 8 -#define R_SCSI1_STATUS__seq_status__info_reselected 9 -#define R_SCSI1_STATUS__seq_status__info_unhandled_status 10 -#define R_SCSI1_STATUS__seq_status__info_bus_reset 11 -#define R_SCSI1_STATUS__seq_status__info_illegal_bf 12 -#define R_SCSI1_STATUS__seq_status__info_bus_free 13 - -#define R_SCSI1_DATA_IN (IO_TYPECAST_RO_UWORD 0xb0000050) -#define R_SCSI1_DATA_IN__data_in__BITNR 0 -#define R_SCSI1_DATA_IN__data_in__WIDTH 16 - -/* -!* Interrupt mask and status registers -!*/ - -#define R_IRQ_MASK0_RD (IO_TYPECAST_RO_UDWORD 0xb00000c0) -#define R_IRQ_MASK0_RD__nmi_pin__BITNR 31 -#define R_IRQ_MASK0_RD__nmi_pin__WIDTH 1 -#define R_IRQ_MASK0_RD__nmi_pin__active 1 -#define R_IRQ_MASK0_RD__nmi_pin__inactive 0 -#define R_IRQ_MASK0_RD__watchdog_nmi__BITNR 30 -#define R_IRQ_MASK0_RD__watchdog_nmi__WIDTH 1 -#define R_IRQ_MASK0_RD__watchdog_nmi__active 1 -#define R_IRQ_MASK0_RD__watchdog_nmi__inactive 0 -#define R_IRQ_MASK0_RD__sqe_test_error__BITNR 29 -#define R_IRQ_MASK0_RD__sqe_test_error__WIDTH 1 -#define R_IRQ_MASK0_RD__sqe_test_error__active 1 -#define R_IRQ_MASK0_RD__sqe_test_error__inactive 0 -#define R_IRQ_MASK0_RD__carrier_loss__BITNR 28 -#define R_IRQ_MASK0_RD__carrier_loss__WIDTH 1 -#define R_IRQ_MASK0_RD__carrier_loss__active 1 -#define R_IRQ_MASK0_RD__carrier_loss__inactive 0 -#define R_IRQ_MASK0_RD__deferred__BITNR 27 -#define R_IRQ_MASK0_RD__deferred__WIDTH 1 -#define R_IRQ_MASK0_RD__deferred__active 1 -#define R_IRQ_MASK0_RD__deferred__inactive 0 -#define R_IRQ_MASK0_RD__late_col__BITNR 26 -#define R_IRQ_MASK0_RD__late_col__WIDTH 1 -#define R_IRQ_MASK0_RD__late_col__active 1 -#define R_IRQ_MASK0_RD__late_col__inactive 0 -#define R_IRQ_MASK0_RD__multiple_col__BITNR 25 -#define R_IRQ_MASK0_RD__multiple_col__WIDTH 1 -#define R_IRQ_MASK0_RD__multiple_col__active 1 -#define R_IRQ_MASK0_RD__multiple_col__inactive 0 -#define R_IRQ_MASK0_RD__single_col__BITNR 24 -#define R_IRQ_MASK0_RD__single_col__WIDTH 1 -#define R_IRQ_MASK0_RD__single_col__active 1 -#define R_IRQ_MASK0_RD__single_col__inactive 0 -#define R_IRQ_MASK0_RD__congestion__BITNR 23 -#define R_IRQ_MASK0_RD__congestion__WIDTH 1 -#define R_IRQ_MASK0_RD__congestion__active 1 -#define R_IRQ_MASK0_RD__congestion__inactive 0 -#define R_IRQ_MASK0_RD__oversize__BITNR 22 -#define R_IRQ_MASK0_RD__oversize__WIDTH 1 -#define R_IRQ_MASK0_RD__oversize__active 1 -#define R_IRQ_MASK0_RD__oversize__inactive 0 -#define R_IRQ_MASK0_RD__alignment_error__BITNR 21 -#define R_IRQ_MASK0_RD__alignment_error__WIDTH 1 -#define R_IRQ_MASK0_RD__alignment_error__active 1 -#define R_IRQ_MASK0_RD__alignment_error__inactive 0 -#define R_IRQ_MASK0_RD__crc_error__BITNR 20 -#define R_IRQ_MASK0_RD__crc_error__WIDTH 1 -#define R_IRQ_MASK0_RD__crc_error__active 1 -#define R_IRQ_MASK0_RD__crc_error__inactive 0 -#define R_IRQ_MASK0_RD__overrun__BITNR 19 -#define R_IRQ_MASK0_RD__overrun__WIDTH 1 -#define R_IRQ_MASK0_RD__overrun__active 1 -#define R_IRQ_MASK0_RD__overrun__inactive 0 -#define R_IRQ_MASK0_RD__underrun__BITNR 18 -#define R_IRQ_MASK0_RD__underrun__WIDTH 1 -#define R_IRQ_MASK0_RD__underrun__active 1 -#define R_IRQ_MASK0_RD__underrun__inactive 0 -#define R_IRQ_MASK0_RD__excessive_col__BITNR 17 -#define R_IRQ_MASK0_RD__excessive_col__WIDTH 1 -#define R_IRQ_MASK0_RD__excessive_col__active 1 -#define R_IRQ_MASK0_RD__excessive_col__inactive 0 -#define R_IRQ_MASK0_RD__mdio__BITNR 16 -#define R_IRQ_MASK0_RD__mdio__WIDTH 1 -#define R_IRQ_MASK0_RD__mdio__active 1 -#define R_IRQ_MASK0_RD__mdio__inactive 0 -#define R_IRQ_MASK0_RD__ata_drq3__BITNR 15 -#define R_IRQ_MASK0_RD__ata_drq3__WIDTH 1 -#define R_IRQ_MASK0_RD__ata_drq3__active 1 -#define R_IRQ_MASK0_RD__ata_drq3__inactive 0 -#define R_IRQ_MASK0_RD__ata_drq2__BITNR 14 -#define R_IRQ_MASK0_RD__ata_drq2__WIDTH 1 -#define R_IRQ_MASK0_RD__ata_drq2__active 1 -#define R_IRQ_MASK0_RD__ata_drq2__inactive 0 -#define R_IRQ_MASK0_RD__ata_drq1__BITNR 13 -#define R_IRQ_MASK0_RD__ata_drq1__WIDTH 1 -#define R_IRQ_MASK0_RD__ata_drq1__active 1 -#define R_IRQ_MASK0_RD__ata_drq1__inactive 0 -#define R_IRQ_MASK0_RD__ata_drq0__BITNR 12 -#define R_IRQ_MASK0_RD__ata_drq0__WIDTH 1 -#define R_IRQ_MASK0_RD__ata_drq0__active 1 -#define R_IRQ_MASK0_RD__ata_drq0__inactive 0 -#define R_IRQ_MASK0_RD__par0_ecp_cmd__BITNR 11 -#define R_IRQ_MASK0_RD__par0_ecp_cmd__WIDTH 1 -#define R_IRQ_MASK0_RD__par0_ecp_cmd__active 1 -#define R_IRQ_MASK0_RD__par0_ecp_cmd__inactive 0 -#define R_IRQ_MASK0_RD__ata_irq3__BITNR 11 -#define R_IRQ_MASK0_RD__ata_irq3__WIDTH 1 -#define R_IRQ_MASK0_RD__ata_irq3__active 1 -#define R_IRQ_MASK0_RD__ata_irq3__inactive 0 -#define R_IRQ_MASK0_RD__par0_peri__BITNR 10 -#define R_IRQ_MASK0_RD__par0_peri__WIDTH 1 -#define R_IRQ_MASK0_RD__par0_peri__active 1 -#define R_IRQ_MASK0_RD__par0_peri__inactive 0 -#define R_IRQ_MASK0_RD__ata_irq2__BITNR 10 -#define R_IRQ_MASK0_RD__ata_irq2__WIDTH 1 -#define R_IRQ_MASK0_RD__ata_irq2__active 1 -#define R_IRQ_MASK0_RD__ata_irq2__inactive 0 -#define R_IRQ_MASK0_RD__par0_data__BITNR 9 -#define R_IRQ_MASK0_RD__par0_data__WIDTH 1 -#define R_IRQ_MASK0_RD__par0_data__active 1 -#define R_IRQ_MASK0_RD__par0_data__inactive 0 -#define R_IRQ_MASK0_RD__ata_irq1__BITNR 9 -#define R_IRQ_MASK0_RD__ata_irq1__WIDTH 1 -#define R_IRQ_MASK0_RD__ata_irq1__active 1 -#define R_IRQ_MASK0_RD__ata_irq1__inactive 0 -#define R_IRQ_MASK0_RD__par0_ready__BITNR 8 -#define R_IRQ_MASK0_RD__par0_ready__WIDTH 1 -#define R_IRQ_MASK0_RD__par0_ready__active 1 -#define R_IRQ_MASK0_RD__par0_ready__inactive 0 -#define R_IRQ_MASK0_RD__ata_irq0__BITNR 8 -#define R_IRQ_MASK0_RD__ata_irq0__WIDTH 1 -#define R_IRQ_MASK0_RD__ata_irq0__active 1 -#define R_IRQ_MASK0_RD__ata_irq0__inactive 0 -#define R_IRQ_MASK0_RD__mio__BITNR 8 -#define R_IRQ_MASK0_RD__mio__WIDTH 1 -#define R_IRQ_MASK0_RD__mio__active 1 -#define R_IRQ_MASK0_RD__mio__inactive 0 -#define R_IRQ_MASK0_RD__scsi0__BITNR 8 -#define R_IRQ_MASK0_RD__scsi0__WIDTH 1 -#define R_IRQ_MASK0_RD__scsi0__active 1 -#define R_IRQ_MASK0_RD__scsi0__inactive 0 -#define R_IRQ_MASK0_RD__ata_dmaend__BITNR 7 -#define R_IRQ_MASK0_RD__ata_dmaend__WIDTH 1 -#define R_IRQ_MASK0_RD__ata_dmaend__active 1 -#define R_IRQ_MASK0_RD__ata_dmaend__inactive 0 -#define R_IRQ_MASK0_RD__irq_ext_vector_nr__BITNR 5 -#define R_IRQ_MASK0_RD__irq_ext_vector_nr__WIDTH 1 -#define R_IRQ_MASK0_RD__irq_ext_vector_nr__active 1 -#define R_IRQ_MASK0_RD__irq_ext_vector_nr__inactive 0 -#define R_IRQ_MASK0_RD__irq_int_vector_nr__BITNR 4 -#define R_IRQ_MASK0_RD__irq_int_vector_nr__WIDTH 1 -#define R_IRQ_MASK0_RD__irq_int_vector_nr__active 1 -#define R_IRQ_MASK0_RD__irq_int_vector_nr__inactive 0 -#define R_IRQ_MASK0_RD__ext_dma1__BITNR 3 -#define R_IRQ_MASK0_RD__ext_dma1__WIDTH 1 -#define R_IRQ_MASK0_RD__ext_dma1__active 1 -#define R_IRQ_MASK0_RD__ext_dma1__inactive 0 -#define R_IRQ_MASK0_RD__ext_dma0__BITNR 2 -#define R_IRQ_MASK0_RD__ext_dma0__WIDTH 1 -#define R_IRQ_MASK0_RD__ext_dma0__active 1 -#define R_IRQ_MASK0_RD__ext_dma0__inactive 0 -#define R_IRQ_MASK0_RD__timer1__BITNR 1 -#define R_IRQ_MASK0_RD__timer1__WIDTH 1 -#define R_IRQ_MASK0_RD__timer1__active 1 -#define R_IRQ_MASK0_RD__timer1__inactive 0 -#define R_IRQ_MASK0_RD__timer0__BITNR 0 -#define R_IRQ_MASK0_RD__timer0__WIDTH 1 -#define R_IRQ_MASK0_RD__timer0__active 1 -#define R_IRQ_MASK0_RD__timer0__inactive 0 - -#define R_IRQ_MASK0_CLR (IO_TYPECAST_UDWORD 0xb00000c0) -#define R_IRQ_MASK0_CLR__nmi_pin__BITNR 31 -#define R_IRQ_MASK0_CLR__nmi_pin__WIDTH 1 -#define R_IRQ_MASK0_CLR__nmi_pin__clr 1 -#define R_IRQ_MASK0_CLR__nmi_pin__nop 0 -#define R_IRQ_MASK0_CLR__watchdog_nmi__BITNR 30 -#define R_IRQ_MASK0_CLR__watchdog_nmi__WIDTH 1 -#define R_IRQ_MASK0_CLR__watchdog_nmi__clr 1 -#define R_IRQ_MASK0_CLR__watchdog_nmi__nop 0 -#define R_IRQ_MASK0_CLR__sqe_test_error__BITNR 29 -#define R_IRQ_MASK0_CLR__sqe_test_error__WIDTH 1 -#define R_IRQ_MASK0_CLR__sqe_test_error__clr 1 -#define R_IRQ_MASK0_CLR__sqe_test_error__nop 0 -#define R_IRQ_MASK0_CLR__carrier_loss__BITNR 28 -#define R_IRQ_MASK0_CLR__carrier_loss__WIDTH 1 -#define R_IRQ_MASK0_CLR__carrier_loss__clr 1 -#define R_IRQ_MASK0_CLR__carrier_loss__nop 0 -#define R_IRQ_MASK0_CLR__deferred__BITNR 27 -#define R_IRQ_MASK0_CLR__deferred__WIDTH 1 -#define R_IRQ_MASK0_CLR__deferred__clr 1 -#define R_IRQ_MASK0_CLR__deferred__nop 0 -#define R_IRQ_MASK0_CLR__late_col__BITNR 26 -#define R_IRQ_MASK0_CLR__late_col__WIDTH 1 -#define R_IRQ_MASK0_CLR__late_col__clr 1 -#define R_IRQ_MASK0_CLR__late_col__nop 0 -#define R_IRQ_MASK0_CLR__multiple_col__BITNR 25 -#define R_IRQ_MASK0_CLR__multiple_col__WIDTH 1 -#define R_IRQ_MASK0_CLR__multiple_col__clr 1 -#define R_IRQ_MASK0_CLR__multiple_col__nop 0 -#define R_IRQ_MASK0_CLR__single_col__BITNR 24 -#define R_IRQ_MASK0_CLR__single_col__WIDTH 1 -#define R_IRQ_MASK0_CLR__single_col__clr 1 -#define R_IRQ_MASK0_CLR__single_col__nop 0 -#define R_IRQ_MASK0_CLR__congestion__BITNR 23 -#define R_IRQ_MASK0_CLR__congestion__WIDTH 1 -#define R_IRQ_MASK0_CLR__congestion__clr 1 -#define R_IRQ_MASK0_CLR__congestion__nop 0 -#define R_IRQ_MASK0_CLR__oversize__BITNR 22 -#define R_IRQ_MASK0_CLR__oversize__WIDTH 1 -#define R_IRQ_MASK0_CLR__oversize__clr 1 -#define R_IRQ_MASK0_CLR__oversize__nop 0 -#define R_IRQ_MASK0_CLR__alignment_error__BITNR 21 -#define R_IRQ_MASK0_CLR__alignment_error__WIDTH 1 -#define R_IRQ_MASK0_CLR__alignment_error__clr 1 -#define R_IRQ_MASK0_CLR__alignment_error__nop 0 -#define R_IRQ_MASK0_CLR__crc_error__BITNR 20 -#define R_IRQ_MASK0_CLR__crc_error__WIDTH 1 -#define R_IRQ_MASK0_CLR__crc_error__clr 1 -#define R_IRQ_MASK0_CLR__crc_error__nop 0 -#define R_IRQ_MASK0_CLR__overrun__BITNR 19 -#define R_IRQ_MASK0_CLR__overrun__WIDTH 1 -#define R_IRQ_MASK0_CLR__overrun__clr 1 -#define R_IRQ_MASK0_CLR__overrun__nop 0 -#define R_IRQ_MASK0_CLR__underrun__BITNR 18 -#define R_IRQ_MASK0_CLR__underrun__WIDTH 1 -#define R_IRQ_MASK0_CLR__underrun__clr 1 -#define R_IRQ_MASK0_CLR__underrun__nop 0 -#define R_IRQ_MASK0_CLR__excessive_col__BITNR 17 -#define R_IRQ_MASK0_CLR__excessive_col__WIDTH 1 -#define R_IRQ_MASK0_CLR__excessive_col__clr 1 -#define R_IRQ_MASK0_CLR__excessive_col__nop 0 -#define R_IRQ_MASK0_CLR__mdio__BITNR 16 -#define R_IRQ_MASK0_CLR__mdio__WIDTH 1 -#define R_IRQ_MASK0_CLR__mdio__clr 1 -#define R_IRQ_MASK0_CLR__mdio__nop 0 -#define R_IRQ_MASK0_CLR__ata_drq3__BITNR 15 -#define R_IRQ_MASK0_CLR__ata_drq3__WIDTH 1 -#define R_IRQ_MASK0_CLR__ata_drq3__clr 1 -#define R_IRQ_MASK0_CLR__ata_drq3__nop 0 -#define R_IRQ_MASK0_CLR__ata_drq2__BITNR 14 -#define R_IRQ_MASK0_CLR__ata_drq2__WIDTH 1 -#define R_IRQ_MASK0_CLR__ata_drq2__clr 1 -#define R_IRQ_MASK0_CLR__ata_drq2__nop 0 -#define R_IRQ_MASK0_CLR__ata_drq1__BITNR 13 -#define R_IRQ_MASK0_CLR__ata_drq1__WIDTH 1 -#define R_IRQ_MASK0_CLR__ata_drq1__clr 1 -#define R_IRQ_MASK0_CLR__ata_drq1__nop 0 -#define R_IRQ_MASK0_CLR__ata_drq0__BITNR 12 -#define R_IRQ_MASK0_CLR__ata_drq0__WIDTH 1 -#define R_IRQ_MASK0_CLR__ata_drq0__clr 1 -#define R_IRQ_MASK0_CLR__ata_drq0__nop 0 -#define R_IRQ_MASK0_CLR__par0_ecp_cmd__BITNR 11 -#define R_IRQ_MASK0_CLR__par0_ecp_cmd__WIDTH 1 -#define R_IRQ_MASK0_CLR__par0_ecp_cmd__clr 1 -#define R_IRQ_MASK0_CLR__par0_ecp_cmd__nop 0 -#define R_IRQ_MASK0_CLR__ata_irq3__BITNR 11 -#define R_IRQ_MASK0_CLR__ata_irq3__WIDTH 1 -#define R_IRQ_MASK0_CLR__ata_irq3__clr 1 -#define R_IRQ_MASK0_CLR__ata_irq3__nop 0 -#define R_IRQ_MASK0_CLR__par0_peri__BITNR 10 -#define R_IRQ_MASK0_CLR__par0_peri__WIDTH 1 -#define R_IRQ_MASK0_CLR__par0_peri__clr 1 -#define R_IRQ_MASK0_CLR__par0_peri__nop 0 -#define R_IRQ_MASK0_CLR__ata_irq2__BITNR 10 -#define R_IRQ_MASK0_CLR__ata_irq2__WIDTH 1 -#define R_IRQ_MASK0_CLR__ata_irq2__clr 1 -#define R_IRQ_MASK0_CLR__ata_irq2__nop 0 -#define R_IRQ_MASK0_CLR__par0_data__BITNR 9 -#define R_IRQ_MASK0_CLR__par0_data__WIDTH 1 -#define R_IRQ_MASK0_CLR__par0_data__clr 1 -#define R_IRQ_MASK0_CLR__par0_data__nop 0 -#define R_IRQ_MASK0_CLR__ata_irq1__BITNR 9 -#define R_IRQ_MASK0_CLR__ata_irq1__WIDTH 1 -#define R_IRQ_MASK0_CLR__ata_irq1__clr 1 -#define R_IRQ_MASK0_CLR__ata_irq1__nop 0 -#define R_IRQ_MASK0_CLR__par0_ready__BITNR 8 -#define R_IRQ_MASK0_CLR__par0_ready__WIDTH 1 -#define R_IRQ_MASK0_CLR__par0_ready__clr 1 -#define R_IRQ_MASK0_CLR__par0_ready__nop 0 -#define R_IRQ_MASK0_CLR__ata_irq0__BITNR 8 -#define R_IRQ_MASK0_CLR__ata_irq0__WIDTH 1 -#define R_IRQ_MASK0_CLR__ata_irq0__clr 1 -#define R_IRQ_MASK0_CLR__ata_irq0__nop 0 -#define R_IRQ_MASK0_CLR__mio__BITNR 8 -#define R_IRQ_MASK0_CLR__mio__WIDTH 1 -#define R_IRQ_MASK0_CLR__mio__clr 1 -#define R_IRQ_MASK0_CLR__mio__nop 0 -#define R_IRQ_MASK0_CLR__scsi0__BITNR 8 -#define R_IRQ_MASK0_CLR__scsi0__WIDTH 1 -#define R_IRQ_MASK0_CLR__scsi0__clr 1 -#define R_IRQ_MASK0_CLR__scsi0__nop 0 -#define R_IRQ_MASK0_CLR__ata_dmaend__BITNR 7 -#define R_IRQ_MASK0_CLR__ata_dmaend__WIDTH 1 -#define R_IRQ_MASK0_CLR__ata_dmaend__clr 1 -#define R_IRQ_MASK0_CLR__ata_dmaend__nop 0 -#define R_IRQ_MASK0_CLR__irq_ext_vector_nr__BITNR 5 -#define R_IRQ_MASK0_CLR__irq_ext_vector_nr__WIDTH 1 -#define R_IRQ_MASK0_CLR__irq_ext_vector_nr__clr 1 -#define R_IRQ_MASK0_CLR__irq_ext_vector_nr__nop 0 -#define R_IRQ_MASK0_CLR__irq_int_vector_nr__BITNR 4 -#define R_IRQ_MASK0_CLR__irq_int_vector_nr__WIDTH 1 -#define R_IRQ_MASK0_CLR__irq_int_vector_nr__clr 1 -#define R_IRQ_MASK0_CLR__irq_int_vector_nr__nop 0 -#define R_IRQ_MASK0_CLR__ext_dma1__BITNR 3 -#define R_IRQ_MASK0_CLR__ext_dma1__WIDTH 1 -#define R_IRQ_MASK0_CLR__ext_dma1__clr 1 -#define R_IRQ_MASK0_CLR__ext_dma1__nop 0 -#define R_IRQ_MASK0_CLR__ext_dma0__BITNR 2 -#define R_IRQ_MASK0_CLR__ext_dma0__WIDTH 1 -#define R_IRQ_MASK0_CLR__ext_dma0__clr 1 -#define R_IRQ_MASK0_CLR__ext_dma0__nop 0 -#define R_IRQ_MASK0_CLR__timer1__BITNR 1 -#define R_IRQ_MASK0_CLR__timer1__WIDTH 1 -#define R_IRQ_MASK0_CLR__timer1__clr 1 -#define R_IRQ_MASK0_CLR__timer1__nop 0 -#define R_IRQ_MASK0_CLR__timer0__BITNR 0 -#define R_IRQ_MASK0_CLR__timer0__WIDTH 1 -#define R_IRQ_MASK0_CLR__timer0__clr 1 -#define R_IRQ_MASK0_CLR__timer0__nop 0 - -#define R_IRQ_READ0 (IO_TYPECAST_RO_UDWORD 0xb00000c4) -#define R_IRQ_READ0__nmi_pin__BITNR 31 -#define R_IRQ_READ0__nmi_pin__WIDTH 1 -#define R_IRQ_READ0__nmi_pin__active 1 -#define R_IRQ_READ0__nmi_pin__inactive 0 -#define R_IRQ_READ0__watchdog_nmi__BITNR 30 -#define R_IRQ_READ0__watchdog_nmi__WIDTH 1 -#define R_IRQ_READ0__watchdog_nmi__active 1 -#define R_IRQ_READ0__watchdog_nmi__inactive 0 -#define R_IRQ_READ0__sqe_test_error__BITNR 29 -#define R_IRQ_READ0__sqe_test_error__WIDTH 1 -#define R_IRQ_READ0__sqe_test_error__active 1 -#define R_IRQ_READ0__sqe_test_error__inactive 0 -#define R_IRQ_READ0__carrier_loss__BITNR 28 -#define R_IRQ_READ0__carrier_loss__WIDTH 1 -#define R_IRQ_READ0__carrier_loss__active 1 -#define R_IRQ_READ0__carrier_loss__inactive 0 -#define R_IRQ_READ0__deferred__BITNR 27 -#define R_IRQ_READ0__deferred__WIDTH 1 -#define R_IRQ_READ0__deferred__active 1 -#define R_IRQ_READ0__deferred__inactive 0 -#define R_IRQ_READ0__late_col__BITNR 26 -#define R_IRQ_READ0__late_col__WIDTH 1 -#define R_IRQ_READ0__late_col__active 1 -#define R_IRQ_READ0__late_col__inactive 0 -#define R_IRQ_READ0__multiple_col__BITNR 25 -#define R_IRQ_READ0__multiple_col__WIDTH 1 -#define R_IRQ_READ0__multiple_col__active 1 -#define R_IRQ_READ0__multiple_col__inactive 0 -#define R_IRQ_READ0__single_col__BITNR 24 -#define R_IRQ_READ0__single_col__WIDTH 1 -#define R_IRQ_READ0__single_col__active 1 -#define R_IRQ_READ0__single_col__inactive 0 -#define R_IRQ_READ0__congestion__BITNR 23 -#define R_IRQ_READ0__congestion__WIDTH 1 -#define R_IRQ_READ0__congestion__active 1 -#define R_IRQ_READ0__congestion__inactive 0 -#define R_IRQ_READ0__oversize__BITNR 22 -#define R_IRQ_READ0__oversize__WIDTH 1 -#define R_IRQ_READ0__oversize__active 1 -#define R_IRQ_READ0__oversize__inactive 0 -#define R_IRQ_READ0__alignment_error__BITNR 21 -#define R_IRQ_READ0__alignment_error__WIDTH 1 -#define R_IRQ_READ0__alignment_error__active 1 -#define R_IRQ_READ0__alignment_error__inactive 0 -#define R_IRQ_READ0__crc_error__BITNR 20 -#define R_IRQ_READ0__crc_error__WIDTH 1 -#define R_IRQ_READ0__crc_error__active 1 -#define R_IRQ_READ0__crc_error__inactive 0 -#define R_IRQ_READ0__overrun__BITNR 19 -#define R_IRQ_READ0__overrun__WIDTH 1 -#define R_IRQ_READ0__overrun__active 1 -#define R_IRQ_READ0__overrun__inactive 0 -#define R_IRQ_READ0__underrun__BITNR 18 -#define R_IRQ_READ0__underrun__WIDTH 1 -#define R_IRQ_READ0__underrun__active 1 -#define R_IRQ_READ0__underrun__inactive 0 -#define R_IRQ_READ0__excessive_col__BITNR 17 -#define R_IRQ_READ0__excessive_col__WIDTH 1 -#define R_IRQ_READ0__excessive_col__active 1 -#define R_IRQ_READ0__excessive_col__inactive 0 -#define R_IRQ_READ0__mdio__BITNR 16 -#define R_IRQ_READ0__mdio__WIDTH 1 -#define R_IRQ_READ0__mdio__active 1 -#define R_IRQ_READ0__mdio__inactive 0 -#define R_IRQ_READ0__ata_drq3__BITNR 15 -#define R_IRQ_READ0__ata_drq3__WIDTH 1 -#define R_IRQ_READ0__ata_drq3__active 1 -#define R_IRQ_READ0__ata_drq3__inactive 0 -#define R_IRQ_READ0__ata_drq2__BITNR 14 -#define R_IRQ_READ0__ata_drq2__WIDTH 1 -#define R_IRQ_READ0__ata_drq2__active 1 -#define R_IRQ_READ0__ata_drq2__inactive 0 -#define R_IRQ_READ0__ata_drq1__BITNR 13 -#define R_IRQ_READ0__ata_drq1__WIDTH 1 -#define R_IRQ_READ0__ata_drq1__active 1 -#define R_IRQ_READ0__ata_drq1__inactive 0 -#define R_IRQ_READ0__ata_drq0__BITNR 12 -#define R_IRQ_READ0__ata_drq0__WIDTH 1 -#define R_IRQ_READ0__ata_drq0__active 1 -#define R_IRQ_READ0__ata_drq0__inactive 0 -#define R_IRQ_READ0__par0_ecp_cmd__BITNR 11 -#define R_IRQ_READ0__par0_ecp_cmd__WIDTH 1 -#define R_IRQ_READ0__par0_ecp_cmd__active 1 -#define R_IRQ_READ0__par0_ecp_cmd__inactive 0 -#define R_IRQ_READ0__ata_irq3__BITNR 11 -#define R_IRQ_READ0__ata_irq3__WIDTH 1 -#define R_IRQ_READ0__ata_irq3__active 1 -#define R_IRQ_READ0__ata_irq3__inactive 0 -#define R_IRQ_READ0__par0_peri__BITNR 10 -#define R_IRQ_READ0__par0_peri__WIDTH 1 -#define R_IRQ_READ0__par0_peri__active 1 -#define R_IRQ_READ0__par0_peri__inactive 0 -#define R_IRQ_READ0__ata_irq2__BITNR 10 -#define R_IRQ_READ0__ata_irq2__WIDTH 1 -#define R_IRQ_READ0__ata_irq2__active 1 -#define R_IRQ_READ0__ata_irq2__inactive 0 -#define R_IRQ_READ0__par0_data__BITNR 9 -#define R_IRQ_READ0__par0_data__WIDTH 1 -#define R_IRQ_READ0__par0_data__active 1 -#define R_IRQ_READ0__par0_data__inactive 0 -#define R_IRQ_READ0__ata_irq1__BITNR 9 -#define R_IRQ_READ0__ata_irq1__WIDTH 1 -#define R_IRQ_READ0__ata_irq1__active 1 -#define R_IRQ_READ0__ata_irq1__inactive 0 -#define R_IRQ_READ0__par0_ready__BITNR 8 -#define R_IRQ_READ0__par0_ready__WIDTH 1 -#define R_IRQ_READ0__par0_ready__active 1 -#define R_IRQ_READ0__par0_ready__inactive 0 -#define R_IRQ_READ0__ata_irq0__BITNR 8 -#define R_IRQ_READ0__ata_irq0__WIDTH 1 -#define R_IRQ_READ0__ata_irq0__active 1 -#define R_IRQ_READ0__ata_irq0__inactive 0 -#define R_IRQ_READ0__mio__BITNR 8 -#define R_IRQ_READ0__mio__WIDTH 1 -#define R_IRQ_READ0__mio__active 1 -#define R_IRQ_READ0__mio__inactive 0 -#define R_IRQ_READ0__scsi0__BITNR 8 -#define R_IRQ_READ0__scsi0__WIDTH 1 -#define R_IRQ_READ0__scsi0__active 1 -#define R_IRQ_READ0__scsi0__inactive 0 -#define R_IRQ_READ0__ata_dmaend__BITNR 7 -#define R_IRQ_READ0__ata_dmaend__WIDTH 1 -#define R_IRQ_READ0__ata_dmaend__active 1 -#define R_IRQ_READ0__ata_dmaend__inactive 0 -#define R_IRQ_READ0__irq_ext_vector_nr__BITNR 5 -#define R_IRQ_READ0__irq_ext_vector_nr__WIDTH 1 -#define R_IRQ_READ0__irq_ext_vector_nr__active 1 -#define R_IRQ_READ0__irq_ext_vector_nr__inactive 0 -#define R_IRQ_READ0__irq_int_vector_nr__BITNR 4 -#define R_IRQ_READ0__irq_int_vector_nr__WIDTH 1 -#define R_IRQ_READ0__irq_int_vector_nr__active 1 -#define R_IRQ_READ0__irq_int_vector_nr__inactive 0 -#define R_IRQ_READ0__ext_dma1__BITNR 3 -#define R_IRQ_READ0__ext_dma1__WIDTH 1 -#define R_IRQ_READ0__ext_dma1__active 1 -#define R_IRQ_READ0__ext_dma1__inactive 0 -#define R_IRQ_READ0__ext_dma0__BITNR 2 -#define R_IRQ_READ0__ext_dma0__WIDTH 1 -#define R_IRQ_READ0__ext_dma0__active 1 -#define R_IRQ_READ0__ext_dma0__inactive 0 -#define R_IRQ_READ0__timer1__BITNR 1 -#define R_IRQ_READ0__timer1__WIDTH 1 -#define R_IRQ_READ0__timer1__active 1 -#define R_IRQ_READ0__timer1__inactive 0 -#define R_IRQ_READ0__timer0__BITNR 0 -#define R_IRQ_READ0__timer0__WIDTH 1 -#define R_IRQ_READ0__timer0__active 1 -#define R_IRQ_READ0__timer0__inactive 0 - -#define R_IRQ_MASK0_SET (IO_TYPECAST_UDWORD 0xb00000c4) -#define R_IRQ_MASK0_SET__nmi_pin__BITNR 31 -#define R_IRQ_MASK0_SET__nmi_pin__WIDTH 1 -#define R_IRQ_MASK0_SET__nmi_pin__set 1 -#define R_IRQ_MASK0_SET__nmi_pin__nop 0 -#define R_IRQ_MASK0_SET__watchdog_nmi__BITNR 30 -#define R_IRQ_MASK0_SET__watchdog_nmi__WIDTH 1 -#define R_IRQ_MASK0_SET__watchdog_nmi__set 1 -#define R_IRQ_MASK0_SET__watchdog_nmi__nop 0 -#define R_IRQ_MASK0_SET__sqe_test_error__BITNR 29 -#define R_IRQ_MASK0_SET__sqe_test_error__WIDTH 1 -#define R_IRQ_MASK0_SET__sqe_test_error__set 1 -#define R_IRQ_MASK0_SET__sqe_test_error__nop 0 -#define R_IRQ_MASK0_SET__carrier_loss__BITNR 28 -#define R_IRQ_MASK0_SET__carrier_loss__WIDTH 1 -#define R_IRQ_MASK0_SET__carrier_loss__set 1 -#define R_IRQ_MASK0_SET__carrier_loss__nop 0 -#define R_IRQ_MASK0_SET__deferred__BITNR 27 -#define R_IRQ_MASK0_SET__deferred__WIDTH 1 -#define R_IRQ_MASK0_SET__deferred__set 1 -#define R_IRQ_MASK0_SET__deferred__nop 0 -#define R_IRQ_MASK0_SET__late_col__BITNR 26 -#define R_IRQ_MASK0_SET__late_col__WIDTH 1 -#define R_IRQ_MASK0_SET__late_col__set 1 -#define R_IRQ_MASK0_SET__late_col__nop 0 -#define R_IRQ_MASK0_SET__multiple_col__BITNR 25 -#define R_IRQ_MASK0_SET__multiple_col__WIDTH 1 -#define R_IRQ_MASK0_SET__multiple_col__set 1 -#define R_IRQ_MASK0_SET__multiple_col__nop 0 -#define R_IRQ_MASK0_SET__single_col__BITNR 24 -#define R_IRQ_MASK0_SET__single_col__WIDTH 1 -#define R_IRQ_MASK0_SET__single_col__set 1 -#define R_IRQ_MASK0_SET__single_col__nop 0 -#define R_IRQ_MASK0_SET__congestion__BITNR 23 -#define R_IRQ_MASK0_SET__congestion__WIDTH 1 -#define R_IRQ_MASK0_SET__congestion__set 1 -#define R_IRQ_MASK0_SET__congestion__nop 0 -#define R_IRQ_MASK0_SET__oversize__BITNR 22 -#define R_IRQ_MASK0_SET__oversize__WIDTH 1 -#define R_IRQ_MASK0_SET__oversize__set 1 -#define R_IRQ_MASK0_SET__oversize__nop 0 -#define R_IRQ_MASK0_SET__alignment_error__BITNR 21 -#define R_IRQ_MASK0_SET__alignment_error__WIDTH 1 -#define R_IRQ_MASK0_SET__alignment_error__set 1 -#define R_IRQ_MASK0_SET__alignment_error__nop 0 -#define R_IRQ_MASK0_SET__crc_error__BITNR 20 -#define R_IRQ_MASK0_SET__crc_error__WIDTH 1 -#define R_IRQ_MASK0_SET__crc_error__set 1 -#define R_IRQ_MASK0_SET__crc_error__nop 0 -#define R_IRQ_MASK0_SET__overrun__BITNR 19 -#define R_IRQ_MASK0_SET__overrun__WIDTH 1 -#define R_IRQ_MASK0_SET__overrun__set 1 -#define R_IRQ_MASK0_SET__overrun__nop 0 -#define R_IRQ_MASK0_SET__underrun__BITNR 18 -#define R_IRQ_MASK0_SET__underrun__WIDTH 1 -#define R_IRQ_MASK0_SET__underrun__set 1 -#define R_IRQ_MASK0_SET__underrun__nop 0 -#define R_IRQ_MASK0_SET__excessive_col__BITNR 17 -#define R_IRQ_MASK0_SET__excessive_col__WIDTH 1 -#define R_IRQ_MASK0_SET__excessive_col__set 1 -#define R_IRQ_MASK0_SET__excessive_col__nop 0 -#define R_IRQ_MASK0_SET__mdio__BITNR 16 -#define R_IRQ_MASK0_SET__mdio__WIDTH 1 -#define R_IRQ_MASK0_SET__mdio__set 1 -#define R_IRQ_MASK0_SET__mdio__nop 0 -#define R_IRQ_MASK0_SET__ata_drq3__BITNR 15 -#define R_IRQ_MASK0_SET__ata_drq3__WIDTH 1 -#define R_IRQ_MASK0_SET__ata_drq3__set 1 -#define R_IRQ_MASK0_SET__ata_drq3__nop 0 -#define R_IRQ_MASK0_SET__ata_drq2__BITNR 14 -#define R_IRQ_MASK0_SET__ata_drq2__WIDTH 1 -#define R_IRQ_MASK0_SET__ata_drq2__set 1 -#define R_IRQ_MASK0_SET__ata_drq2__nop 0 -#define R_IRQ_MASK0_SET__ata_drq1__BITNR 13 -#define R_IRQ_MASK0_SET__ata_drq1__WIDTH 1 -#define R_IRQ_MASK0_SET__ata_drq1__set 1 -#define R_IRQ_MASK0_SET__ata_drq1__nop 0 -#define R_IRQ_MASK0_SET__ata_drq0__BITNR 12 -#define R_IRQ_MASK0_SET__ata_drq0__WIDTH 1 -#define R_IRQ_MASK0_SET__ata_drq0__set 1 -#define R_IRQ_MASK0_SET__ata_drq0__nop 0 -#define R_IRQ_MASK0_SET__par0_ecp_cmd__BITNR 11 -#define R_IRQ_MASK0_SET__par0_ecp_cmd__WIDTH 1 -#define R_IRQ_MASK0_SET__par0_ecp_cmd__set 1 -#define R_IRQ_MASK0_SET__par0_ecp_cmd__nop 0 -#define R_IRQ_MASK0_SET__ata_irq3__BITNR 11 -#define R_IRQ_MASK0_SET__ata_irq3__WIDTH 1 -#define R_IRQ_MASK0_SET__ata_irq3__set 1 -#define R_IRQ_MASK0_SET__ata_irq3__nop 0 -#define R_IRQ_MASK0_SET__par0_peri__BITNR 10 -#define R_IRQ_MASK0_SET__par0_peri__WIDTH 1 -#define R_IRQ_MASK0_SET__par0_peri__set 1 -#define R_IRQ_MASK0_SET__par0_peri__nop 0 -#define R_IRQ_MASK0_SET__ata_irq2__BITNR 10 -#define R_IRQ_MASK0_SET__ata_irq2__WIDTH 1 -#define R_IRQ_MASK0_SET__ata_irq2__set 1 -#define R_IRQ_MASK0_SET__ata_irq2__nop 0 -#define R_IRQ_MASK0_SET__par0_data__BITNR 9 -#define R_IRQ_MASK0_SET__par0_data__WIDTH 1 -#define R_IRQ_MASK0_SET__par0_data__set 1 -#define R_IRQ_MASK0_SET__par0_data__nop 0 -#define R_IRQ_MASK0_SET__ata_irq1__BITNR 9 -#define R_IRQ_MASK0_SET__ata_irq1__WIDTH 1 -#define R_IRQ_MASK0_SET__ata_irq1__set 1 -#define R_IRQ_MASK0_SET__ata_irq1__nop 0 -#define R_IRQ_MASK0_SET__par0_ready__BITNR 8 -#define R_IRQ_MASK0_SET__par0_ready__WIDTH 1 -#define R_IRQ_MASK0_SET__par0_ready__set 1 -#define R_IRQ_MASK0_SET__par0_ready__nop 0 -#define R_IRQ_MASK0_SET__ata_irq0__BITNR 8 -#define R_IRQ_MASK0_SET__ata_irq0__WIDTH 1 -#define R_IRQ_MASK0_SET__ata_irq0__set 1 -#define R_IRQ_MASK0_SET__ata_irq0__nop 0 -#define R_IRQ_MASK0_SET__mio__BITNR 8 -#define R_IRQ_MASK0_SET__mio__WIDTH 1 -#define R_IRQ_MASK0_SET__mio__set 1 -#define R_IRQ_MASK0_SET__mio__nop 0 -#define R_IRQ_MASK0_SET__scsi0__BITNR 8 -#define R_IRQ_MASK0_SET__scsi0__WIDTH 1 -#define R_IRQ_MASK0_SET__scsi0__set 1 -#define R_IRQ_MASK0_SET__scsi0__nop 0 -#define R_IRQ_MASK0_SET__ata_dmaend__BITNR 7 -#define R_IRQ_MASK0_SET__ata_dmaend__WIDTH 1 -#define R_IRQ_MASK0_SET__ata_dmaend__set 1 -#define R_IRQ_MASK0_SET__ata_dmaend__nop 0 -#define R_IRQ_MASK0_SET__irq_ext_vector_nr__BITNR 5 -#define R_IRQ_MASK0_SET__irq_ext_vector_nr__WIDTH 1 -#define R_IRQ_MASK0_SET__irq_ext_vector_nr__set 1 -#define R_IRQ_MASK0_SET__irq_ext_vector_nr__nop 0 -#define R_IRQ_MASK0_SET__irq_int_vector_nr__BITNR 4 -#define R_IRQ_MASK0_SET__irq_int_vector_nr__WIDTH 1 -#define R_IRQ_MASK0_SET__irq_int_vector_nr__set 1 -#define R_IRQ_MASK0_SET__irq_int_vector_nr__nop 0 -#define R_IRQ_MASK0_SET__ext_dma1__BITNR 3 -#define R_IRQ_MASK0_SET__ext_dma1__WIDTH 1 -#define R_IRQ_MASK0_SET__ext_dma1__set 1 -#define R_IRQ_MASK0_SET__ext_dma1__nop 0 -#define R_IRQ_MASK0_SET__ext_dma0__BITNR 2 -#define R_IRQ_MASK0_SET__ext_dma0__WIDTH 1 -#define R_IRQ_MASK0_SET__ext_dma0__set 1 -#define R_IRQ_MASK0_SET__ext_dma0__nop 0 -#define R_IRQ_MASK0_SET__timer1__BITNR 1 -#define R_IRQ_MASK0_SET__timer1__WIDTH 1 -#define R_IRQ_MASK0_SET__timer1__set 1 -#define R_IRQ_MASK0_SET__timer1__nop 0 -#define R_IRQ_MASK0_SET__timer0__BITNR 0 -#define R_IRQ_MASK0_SET__timer0__WIDTH 1 -#define R_IRQ_MASK0_SET__timer0__set 1 -#define R_IRQ_MASK0_SET__timer0__nop 0 - -#define R_IRQ_MASK1_RD (IO_TYPECAST_RO_UDWORD 0xb00000c8) -#define R_IRQ_MASK1_RD__sw_int7__BITNR 31 -#define R_IRQ_MASK1_RD__sw_int7__WIDTH 1 -#define R_IRQ_MASK1_RD__sw_int7__active 1 -#define R_IRQ_MASK1_RD__sw_int7__inactive 0 -#define R_IRQ_MASK1_RD__sw_int6__BITNR 30 -#define R_IRQ_MASK1_RD__sw_int6__WIDTH 1 -#define R_IRQ_MASK1_RD__sw_int6__active 1 -#define R_IRQ_MASK1_RD__sw_int6__inactive 0 -#define R_IRQ_MASK1_RD__sw_int5__BITNR 29 -#define R_IRQ_MASK1_RD__sw_int5__WIDTH 1 -#define R_IRQ_MASK1_RD__sw_int5__active 1 -#define R_IRQ_MASK1_RD__sw_int5__inactive 0 -#define R_IRQ_MASK1_RD__sw_int4__BITNR 28 -#define R_IRQ_MASK1_RD__sw_int4__WIDTH 1 -#define R_IRQ_MASK1_RD__sw_int4__active 1 -#define R_IRQ_MASK1_RD__sw_int4__inactive 0 -#define R_IRQ_MASK1_RD__sw_int3__BITNR 27 -#define R_IRQ_MASK1_RD__sw_int3__WIDTH 1 -#define R_IRQ_MASK1_RD__sw_int3__active 1 -#define R_IRQ_MASK1_RD__sw_int3__inactive 0 -#define R_IRQ_MASK1_RD__sw_int2__BITNR 26 -#define R_IRQ_MASK1_RD__sw_int2__WIDTH 1 -#define R_IRQ_MASK1_RD__sw_int2__active 1 -#define R_IRQ_MASK1_RD__sw_int2__inactive 0 -#define R_IRQ_MASK1_RD__sw_int1__BITNR 25 -#define R_IRQ_MASK1_RD__sw_int1__WIDTH 1 -#define R_IRQ_MASK1_RD__sw_int1__active 1 -#define R_IRQ_MASK1_RD__sw_int1__inactive 0 -#define R_IRQ_MASK1_RD__sw_int0__BITNR 24 -#define R_IRQ_MASK1_RD__sw_int0__WIDTH 1 -#define R_IRQ_MASK1_RD__sw_int0__active 1 -#define R_IRQ_MASK1_RD__sw_int0__inactive 0 -#define R_IRQ_MASK1_RD__par1_ecp_cmd__BITNR 19 -#define R_IRQ_MASK1_RD__par1_ecp_cmd__WIDTH 1 -#define R_IRQ_MASK1_RD__par1_ecp_cmd__active 1 -#define R_IRQ_MASK1_RD__par1_ecp_cmd__inactive 0 -#define R_IRQ_MASK1_RD__par1_peri__BITNR 18 -#define R_IRQ_MASK1_RD__par1_peri__WIDTH 1 -#define R_IRQ_MASK1_RD__par1_peri__active 1 -#define R_IRQ_MASK1_RD__par1_peri__inactive 0 -#define R_IRQ_MASK1_RD__par1_data__BITNR 17 -#define R_IRQ_MASK1_RD__par1_data__WIDTH 1 -#define R_IRQ_MASK1_RD__par1_data__active 1 -#define R_IRQ_MASK1_RD__par1_data__inactive 0 -#define R_IRQ_MASK1_RD__par1_ready__BITNR 16 -#define R_IRQ_MASK1_RD__par1_ready__WIDTH 1 -#define R_IRQ_MASK1_RD__par1_ready__active 1 -#define R_IRQ_MASK1_RD__par1_ready__inactive 0 -#define R_IRQ_MASK1_RD__scsi1__BITNR 16 -#define R_IRQ_MASK1_RD__scsi1__WIDTH 1 -#define R_IRQ_MASK1_RD__scsi1__active 1 -#define R_IRQ_MASK1_RD__scsi1__inactive 0 -#define R_IRQ_MASK1_RD__ser3_ready__BITNR 15 -#define R_IRQ_MASK1_RD__ser3_ready__WIDTH 1 -#define R_IRQ_MASK1_RD__ser3_ready__active 1 -#define R_IRQ_MASK1_RD__ser3_ready__inactive 0 -#define R_IRQ_MASK1_RD__ser3_data__BITNR 14 -#define R_IRQ_MASK1_RD__ser3_data__WIDTH 1 -#define R_IRQ_MASK1_RD__ser3_data__active 1 -#define R_IRQ_MASK1_RD__ser3_data__inactive 0 -#define R_IRQ_MASK1_RD__ser2_ready__BITNR 13 -#define R_IRQ_MASK1_RD__ser2_ready__WIDTH 1 -#define R_IRQ_MASK1_RD__ser2_ready__active 1 -#define R_IRQ_MASK1_RD__ser2_ready__inactive 0 -#define R_IRQ_MASK1_RD__ser2_data__BITNR 12 -#define R_IRQ_MASK1_RD__ser2_data__WIDTH 1 -#define R_IRQ_MASK1_RD__ser2_data__active 1 -#define R_IRQ_MASK1_RD__ser2_data__inactive 0 -#define R_IRQ_MASK1_RD__ser1_ready__BITNR 11 -#define R_IRQ_MASK1_RD__ser1_ready__WIDTH 1 -#define R_IRQ_MASK1_RD__ser1_ready__active 1 -#define R_IRQ_MASK1_RD__ser1_ready__inactive 0 -#define R_IRQ_MASK1_RD__ser1_data__BITNR 10 -#define R_IRQ_MASK1_RD__ser1_data__WIDTH 1 -#define R_IRQ_MASK1_RD__ser1_data__active 1 -#define R_IRQ_MASK1_RD__ser1_data__inactive 0 -#define R_IRQ_MASK1_RD__ser0_ready__BITNR 9 -#define R_IRQ_MASK1_RD__ser0_ready__WIDTH 1 -#define R_IRQ_MASK1_RD__ser0_ready__active 1 -#define R_IRQ_MASK1_RD__ser0_ready__inactive 0 -#define R_IRQ_MASK1_RD__ser0_data__BITNR 8 -#define R_IRQ_MASK1_RD__ser0_data__WIDTH 1 -#define R_IRQ_MASK1_RD__ser0_data__active 1 -#define R_IRQ_MASK1_RD__ser0_data__inactive 0 -#define R_IRQ_MASK1_RD__pa7__BITNR 7 -#define R_IRQ_MASK1_RD__pa7__WIDTH 1 -#define R_IRQ_MASK1_RD__pa7__active 1 -#define R_IRQ_MASK1_RD__pa7__inactive 0 -#define R_IRQ_MASK1_RD__pa6__BITNR 6 -#define R_IRQ_MASK1_RD__pa6__WIDTH 1 -#define R_IRQ_MASK1_RD__pa6__active 1 -#define R_IRQ_MASK1_RD__pa6__inactive 0 -#define R_IRQ_MASK1_RD__pa5__BITNR 5 -#define R_IRQ_MASK1_RD__pa5__WIDTH 1 -#define R_IRQ_MASK1_RD__pa5__active 1 -#define R_IRQ_MASK1_RD__pa5__inactive 0 -#define R_IRQ_MASK1_RD__pa4__BITNR 4 -#define R_IRQ_MASK1_RD__pa4__WIDTH 1 -#define R_IRQ_MASK1_RD__pa4__active 1 -#define R_IRQ_MASK1_RD__pa4__inactive 0 -#define R_IRQ_MASK1_RD__pa3__BITNR 3 -#define R_IRQ_MASK1_RD__pa3__WIDTH 1 -#define R_IRQ_MASK1_RD__pa3__active 1 -#define R_IRQ_MASK1_RD__pa3__inactive 0 -#define R_IRQ_MASK1_RD__pa2__BITNR 2 -#define R_IRQ_MASK1_RD__pa2__WIDTH 1 -#define R_IRQ_MASK1_RD__pa2__active 1 -#define R_IRQ_MASK1_RD__pa2__inactive 0 -#define R_IRQ_MASK1_RD__pa1__BITNR 1 -#define R_IRQ_MASK1_RD__pa1__WIDTH 1 -#define R_IRQ_MASK1_RD__pa1__active 1 -#define R_IRQ_MASK1_RD__pa1__inactive 0 -#define R_IRQ_MASK1_RD__pa0__BITNR 0 -#define R_IRQ_MASK1_RD__pa0__WIDTH 1 -#define R_IRQ_MASK1_RD__pa0__active 1 -#define R_IRQ_MASK1_RD__pa0__inactive 0 - -#define R_IRQ_MASK1_CLR (IO_TYPECAST_UDWORD 0xb00000c8) -#define R_IRQ_MASK1_CLR__sw_int7__BITNR 31 -#define R_IRQ_MASK1_CLR__sw_int7__WIDTH 1 -#define R_IRQ_MASK1_CLR__sw_int7__clr 1 -#define R_IRQ_MASK1_CLR__sw_int7__nop 0 -#define R_IRQ_MASK1_CLR__sw_int6__BITNR 30 -#define R_IRQ_MASK1_CLR__sw_int6__WIDTH 1 -#define R_IRQ_MASK1_CLR__sw_int6__clr 1 -#define R_IRQ_MASK1_CLR__sw_int6__nop 0 -#define R_IRQ_MASK1_CLR__sw_int5__BITNR 29 -#define R_IRQ_MASK1_CLR__sw_int5__WIDTH 1 -#define R_IRQ_MASK1_CLR__sw_int5__clr 1 -#define R_IRQ_MASK1_CLR__sw_int5__nop 0 -#define R_IRQ_MASK1_CLR__sw_int4__BITNR 28 -#define R_IRQ_MASK1_CLR__sw_int4__WIDTH 1 -#define R_IRQ_MASK1_CLR__sw_int4__clr 1 -#define R_IRQ_MASK1_CLR__sw_int4__nop 0 -#define R_IRQ_MASK1_CLR__sw_int3__BITNR 27 -#define R_IRQ_MASK1_CLR__sw_int3__WIDTH 1 -#define R_IRQ_MASK1_CLR__sw_int3__clr 1 -#define R_IRQ_MASK1_CLR__sw_int3__nop 0 -#define R_IRQ_MASK1_CLR__sw_int2__BITNR 26 -#define R_IRQ_MASK1_CLR__sw_int2__WIDTH 1 -#define R_IRQ_MASK1_CLR__sw_int2__clr 1 -#define R_IRQ_MASK1_CLR__sw_int2__nop 0 -#define R_IRQ_MASK1_CLR__sw_int1__BITNR 25 -#define R_IRQ_MASK1_CLR__sw_int1__WIDTH 1 -#define R_IRQ_MASK1_CLR__sw_int1__clr 1 -#define R_IRQ_MASK1_CLR__sw_int1__nop 0 -#define R_IRQ_MASK1_CLR__sw_int0__BITNR 24 -#define R_IRQ_MASK1_CLR__sw_int0__WIDTH 1 -#define R_IRQ_MASK1_CLR__sw_int0__clr 1 -#define R_IRQ_MASK1_CLR__sw_int0__nop 0 -#define R_IRQ_MASK1_CLR__par1_ecp_cmd__BITNR 19 -#define R_IRQ_MASK1_CLR__par1_ecp_cmd__WIDTH 1 -#define R_IRQ_MASK1_CLR__par1_ecp_cmd__clr 1 -#define R_IRQ_MASK1_CLR__par1_ecp_cmd__nop 0 -#define R_IRQ_MASK1_CLR__par1_peri__BITNR 18 -#define R_IRQ_MASK1_CLR__par1_peri__WIDTH 1 -#define R_IRQ_MASK1_CLR__par1_peri__clr 1 -#define R_IRQ_MASK1_CLR__par1_peri__nop 0 -#define R_IRQ_MASK1_CLR__par1_data__BITNR 17 -#define R_IRQ_MASK1_CLR__par1_data__WIDTH 1 -#define R_IRQ_MASK1_CLR__par1_data__clr 1 -#define R_IRQ_MASK1_CLR__par1_data__nop 0 -#define R_IRQ_MASK1_CLR__par1_ready__BITNR 16 -#define R_IRQ_MASK1_CLR__par1_ready__WIDTH 1 -#define R_IRQ_MASK1_CLR__par1_ready__clr 1 -#define R_IRQ_MASK1_CLR__par1_ready__nop 0 -#define R_IRQ_MASK1_CLR__scsi1__BITNR 16 -#define R_IRQ_MASK1_CLR__scsi1__WIDTH 1 -#define R_IRQ_MASK1_CLR__scsi1__clr 1 -#define R_IRQ_MASK1_CLR__scsi1__nop 0 -#define R_IRQ_MASK1_CLR__ser3_ready__BITNR 15 -#define R_IRQ_MASK1_CLR__ser3_ready__WIDTH 1 -#define R_IRQ_MASK1_CLR__ser3_ready__clr 1 -#define R_IRQ_MASK1_CLR__ser3_ready__nop 0 -#define R_IRQ_MASK1_CLR__ser3_data__BITNR 14 -#define R_IRQ_MASK1_CLR__ser3_data__WIDTH 1 -#define R_IRQ_MASK1_CLR__ser3_data__clr 1 -#define R_IRQ_MASK1_CLR__ser3_data__nop 0 -#define R_IRQ_MASK1_CLR__ser2_ready__BITNR 13 -#define R_IRQ_MASK1_CLR__ser2_ready__WIDTH 1 -#define R_IRQ_MASK1_CLR__ser2_ready__clr 1 -#define R_IRQ_MASK1_CLR__ser2_ready__nop 0 -#define R_IRQ_MASK1_CLR__ser2_data__BITNR 12 -#define R_IRQ_MASK1_CLR__ser2_data__WIDTH 1 -#define R_IRQ_MASK1_CLR__ser2_data__clr 1 -#define R_IRQ_MASK1_CLR__ser2_data__nop 0 -#define R_IRQ_MASK1_CLR__ser1_ready__BITNR 11 -#define R_IRQ_MASK1_CLR__ser1_ready__WIDTH 1 -#define R_IRQ_MASK1_CLR__ser1_ready__clr 1 -#define R_IRQ_MASK1_CLR__ser1_ready__nop 0 -#define R_IRQ_MASK1_CLR__ser1_data__BITNR 10 -#define R_IRQ_MASK1_CLR__ser1_data__WIDTH 1 -#define R_IRQ_MASK1_CLR__ser1_data__clr 1 -#define R_IRQ_MASK1_CLR__ser1_data__nop 0 -#define R_IRQ_MASK1_CLR__ser0_ready__BITNR 9 -#define R_IRQ_MASK1_CLR__ser0_ready__WIDTH 1 -#define R_IRQ_MASK1_CLR__ser0_ready__clr 1 -#define R_IRQ_MASK1_CLR__ser0_ready__nop 0 -#define R_IRQ_MASK1_CLR__ser0_data__BITNR 8 -#define R_IRQ_MASK1_CLR__ser0_data__WIDTH 1 -#define R_IRQ_MASK1_CLR__ser0_data__clr 1 -#define R_IRQ_MASK1_CLR__ser0_data__nop 0 -#define R_IRQ_MASK1_CLR__pa7__BITNR 7 -#define R_IRQ_MASK1_CLR__pa7__WIDTH 1 -#define R_IRQ_MASK1_CLR__pa7__clr 1 -#define R_IRQ_MASK1_CLR__pa7__nop 0 -#define R_IRQ_MASK1_CLR__pa6__BITNR 6 -#define R_IRQ_MASK1_CLR__pa6__WIDTH 1 -#define R_IRQ_MASK1_CLR__pa6__clr 1 -#define R_IRQ_MASK1_CLR__pa6__nop 0 -#define R_IRQ_MASK1_CLR__pa5__BITNR 5 -#define R_IRQ_MASK1_CLR__pa5__WIDTH 1 -#define R_IRQ_MASK1_CLR__pa5__clr 1 -#define R_IRQ_MASK1_CLR__pa5__nop 0 -#define R_IRQ_MASK1_CLR__pa4__BITNR 4 -#define R_IRQ_MASK1_CLR__pa4__WIDTH 1 -#define R_IRQ_MASK1_CLR__pa4__clr 1 -#define R_IRQ_MASK1_CLR__pa4__nop 0 -#define R_IRQ_MASK1_CLR__pa3__BITNR 3 -#define R_IRQ_MASK1_CLR__pa3__WIDTH 1 -#define R_IRQ_MASK1_CLR__pa3__clr 1 -#define R_IRQ_MASK1_CLR__pa3__nop 0 -#define R_IRQ_MASK1_CLR__pa2__BITNR 2 -#define R_IRQ_MASK1_CLR__pa2__WIDTH 1 -#define R_IRQ_MASK1_CLR__pa2__clr 1 -#define R_IRQ_MASK1_CLR__pa2__nop 0 -#define R_IRQ_MASK1_CLR__pa1__BITNR 1 -#define R_IRQ_MASK1_CLR__pa1__WIDTH 1 -#define R_IRQ_MASK1_CLR__pa1__clr 1 -#define R_IRQ_MASK1_CLR__pa1__nop 0 -#define R_IRQ_MASK1_CLR__pa0__BITNR 0 -#define R_IRQ_MASK1_CLR__pa0__WIDTH 1 -#define R_IRQ_MASK1_CLR__pa0__clr 1 -#define R_IRQ_MASK1_CLR__pa0__nop 0 - -#define R_IRQ_READ1 (IO_TYPECAST_RO_UDWORD 0xb00000cc) -#define R_IRQ_READ1__sw_int7__BITNR 31 -#define R_IRQ_READ1__sw_int7__WIDTH 1 -#define R_IRQ_READ1__sw_int7__active 1 -#define R_IRQ_READ1__sw_int7__inactive 0 -#define R_IRQ_READ1__sw_int6__BITNR 30 -#define R_IRQ_READ1__sw_int6__WIDTH 1 -#define R_IRQ_READ1__sw_int6__active 1 -#define R_IRQ_READ1__sw_int6__inactive 0 -#define R_IRQ_READ1__sw_int5__BITNR 29 -#define R_IRQ_READ1__sw_int5__WIDTH 1 -#define R_IRQ_READ1__sw_int5__active 1 -#define R_IRQ_READ1__sw_int5__inactive 0 -#define R_IRQ_READ1__sw_int4__BITNR 28 -#define R_IRQ_READ1__sw_int4__WIDTH 1 -#define R_IRQ_READ1__sw_int4__active 1 -#define R_IRQ_READ1__sw_int4__inactive 0 -#define R_IRQ_READ1__sw_int3__BITNR 27 -#define R_IRQ_READ1__sw_int3__WIDTH 1 -#define R_IRQ_READ1__sw_int3__active 1 -#define R_IRQ_READ1__sw_int3__inactive 0 -#define R_IRQ_READ1__sw_int2__BITNR 26 -#define R_IRQ_READ1__sw_int2__WIDTH 1 -#define R_IRQ_READ1__sw_int2__active 1 -#define R_IRQ_READ1__sw_int2__inactive 0 -#define R_IRQ_READ1__sw_int1__BITNR 25 -#define R_IRQ_READ1__sw_int1__WIDTH 1 -#define R_IRQ_READ1__sw_int1__active 1 -#define R_IRQ_READ1__sw_int1__inactive 0 -#define R_IRQ_READ1__sw_int0__BITNR 24 -#define R_IRQ_READ1__sw_int0__WIDTH 1 -#define R_IRQ_READ1__sw_int0__active 1 -#define R_IRQ_READ1__sw_int0__inactive 0 -#define R_IRQ_READ1__par1_ecp_cmd__BITNR 19 -#define R_IRQ_READ1__par1_ecp_cmd__WIDTH 1 -#define R_IRQ_READ1__par1_ecp_cmd__active 1 -#define R_IRQ_READ1__par1_ecp_cmd__inactive 0 -#define R_IRQ_READ1__par1_peri__BITNR 18 -#define R_IRQ_READ1__par1_peri__WIDTH 1 -#define R_IRQ_READ1__par1_peri__active 1 -#define R_IRQ_READ1__par1_peri__inactive 0 -#define R_IRQ_READ1__par1_data__BITNR 17 -#define R_IRQ_READ1__par1_data__WIDTH 1 -#define R_IRQ_READ1__par1_data__active 1 -#define R_IRQ_READ1__par1_data__inactive 0 -#define R_IRQ_READ1__par1_ready__BITNR 16 -#define R_IRQ_READ1__par1_ready__WIDTH 1 -#define R_IRQ_READ1__par1_ready__active 1 -#define R_IRQ_READ1__par1_ready__inactive 0 -#define R_IRQ_READ1__scsi1__BITNR 16 -#define R_IRQ_READ1__scsi1__WIDTH 1 -#define R_IRQ_READ1__scsi1__active 1 -#define R_IRQ_READ1__scsi1__inactive 0 -#define R_IRQ_READ1__ser3_ready__BITNR 15 -#define R_IRQ_READ1__ser3_ready__WIDTH 1 -#define R_IRQ_READ1__ser3_ready__active 1 -#define R_IRQ_READ1__ser3_ready__inactive 0 -#define R_IRQ_READ1__ser3_data__BITNR 14 -#define R_IRQ_READ1__ser3_data__WIDTH 1 -#define R_IRQ_READ1__ser3_data__active 1 -#define R_IRQ_READ1__ser3_data__inactive 0 -#define R_IRQ_READ1__ser2_ready__BITNR 13 -#define R_IRQ_READ1__ser2_ready__WIDTH 1 -#define R_IRQ_READ1__ser2_ready__active 1 -#define R_IRQ_READ1__ser2_ready__inactive 0 -#define R_IRQ_READ1__ser2_data__BITNR 12 -#define R_IRQ_READ1__ser2_data__WIDTH 1 -#define R_IRQ_READ1__ser2_data__active 1 -#define R_IRQ_READ1__ser2_data__inactive 0 -#define R_IRQ_READ1__ser1_ready__BITNR 11 -#define R_IRQ_READ1__ser1_ready__WIDTH 1 -#define R_IRQ_READ1__ser1_ready__active 1 -#define R_IRQ_READ1__ser1_ready__inactive 0 -#define R_IRQ_READ1__ser1_data__BITNR 10 -#define R_IRQ_READ1__ser1_data__WIDTH 1 -#define R_IRQ_READ1__ser1_data__active 1 -#define R_IRQ_READ1__ser1_data__inactive 0 -#define R_IRQ_READ1__ser0_ready__BITNR 9 -#define R_IRQ_READ1__ser0_ready__WIDTH 1 -#define R_IRQ_READ1__ser0_ready__active 1 -#define R_IRQ_READ1__ser0_ready__inactive 0 -#define R_IRQ_READ1__ser0_data__BITNR 8 -#define R_IRQ_READ1__ser0_data__WIDTH 1 -#define R_IRQ_READ1__ser0_data__active 1 -#define R_IRQ_READ1__ser0_data__inactive 0 -#define R_IRQ_READ1__pa7__BITNR 7 -#define R_IRQ_READ1__pa7__WIDTH 1 -#define R_IRQ_READ1__pa7__active 1 -#define R_IRQ_READ1__pa7__inactive 0 -#define R_IRQ_READ1__pa6__BITNR 6 -#define R_IRQ_READ1__pa6__WIDTH 1 -#define R_IRQ_READ1__pa6__active 1 -#define R_IRQ_READ1__pa6__inactive 0 -#define R_IRQ_READ1__pa5__BITNR 5 -#define R_IRQ_READ1__pa5__WIDTH 1 -#define R_IRQ_READ1__pa5__active 1 -#define R_IRQ_READ1__pa5__inactive 0 -#define R_IRQ_READ1__pa4__BITNR 4 -#define R_IRQ_READ1__pa4__WIDTH 1 -#define R_IRQ_READ1__pa4__active 1 -#define R_IRQ_READ1__pa4__inactive 0 -#define R_IRQ_READ1__pa3__BITNR 3 -#define R_IRQ_READ1__pa3__WIDTH 1 -#define R_IRQ_READ1__pa3__active 1 -#define R_IRQ_READ1__pa3__inactive 0 -#define R_IRQ_READ1__pa2__BITNR 2 -#define R_IRQ_READ1__pa2__WIDTH 1 -#define R_IRQ_READ1__pa2__active 1 -#define R_IRQ_READ1__pa2__inactive 0 -#define R_IRQ_READ1__pa1__BITNR 1 -#define R_IRQ_READ1__pa1__WIDTH 1 -#define R_IRQ_READ1__pa1__active 1 -#define R_IRQ_READ1__pa1__inactive 0 -#define R_IRQ_READ1__pa0__BITNR 0 -#define R_IRQ_READ1__pa0__WIDTH 1 -#define R_IRQ_READ1__pa0__active 1 -#define R_IRQ_READ1__pa0__inactive 0 - -#define R_IRQ_MASK1_SET (IO_TYPECAST_UDWORD 0xb00000cc) -#define R_IRQ_MASK1_SET__sw_int7__BITNR 31 -#define R_IRQ_MASK1_SET__sw_int7__WIDTH 1 -#define R_IRQ_MASK1_SET__sw_int7__set 1 -#define R_IRQ_MASK1_SET__sw_int7__nop 0 -#define R_IRQ_MASK1_SET__sw_int6__BITNR 30 -#define R_IRQ_MASK1_SET__sw_int6__WIDTH 1 -#define R_IRQ_MASK1_SET__sw_int6__set 1 -#define R_IRQ_MASK1_SET__sw_int6__nop 0 -#define R_IRQ_MASK1_SET__sw_int5__BITNR 29 -#define R_IRQ_MASK1_SET__sw_int5__WIDTH 1 -#define R_IRQ_MASK1_SET__sw_int5__set 1 -#define R_IRQ_MASK1_SET__sw_int5__nop 0 -#define R_IRQ_MASK1_SET__sw_int4__BITNR 28 -#define R_IRQ_MASK1_SET__sw_int4__WIDTH 1 -#define R_IRQ_MASK1_SET__sw_int4__set 1 -#define R_IRQ_MASK1_SET__sw_int4__nop 0 -#define R_IRQ_MASK1_SET__sw_int3__BITNR 27 -#define R_IRQ_MASK1_SET__sw_int3__WIDTH 1 -#define R_IRQ_MASK1_SET__sw_int3__set 1 -#define R_IRQ_MASK1_SET__sw_int3__nop 0 -#define R_IRQ_MASK1_SET__sw_int2__BITNR 26 -#define R_IRQ_MASK1_SET__sw_int2__WIDTH 1 -#define R_IRQ_MASK1_SET__sw_int2__set 1 -#define R_IRQ_MASK1_SET__sw_int2__nop 0 -#define R_IRQ_MASK1_SET__sw_int1__BITNR 25 -#define R_IRQ_MASK1_SET__sw_int1__WIDTH 1 -#define R_IRQ_MASK1_SET__sw_int1__set 1 -#define R_IRQ_MASK1_SET__sw_int1__nop 0 -#define R_IRQ_MASK1_SET__sw_int0__BITNR 24 -#define R_IRQ_MASK1_SET__sw_int0__WIDTH 1 -#define R_IRQ_MASK1_SET__sw_int0__set 1 -#define R_IRQ_MASK1_SET__sw_int0__nop 0 -#define R_IRQ_MASK1_SET__par1_ecp_cmd__BITNR 19 -#define R_IRQ_MASK1_SET__par1_ecp_cmd__WIDTH 1 -#define R_IRQ_MASK1_SET__par1_ecp_cmd__set 1 -#define R_IRQ_MASK1_SET__par1_ecp_cmd__nop 0 -#define R_IRQ_MASK1_SET__par1_peri__BITNR 18 -#define R_IRQ_MASK1_SET__par1_peri__WIDTH 1 -#define R_IRQ_MASK1_SET__par1_peri__set 1 -#define R_IRQ_MASK1_SET__par1_peri__nop 0 -#define R_IRQ_MASK1_SET__par1_data__BITNR 17 -#define R_IRQ_MASK1_SET__par1_data__WIDTH 1 -#define R_IRQ_MASK1_SET__par1_data__set 1 -#define R_IRQ_MASK1_SET__par1_data__nop 0 -#define R_IRQ_MASK1_SET__par1_ready__BITNR 16 -#define R_IRQ_MASK1_SET__par1_ready__WIDTH 1 -#define R_IRQ_MASK1_SET__par1_ready__set 1 -#define R_IRQ_MASK1_SET__par1_ready__nop 0 -#define R_IRQ_MASK1_SET__scsi1__BITNR 16 -#define R_IRQ_MASK1_SET__scsi1__WIDTH 1 -#define R_IRQ_MASK1_SET__scsi1__set 1 -#define R_IRQ_MASK1_SET__scsi1__nop 0 -#define R_IRQ_MASK1_SET__ser3_ready__BITNR 15 -#define R_IRQ_MASK1_SET__ser3_ready__WIDTH 1 -#define R_IRQ_MASK1_SET__ser3_ready__set 1 -#define R_IRQ_MASK1_SET__ser3_ready__nop 0 -#define R_IRQ_MASK1_SET__ser3_data__BITNR 14 -#define R_IRQ_MASK1_SET__ser3_data__WIDTH 1 -#define R_IRQ_MASK1_SET__ser3_data__set 1 -#define R_IRQ_MASK1_SET__ser3_data__nop 0 -#define R_IRQ_MASK1_SET__ser2_ready__BITNR 13 -#define R_IRQ_MASK1_SET__ser2_ready__WIDTH 1 -#define R_IRQ_MASK1_SET__ser2_ready__set 1 -#define R_IRQ_MASK1_SET__ser2_ready__nop 0 -#define R_IRQ_MASK1_SET__ser2_data__BITNR 12 -#define R_IRQ_MASK1_SET__ser2_data__WIDTH 1 -#define R_IRQ_MASK1_SET__ser2_data__set 1 -#define R_IRQ_MASK1_SET__ser2_data__nop 0 -#define R_IRQ_MASK1_SET__ser1_ready__BITNR 11 -#define R_IRQ_MASK1_SET__ser1_ready__WIDTH 1 -#define R_IRQ_MASK1_SET__ser1_ready__set 1 -#define R_IRQ_MASK1_SET__ser1_ready__nop 0 -#define R_IRQ_MASK1_SET__ser1_data__BITNR 10 -#define R_IRQ_MASK1_SET__ser1_data__WIDTH 1 -#define R_IRQ_MASK1_SET__ser1_data__set 1 -#define R_IRQ_MASK1_SET__ser1_data__nop 0 -#define R_IRQ_MASK1_SET__ser0_ready__BITNR 9 -#define R_IRQ_MASK1_SET__ser0_ready__WIDTH 1 -#define R_IRQ_MASK1_SET__ser0_ready__set 1 -#define R_IRQ_MASK1_SET__ser0_ready__nop 0 -#define R_IRQ_MASK1_SET__ser0_data__BITNR 8 -#define R_IRQ_MASK1_SET__ser0_data__WIDTH 1 -#define R_IRQ_MASK1_SET__ser0_data__set 1 -#define R_IRQ_MASK1_SET__ser0_data__nop 0 -#define R_IRQ_MASK1_SET__pa7__BITNR 7 -#define R_IRQ_MASK1_SET__pa7__WIDTH 1 -#define R_IRQ_MASK1_SET__pa7__set 1 -#define R_IRQ_MASK1_SET__pa7__nop 0 -#define R_IRQ_MASK1_SET__pa6__BITNR 6 -#define R_IRQ_MASK1_SET__pa6__WIDTH 1 -#define R_IRQ_MASK1_SET__pa6__set 1 -#define R_IRQ_MASK1_SET__pa6__nop 0 -#define R_IRQ_MASK1_SET__pa5__BITNR 5 -#define R_IRQ_MASK1_SET__pa5__WIDTH 1 -#define R_IRQ_MASK1_SET__pa5__set 1 -#define R_IRQ_MASK1_SET__pa5__nop 0 -#define R_IRQ_MASK1_SET__pa4__BITNR 4 -#define R_IRQ_MASK1_SET__pa4__WIDTH 1 -#define R_IRQ_MASK1_SET__pa4__set 1 -#define R_IRQ_MASK1_SET__pa4__nop 0 -#define R_IRQ_MASK1_SET__pa3__BITNR 3 -#define R_IRQ_MASK1_SET__pa3__WIDTH 1 -#define R_IRQ_MASK1_SET__pa3__set 1 -#define R_IRQ_MASK1_SET__pa3__nop 0 -#define R_IRQ_MASK1_SET__pa2__BITNR 2 -#define R_IRQ_MASK1_SET__pa2__WIDTH 1 -#define R_IRQ_MASK1_SET__pa2__set 1 -#define R_IRQ_MASK1_SET__pa2__nop 0 -#define R_IRQ_MASK1_SET__pa1__BITNR 1 -#define R_IRQ_MASK1_SET__pa1__WIDTH 1 -#define R_IRQ_MASK1_SET__pa1__set 1 -#define R_IRQ_MASK1_SET__pa1__nop 0 -#define R_IRQ_MASK1_SET__pa0__BITNR 0 -#define R_IRQ_MASK1_SET__pa0__WIDTH 1 -#define R_IRQ_MASK1_SET__pa0__set 1 -#define R_IRQ_MASK1_SET__pa0__nop 0 - -#define R_IRQ_MASK2_RD (IO_TYPECAST_RO_UDWORD 0xb00000d0) -#define R_IRQ_MASK2_RD__dma8_sub3_descr__BITNR 23 -#define R_IRQ_MASK2_RD__dma8_sub3_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma8_sub3_descr__active 1 -#define R_IRQ_MASK2_RD__dma8_sub3_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma8_sub2_descr__BITNR 22 -#define R_IRQ_MASK2_RD__dma8_sub2_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma8_sub2_descr__active 1 -#define R_IRQ_MASK2_RD__dma8_sub2_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma8_sub1_descr__BITNR 21 -#define R_IRQ_MASK2_RD__dma8_sub1_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma8_sub1_descr__active 1 -#define R_IRQ_MASK2_RD__dma8_sub1_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma8_sub0_descr__BITNR 20 -#define R_IRQ_MASK2_RD__dma8_sub0_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma8_sub0_descr__active 1 -#define R_IRQ_MASK2_RD__dma8_sub0_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma9_eop__BITNR 19 -#define R_IRQ_MASK2_RD__dma9_eop__WIDTH 1 -#define R_IRQ_MASK2_RD__dma9_eop__active 1 -#define R_IRQ_MASK2_RD__dma9_eop__inactive 0 -#define R_IRQ_MASK2_RD__dma9_descr__BITNR 18 -#define R_IRQ_MASK2_RD__dma9_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma9_descr__active 1 -#define R_IRQ_MASK2_RD__dma9_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma8_eop__BITNR 17 -#define R_IRQ_MASK2_RD__dma8_eop__WIDTH 1 -#define R_IRQ_MASK2_RD__dma8_eop__active 1 -#define R_IRQ_MASK2_RD__dma8_eop__inactive 0 -#define R_IRQ_MASK2_RD__dma8_descr__BITNR 16 -#define R_IRQ_MASK2_RD__dma8_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma8_descr__active 1 -#define R_IRQ_MASK2_RD__dma8_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma7_eop__BITNR 15 -#define R_IRQ_MASK2_RD__dma7_eop__WIDTH 1 -#define R_IRQ_MASK2_RD__dma7_eop__active 1 -#define R_IRQ_MASK2_RD__dma7_eop__inactive 0 -#define R_IRQ_MASK2_RD__dma7_descr__BITNR 14 -#define R_IRQ_MASK2_RD__dma7_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma7_descr__active 1 -#define R_IRQ_MASK2_RD__dma7_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma6_eop__BITNR 13 -#define R_IRQ_MASK2_RD__dma6_eop__WIDTH 1 -#define R_IRQ_MASK2_RD__dma6_eop__active 1 -#define R_IRQ_MASK2_RD__dma6_eop__inactive 0 -#define R_IRQ_MASK2_RD__dma6_descr__BITNR 12 -#define R_IRQ_MASK2_RD__dma6_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma6_descr__active 1 -#define R_IRQ_MASK2_RD__dma6_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma5_eop__BITNR 11 -#define R_IRQ_MASK2_RD__dma5_eop__WIDTH 1 -#define R_IRQ_MASK2_RD__dma5_eop__active 1 -#define R_IRQ_MASK2_RD__dma5_eop__inactive 0 -#define R_IRQ_MASK2_RD__dma5_descr__BITNR 10 -#define R_IRQ_MASK2_RD__dma5_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma5_descr__active 1 -#define R_IRQ_MASK2_RD__dma5_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma4_eop__BITNR 9 -#define R_IRQ_MASK2_RD__dma4_eop__WIDTH 1 -#define R_IRQ_MASK2_RD__dma4_eop__active 1 -#define R_IRQ_MASK2_RD__dma4_eop__inactive 0 -#define R_IRQ_MASK2_RD__dma4_descr__BITNR 8 -#define R_IRQ_MASK2_RD__dma4_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma4_descr__active 1 -#define R_IRQ_MASK2_RD__dma4_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma3_eop__BITNR 7 -#define R_IRQ_MASK2_RD__dma3_eop__WIDTH 1 -#define R_IRQ_MASK2_RD__dma3_eop__active 1 -#define R_IRQ_MASK2_RD__dma3_eop__inactive 0 -#define R_IRQ_MASK2_RD__dma3_descr__BITNR 6 -#define R_IRQ_MASK2_RD__dma3_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma3_descr__active 1 -#define R_IRQ_MASK2_RD__dma3_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma2_eop__BITNR 5 -#define R_IRQ_MASK2_RD__dma2_eop__WIDTH 1 -#define R_IRQ_MASK2_RD__dma2_eop__active 1 -#define R_IRQ_MASK2_RD__dma2_eop__inactive 0 -#define R_IRQ_MASK2_RD__dma2_descr__BITNR 4 -#define R_IRQ_MASK2_RD__dma2_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma2_descr__active 1 -#define R_IRQ_MASK2_RD__dma2_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma1_eop__BITNR 3 -#define R_IRQ_MASK2_RD__dma1_eop__WIDTH 1 -#define R_IRQ_MASK2_RD__dma1_eop__active 1 -#define R_IRQ_MASK2_RD__dma1_eop__inactive 0 -#define R_IRQ_MASK2_RD__dma1_descr__BITNR 2 -#define R_IRQ_MASK2_RD__dma1_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma1_descr__active 1 -#define R_IRQ_MASK2_RD__dma1_descr__inactive 0 -#define R_IRQ_MASK2_RD__dma0_eop__BITNR 1 -#define R_IRQ_MASK2_RD__dma0_eop__WIDTH 1 -#define R_IRQ_MASK2_RD__dma0_eop__active 1 -#define R_IRQ_MASK2_RD__dma0_eop__inactive 0 -#define R_IRQ_MASK2_RD__dma0_descr__BITNR 0 -#define R_IRQ_MASK2_RD__dma0_descr__WIDTH 1 -#define R_IRQ_MASK2_RD__dma0_descr__active 1 -#define R_IRQ_MASK2_RD__dma0_descr__inactive 0 - -#define R_IRQ_MASK2_CLR (IO_TYPECAST_UDWORD 0xb00000d0) -#define R_IRQ_MASK2_CLR__dma8_sub3_descr__BITNR 23 -#define R_IRQ_MASK2_CLR__dma8_sub3_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma8_sub3_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma8_sub3_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma8_sub2_descr__BITNR 22 -#define R_IRQ_MASK2_CLR__dma8_sub2_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma8_sub2_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma8_sub2_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma8_sub1_descr__BITNR 21 -#define R_IRQ_MASK2_CLR__dma8_sub1_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma8_sub1_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma8_sub1_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma8_sub0_descr__BITNR 20 -#define R_IRQ_MASK2_CLR__dma8_sub0_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma8_sub0_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma8_sub0_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma9_eop__BITNR 19 -#define R_IRQ_MASK2_CLR__dma9_eop__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma9_eop__clr 1 -#define R_IRQ_MASK2_CLR__dma9_eop__nop 0 -#define R_IRQ_MASK2_CLR__dma9_descr__BITNR 18 -#define R_IRQ_MASK2_CLR__dma9_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma9_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma9_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma8_eop__BITNR 17 -#define R_IRQ_MASK2_CLR__dma8_eop__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma8_eop__clr 1 -#define R_IRQ_MASK2_CLR__dma8_eop__nop 0 -#define R_IRQ_MASK2_CLR__dma8_descr__BITNR 16 -#define R_IRQ_MASK2_CLR__dma8_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma8_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma8_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma7_eop__BITNR 15 -#define R_IRQ_MASK2_CLR__dma7_eop__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma7_eop__clr 1 -#define R_IRQ_MASK2_CLR__dma7_eop__nop 0 -#define R_IRQ_MASK2_CLR__dma7_descr__BITNR 14 -#define R_IRQ_MASK2_CLR__dma7_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma7_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma7_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma6_eop__BITNR 13 -#define R_IRQ_MASK2_CLR__dma6_eop__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma6_eop__clr 1 -#define R_IRQ_MASK2_CLR__dma6_eop__nop 0 -#define R_IRQ_MASK2_CLR__dma6_descr__BITNR 12 -#define R_IRQ_MASK2_CLR__dma6_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma6_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma6_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma5_eop__BITNR 11 -#define R_IRQ_MASK2_CLR__dma5_eop__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma5_eop__clr 1 -#define R_IRQ_MASK2_CLR__dma5_eop__nop 0 -#define R_IRQ_MASK2_CLR__dma5_descr__BITNR 10 -#define R_IRQ_MASK2_CLR__dma5_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma5_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma5_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma4_eop__BITNR 9 -#define R_IRQ_MASK2_CLR__dma4_eop__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma4_eop__clr 1 -#define R_IRQ_MASK2_CLR__dma4_eop__nop 0 -#define R_IRQ_MASK2_CLR__dma4_descr__BITNR 8 -#define R_IRQ_MASK2_CLR__dma4_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma4_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma4_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma3_eop__BITNR 7 -#define R_IRQ_MASK2_CLR__dma3_eop__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma3_eop__clr 1 -#define R_IRQ_MASK2_CLR__dma3_eop__nop 0 -#define R_IRQ_MASK2_CLR__dma3_descr__BITNR 6 -#define R_IRQ_MASK2_CLR__dma3_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma3_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma3_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma2_eop__BITNR 5 -#define R_IRQ_MASK2_CLR__dma2_eop__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma2_eop__clr 1 -#define R_IRQ_MASK2_CLR__dma2_eop__nop 0 -#define R_IRQ_MASK2_CLR__dma2_descr__BITNR 4 -#define R_IRQ_MASK2_CLR__dma2_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma2_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma2_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma1_eop__BITNR 3 -#define R_IRQ_MASK2_CLR__dma1_eop__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma1_eop__clr 1 -#define R_IRQ_MASK2_CLR__dma1_eop__nop 0 -#define R_IRQ_MASK2_CLR__dma1_descr__BITNR 2 -#define R_IRQ_MASK2_CLR__dma1_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma1_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma1_descr__nop 0 -#define R_IRQ_MASK2_CLR__dma0_eop__BITNR 1 -#define R_IRQ_MASK2_CLR__dma0_eop__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma0_eop__clr 1 -#define R_IRQ_MASK2_CLR__dma0_eop__nop 0 -#define R_IRQ_MASK2_CLR__dma0_descr__BITNR 0 -#define R_IRQ_MASK2_CLR__dma0_descr__WIDTH 1 -#define R_IRQ_MASK2_CLR__dma0_descr__clr 1 -#define R_IRQ_MASK2_CLR__dma0_descr__nop 0 - -#define R_IRQ_READ2 (IO_TYPECAST_RO_UDWORD 0xb00000d4) -#define R_IRQ_READ2__dma8_sub3_descr__BITNR 23 -#define R_IRQ_READ2__dma8_sub3_descr__WIDTH 1 -#define R_IRQ_READ2__dma8_sub3_descr__active 1 -#define R_IRQ_READ2__dma8_sub3_descr__inactive 0 -#define R_IRQ_READ2__dma8_sub2_descr__BITNR 22 -#define R_IRQ_READ2__dma8_sub2_descr__WIDTH 1 -#define R_IRQ_READ2__dma8_sub2_descr__active 1 -#define R_IRQ_READ2__dma8_sub2_descr__inactive 0 -#define R_IRQ_READ2__dma8_sub1_descr__BITNR 21 -#define R_IRQ_READ2__dma8_sub1_descr__WIDTH 1 -#define R_IRQ_READ2__dma8_sub1_descr__active 1 -#define R_IRQ_READ2__dma8_sub1_descr__inactive 0 -#define R_IRQ_READ2__dma8_sub0_descr__BITNR 20 -#define R_IRQ_READ2__dma8_sub0_descr__WIDTH 1 -#define R_IRQ_READ2__dma8_sub0_descr__active 1 -#define R_IRQ_READ2__dma8_sub0_descr__inactive 0 -#define R_IRQ_READ2__dma9_eop__BITNR 19 -#define R_IRQ_READ2__dma9_eop__WIDTH 1 -#define R_IRQ_READ2__dma9_eop__active 1 -#define R_IRQ_READ2__dma9_eop__inactive 0 -#define R_IRQ_READ2__dma9_descr__BITNR 18 -#define R_IRQ_READ2__dma9_descr__WIDTH 1 -#define R_IRQ_READ2__dma9_descr__active 1 -#define R_IRQ_READ2__dma9_descr__inactive 0 -#define R_IRQ_READ2__dma8_eop__BITNR 17 -#define R_IRQ_READ2__dma8_eop__WIDTH 1 -#define R_IRQ_READ2__dma8_eop__active 1 -#define R_IRQ_READ2__dma8_eop__inactive 0 -#define R_IRQ_READ2__dma8_descr__BITNR 16 -#define R_IRQ_READ2__dma8_descr__WIDTH 1 -#define R_IRQ_READ2__dma8_descr__active 1 -#define R_IRQ_READ2__dma8_descr__inactive 0 -#define R_IRQ_READ2__dma7_eop__BITNR 15 -#define R_IRQ_READ2__dma7_eop__WIDTH 1 -#define R_IRQ_READ2__dma7_eop__active 1 -#define R_IRQ_READ2__dma7_eop__inactive 0 -#define R_IRQ_READ2__dma7_descr__BITNR 14 -#define R_IRQ_READ2__dma7_descr__WIDTH 1 -#define R_IRQ_READ2__dma7_descr__active 1 -#define R_IRQ_READ2__dma7_descr__inactive 0 -#define R_IRQ_READ2__dma6_eop__BITNR 13 -#define R_IRQ_READ2__dma6_eop__WIDTH 1 -#define R_IRQ_READ2__dma6_eop__active 1 -#define R_IRQ_READ2__dma6_eop__inactive 0 -#define R_IRQ_READ2__dma6_descr__BITNR 12 -#define R_IRQ_READ2__dma6_descr__WIDTH 1 -#define R_IRQ_READ2__dma6_descr__active 1 -#define R_IRQ_READ2__dma6_descr__inactive 0 -#define R_IRQ_READ2__dma5_eop__BITNR 11 -#define R_IRQ_READ2__dma5_eop__WIDTH 1 -#define R_IRQ_READ2__dma5_eop__active 1 -#define R_IRQ_READ2__dma5_eop__inactive 0 -#define R_IRQ_READ2__dma5_descr__BITNR 10 -#define R_IRQ_READ2__dma5_descr__WIDTH 1 -#define R_IRQ_READ2__dma5_descr__active 1 -#define R_IRQ_READ2__dma5_descr__inactive 0 -#define R_IRQ_READ2__dma4_eop__BITNR 9 -#define R_IRQ_READ2__dma4_eop__WIDTH 1 -#define R_IRQ_READ2__dma4_eop__active 1 -#define R_IRQ_READ2__dma4_eop__inactive 0 -#define R_IRQ_READ2__dma4_descr__BITNR 8 -#define R_IRQ_READ2__dma4_descr__WIDTH 1 -#define R_IRQ_READ2__dma4_descr__active 1 -#define R_IRQ_READ2__dma4_descr__inactive 0 -#define R_IRQ_READ2__dma3_eop__BITNR 7 -#define R_IRQ_READ2__dma3_eop__WIDTH 1 -#define R_IRQ_READ2__dma3_eop__active 1 -#define R_IRQ_READ2__dma3_eop__inactive 0 -#define R_IRQ_READ2__dma3_descr__BITNR 6 -#define R_IRQ_READ2__dma3_descr__WIDTH 1 -#define R_IRQ_READ2__dma3_descr__active 1 -#define R_IRQ_READ2__dma3_descr__inactive 0 -#define R_IRQ_READ2__dma2_eop__BITNR 5 -#define R_IRQ_READ2__dma2_eop__WIDTH 1 -#define R_IRQ_READ2__dma2_eop__active 1 -#define R_IRQ_READ2__dma2_eop__inactive 0 -#define R_IRQ_READ2__dma2_descr__BITNR 4 -#define R_IRQ_READ2__dma2_descr__WIDTH 1 -#define R_IRQ_READ2__dma2_descr__active 1 -#define R_IRQ_READ2__dma2_descr__inactive 0 -#define R_IRQ_READ2__dma1_eop__BITNR 3 -#define R_IRQ_READ2__dma1_eop__WIDTH 1 -#define R_IRQ_READ2__dma1_eop__active 1 -#define R_IRQ_READ2__dma1_eop__inactive 0 -#define R_IRQ_READ2__dma1_descr__BITNR 2 -#define R_IRQ_READ2__dma1_descr__WIDTH 1 -#define R_IRQ_READ2__dma1_descr__active 1 -#define R_IRQ_READ2__dma1_descr__inactive 0 -#define R_IRQ_READ2__dma0_eop__BITNR 1 -#define R_IRQ_READ2__dma0_eop__WIDTH 1 -#define R_IRQ_READ2__dma0_eop__active 1 -#define R_IRQ_READ2__dma0_eop__inactive 0 -#define R_IRQ_READ2__dma0_descr__BITNR 0 -#define R_IRQ_READ2__dma0_descr__WIDTH 1 -#define R_IRQ_READ2__dma0_descr__active 1 -#define R_IRQ_READ2__dma0_descr__inactive 0 - -#define R_IRQ_MASK2_SET (IO_TYPECAST_UDWORD 0xb00000d4) -#define R_IRQ_MASK2_SET__dma8_sub3_descr__BITNR 23 -#define R_IRQ_MASK2_SET__dma8_sub3_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma8_sub3_descr__set 1 -#define R_IRQ_MASK2_SET__dma8_sub3_descr__nop 0 -#define R_IRQ_MASK2_SET__dma8_sub2_descr__BITNR 22 -#define R_IRQ_MASK2_SET__dma8_sub2_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma8_sub2_descr__set 1 -#define R_IRQ_MASK2_SET__dma8_sub2_descr__nop 0 -#define R_IRQ_MASK2_SET__dma8_sub1_descr__BITNR 21 -#define R_IRQ_MASK2_SET__dma8_sub1_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma8_sub1_descr__set 1 -#define R_IRQ_MASK2_SET__dma8_sub1_descr__nop 0 -#define R_IRQ_MASK2_SET__dma8_sub0_descr__BITNR 20 -#define R_IRQ_MASK2_SET__dma8_sub0_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma8_sub0_descr__set 1 -#define R_IRQ_MASK2_SET__dma8_sub0_descr__nop 0 -#define R_IRQ_MASK2_SET__dma9_eop__BITNR 19 -#define R_IRQ_MASK2_SET__dma9_eop__WIDTH 1 -#define R_IRQ_MASK2_SET__dma9_eop__set 1 -#define R_IRQ_MASK2_SET__dma9_eop__nop 0 -#define R_IRQ_MASK2_SET__dma9_descr__BITNR 18 -#define R_IRQ_MASK2_SET__dma9_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma9_descr__set 1 -#define R_IRQ_MASK2_SET__dma9_descr__nop 0 -#define R_IRQ_MASK2_SET__dma8_eop__BITNR 17 -#define R_IRQ_MASK2_SET__dma8_eop__WIDTH 1 -#define R_IRQ_MASK2_SET__dma8_eop__set 1 -#define R_IRQ_MASK2_SET__dma8_eop__nop 0 -#define R_IRQ_MASK2_SET__dma8_descr__BITNR 16 -#define R_IRQ_MASK2_SET__dma8_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma8_descr__set 1 -#define R_IRQ_MASK2_SET__dma8_descr__nop 0 -#define R_IRQ_MASK2_SET__dma7_eop__BITNR 15 -#define R_IRQ_MASK2_SET__dma7_eop__WIDTH 1 -#define R_IRQ_MASK2_SET__dma7_eop__set 1 -#define R_IRQ_MASK2_SET__dma7_eop__nop 0 -#define R_IRQ_MASK2_SET__dma7_descr__BITNR 14 -#define R_IRQ_MASK2_SET__dma7_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma7_descr__set 1 -#define R_IRQ_MASK2_SET__dma7_descr__nop 0 -#define R_IRQ_MASK2_SET__dma6_eop__BITNR 13 -#define R_IRQ_MASK2_SET__dma6_eop__WIDTH 1 -#define R_IRQ_MASK2_SET__dma6_eop__set 1 -#define R_IRQ_MASK2_SET__dma6_eop__nop 0 -#define R_IRQ_MASK2_SET__dma6_descr__BITNR 12 -#define R_IRQ_MASK2_SET__dma6_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma6_descr__set 1 -#define R_IRQ_MASK2_SET__dma6_descr__nop 0 -#define R_IRQ_MASK2_SET__dma5_eop__BITNR 11 -#define R_IRQ_MASK2_SET__dma5_eop__WIDTH 1 -#define R_IRQ_MASK2_SET__dma5_eop__set 1 -#define R_IRQ_MASK2_SET__dma5_eop__nop 0 -#define R_IRQ_MASK2_SET__dma5_descr__BITNR 10 -#define R_IRQ_MASK2_SET__dma5_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma5_descr__set 1 -#define R_IRQ_MASK2_SET__dma5_descr__nop 0 -#define R_IRQ_MASK2_SET__dma4_eop__BITNR 9 -#define R_IRQ_MASK2_SET__dma4_eop__WIDTH 1 -#define R_IRQ_MASK2_SET__dma4_eop__set 1 -#define R_IRQ_MASK2_SET__dma4_eop__nop 0 -#define R_IRQ_MASK2_SET__dma4_descr__BITNR 8 -#define R_IRQ_MASK2_SET__dma4_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma4_descr__set 1 -#define R_IRQ_MASK2_SET__dma4_descr__nop 0 -#define R_IRQ_MASK2_SET__dma3_eop__BITNR 7 -#define R_IRQ_MASK2_SET__dma3_eop__WIDTH 1 -#define R_IRQ_MASK2_SET__dma3_eop__set 1 -#define R_IRQ_MASK2_SET__dma3_eop__nop 0 -#define R_IRQ_MASK2_SET__dma3_descr__BITNR 6 -#define R_IRQ_MASK2_SET__dma3_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma3_descr__set 1 -#define R_IRQ_MASK2_SET__dma3_descr__nop 0 -#define R_IRQ_MASK2_SET__dma2_eop__BITNR 5 -#define R_IRQ_MASK2_SET__dma2_eop__WIDTH 1 -#define R_IRQ_MASK2_SET__dma2_eop__set 1 -#define R_IRQ_MASK2_SET__dma2_eop__nop 0 -#define R_IRQ_MASK2_SET__dma2_descr__BITNR 4 -#define R_IRQ_MASK2_SET__dma2_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma2_descr__set 1 -#define R_IRQ_MASK2_SET__dma2_descr__nop 0 -#define R_IRQ_MASK2_SET__dma1_eop__BITNR 3 -#define R_IRQ_MASK2_SET__dma1_eop__WIDTH 1 -#define R_IRQ_MASK2_SET__dma1_eop__set 1 -#define R_IRQ_MASK2_SET__dma1_eop__nop 0 -#define R_IRQ_MASK2_SET__dma1_descr__BITNR 2 -#define R_IRQ_MASK2_SET__dma1_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma1_descr__set 1 -#define R_IRQ_MASK2_SET__dma1_descr__nop 0 -#define R_IRQ_MASK2_SET__dma0_eop__BITNR 1 -#define R_IRQ_MASK2_SET__dma0_eop__WIDTH 1 -#define R_IRQ_MASK2_SET__dma0_eop__set 1 -#define R_IRQ_MASK2_SET__dma0_eop__nop 0 -#define R_IRQ_MASK2_SET__dma0_descr__BITNR 0 -#define R_IRQ_MASK2_SET__dma0_descr__WIDTH 1 -#define R_IRQ_MASK2_SET__dma0_descr__set 1 -#define R_IRQ_MASK2_SET__dma0_descr__nop 0 - -#define R_VECT_MASK_RD (IO_TYPECAST_RO_UDWORD 0xb00000d8) -#define R_VECT_MASK_RD__usb__BITNR 31 -#define R_VECT_MASK_RD__usb__WIDTH 1 -#define R_VECT_MASK_RD__usb__active 1 -#define R_VECT_MASK_RD__usb__inactive 0 -#define R_VECT_MASK_RD__dma9__BITNR 25 -#define R_VECT_MASK_RD__dma9__WIDTH 1 -#define R_VECT_MASK_RD__dma9__active 1 -#define R_VECT_MASK_RD__dma9__inactive 0 -#define R_VECT_MASK_RD__dma8__BITNR 24 -#define R_VECT_MASK_RD__dma8__WIDTH 1 -#define R_VECT_MASK_RD__dma8__active 1 -#define R_VECT_MASK_RD__dma8__inactive 0 -#define R_VECT_MASK_RD__dma7__BITNR 23 -#define R_VECT_MASK_RD__dma7__WIDTH 1 -#define R_VECT_MASK_RD__dma7__active 1 -#define R_VECT_MASK_RD__dma7__inactive 0 -#define R_VECT_MASK_RD__dma6__BITNR 22 -#define R_VECT_MASK_RD__dma6__WIDTH 1 -#define R_VECT_MASK_RD__dma6__active 1 -#define R_VECT_MASK_RD__dma6__inactive 0 -#define R_VECT_MASK_RD__dma5__BITNR 21 -#define R_VECT_MASK_RD__dma5__WIDTH 1 -#define R_VECT_MASK_RD__dma5__active 1 -#define R_VECT_MASK_RD__dma5__inactive 0 -#define R_VECT_MASK_RD__dma4__BITNR 20 -#define R_VECT_MASK_RD__dma4__WIDTH 1 -#define R_VECT_MASK_RD__dma4__active 1 -#define R_VECT_MASK_RD__dma4__inactive 0 -#define R_VECT_MASK_RD__dma3__BITNR 19 -#define R_VECT_MASK_RD__dma3__WIDTH 1 -#define R_VECT_MASK_RD__dma3__active 1 -#define R_VECT_MASK_RD__dma3__inactive 0 -#define R_VECT_MASK_RD__dma2__BITNR 18 -#define R_VECT_MASK_RD__dma2__WIDTH 1 -#define R_VECT_MASK_RD__dma2__active 1 -#define R_VECT_MASK_RD__dma2__inactive 0 -#define R_VECT_MASK_RD__dma1__BITNR 17 -#define R_VECT_MASK_RD__dma1__WIDTH 1 -#define R_VECT_MASK_RD__dma1__active 1 -#define R_VECT_MASK_RD__dma1__inactive 0 -#define R_VECT_MASK_RD__dma0__BITNR 16 -#define R_VECT_MASK_RD__dma0__WIDTH 1 -#define R_VECT_MASK_RD__dma0__active 1 -#define R_VECT_MASK_RD__dma0__inactive 0 -#define R_VECT_MASK_RD__ext_dma1__BITNR 13 -#define R_VECT_MASK_RD__ext_dma1__WIDTH 1 -#define R_VECT_MASK_RD__ext_dma1__active 1 -#define R_VECT_MASK_RD__ext_dma1__inactive 0 -#define R_VECT_MASK_RD__ext_dma0__BITNR 12 -#define R_VECT_MASK_RD__ext_dma0__WIDTH 1 -#define R_VECT_MASK_RD__ext_dma0__active 1 -#define R_VECT_MASK_RD__ext_dma0__inactive 0 -#define R_VECT_MASK_RD__pa__BITNR 11 -#define R_VECT_MASK_RD__pa__WIDTH 1 -#define R_VECT_MASK_RD__pa__active 1 -#define R_VECT_MASK_RD__pa__inactive 0 -#define R_VECT_MASK_RD__irq_intnr__BITNR 10 -#define R_VECT_MASK_RD__irq_intnr__WIDTH 1 -#define R_VECT_MASK_RD__irq_intnr__active 1 -#define R_VECT_MASK_RD__irq_intnr__inactive 0 -#define R_VECT_MASK_RD__sw__BITNR 9 -#define R_VECT_MASK_RD__sw__WIDTH 1 -#define R_VECT_MASK_RD__sw__active 1 -#define R_VECT_MASK_RD__sw__inactive 0 -#define R_VECT_MASK_RD__serial__BITNR 8 -#define R_VECT_MASK_RD__serial__WIDTH 1 -#define R_VECT_MASK_RD__serial__active 1 -#define R_VECT_MASK_RD__serial__inactive 0 -#define R_VECT_MASK_RD__snmp__BITNR 7 -#define R_VECT_MASK_RD__snmp__WIDTH 1 -#define R_VECT_MASK_RD__snmp__active 1 -#define R_VECT_MASK_RD__snmp__inactive 0 -#define R_VECT_MASK_RD__network__BITNR 6 -#define R_VECT_MASK_RD__network__WIDTH 1 -#define R_VECT_MASK_RD__network__active 1 -#define R_VECT_MASK_RD__network__inactive 0 -#define R_VECT_MASK_RD__scsi1__BITNR 5 -#define R_VECT_MASK_RD__scsi1__WIDTH 1 -#define R_VECT_MASK_RD__scsi1__active 1 -#define R_VECT_MASK_RD__scsi1__inactive 0 -#define R_VECT_MASK_RD__par1__BITNR 5 -#define R_VECT_MASK_RD__par1__WIDTH 1 -#define R_VECT_MASK_RD__par1__active 1 -#define R_VECT_MASK_RD__par1__inactive 0 -#define R_VECT_MASK_RD__scsi0__BITNR 4 -#define R_VECT_MASK_RD__scsi0__WIDTH 1 -#define R_VECT_MASK_RD__scsi0__active 1 -#define R_VECT_MASK_RD__scsi0__inactive 0 -#define R_VECT_MASK_RD__par0__BITNR 4 -#define R_VECT_MASK_RD__par0__WIDTH 1 -#define R_VECT_MASK_RD__par0__active 1 -#define R_VECT_MASK_RD__par0__inactive 0 -#define R_VECT_MASK_RD__ata__BITNR 4 -#define R_VECT_MASK_RD__ata__WIDTH 1 -#define R_VECT_MASK_RD__ata__active 1 -#define R_VECT_MASK_RD__ata__inactive 0 -#define R_VECT_MASK_RD__mio__BITNR 4 -#define R_VECT_MASK_RD__mio__WIDTH 1 -#define R_VECT_MASK_RD__mio__active 1 -#define R_VECT_MASK_RD__mio__inactive 0 -#define R_VECT_MASK_RD__timer1__BITNR 3 -#define R_VECT_MASK_RD__timer1__WIDTH 1 -#define R_VECT_MASK_RD__timer1__active 1 -#define R_VECT_MASK_RD__timer1__inactive 0 -#define R_VECT_MASK_RD__timer0__BITNR 2 -#define R_VECT_MASK_RD__timer0__WIDTH 1 -#define R_VECT_MASK_RD__timer0__active 1 -#define R_VECT_MASK_RD__timer0__inactive 0 -#define R_VECT_MASK_RD__nmi__BITNR 1 -#define R_VECT_MASK_RD__nmi__WIDTH 1 -#define R_VECT_MASK_RD__nmi__active 1 -#define R_VECT_MASK_RD__nmi__inactive 0 -#define R_VECT_MASK_RD__some__BITNR 0 -#define R_VECT_MASK_RD__some__WIDTH 1 -#define R_VECT_MASK_RD__some__active 1 -#define R_VECT_MASK_RD__some__inactive 0 - -#define R_VECT_MASK_CLR (IO_TYPECAST_UDWORD 0xb00000d8) -#define R_VECT_MASK_CLR__usb__BITNR 31 -#define R_VECT_MASK_CLR__usb__WIDTH 1 -#define R_VECT_MASK_CLR__usb__clr 1 -#define R_VECT_MASK_CLR__usb__nop 0 -#define R_VECT_MASK_CLR__dma9__BITNR 25 -#define R_VECT_MASK_CLR__dma9__WIDTH 1 -#define R_VECT_MASK_CLR__dma9__clr 1 -#define R_VECT_MASK_CLR__dma9__nop 0 -#define R_VECT_MASK_CLR__dma8__BITNR 24 -#define R_VECT_MASK_CLR__dma8__WIDTH 1 -#define R_VECT_MASK_CLR__dma8__clr 1 -#define R_VECT_MASK_CLR__dma8__nop 0 -#define R_VECT_MASK_CLR__dma7__BITNR 23 -#define R_VECT_MASK_CLR__dma7__WIDTH 1 -#define R_VECT_MASK_CLR__dma7__clr 1 -#define R_VECT_MASK_CLR__dma7__nop 0 -#define R_VECT_MASK_CLR__dma6__BITNR 22 -#define R_VECT_MASK_CLR__dma6__WIDTH 1 -#define R_VECT_MASK_CLR__dma6__clr 1 -#define R_VECT_MASK_CLR__dma6__nop 0 -#define R_VECT_MASK_CLR__dma5__BITNR 21 -#define R_VECT_MASK_CLR__dma5__WIDTH 1 -#define R_VECT_MASK_CLR__dma5__clr 1 -#define R_VECT_MASK_CLR__dma5__nop 0 -#define R_VECT_MASK_CLR__dma4__BITNR 20 -#define R_VECT_MASK_CLR__dma4__WIDTH 1 -#define R_VECT_MASK_CLR__dma4__clr 1 -#define R_VECT_MASK_CLR__dma4__nop 0 -#define R_VECT_MASK_CLR__dma3__BITNR 19 -#define R_VECT_MASK_CLR__dma3__WIDTH 1 -#define R_VECT_MASK_CLR__dma3__clr 1 -#define R_VECT_MASK_CLR__dma3__nop 0 -#define R_VECT_MASK_CLR__dma2__BITNR 18 -#define R_VECT_MASK_CLR__dma2__WIDTH 1 -#define R_VECT_MASK_CLR__dma2__clr 1 -#define R_VECT_MASK_CLR__dma2__nop 0 -#define R_VECT_MASK_CLR__dma1__BITNR 17 -#define R_VECT_MASK_CLR__dma1__WIDTH 1 -#define R_VECT_MASK_CLR__dma1__clr 1 -#define R_VECT_MASK_CLR__dma1__nop 0 -#define R_VECT_MASK_CLR__dma0__BITNR 16 -#define R_VECT_MASK_CLR__dma0__WIDTH 1 -#define R_VECT_MASK_CLR__dma0__clr 1 -#define R_VECT_MASK_CLR__dma0__nop 0 -#define R_VECT_MASK_CLR__ext_dma1__BITNR 13 -#define R_VECT_MASK_CLR__ext_dma1__WIDTH 1 -#define R_VECT_MASK_CLR__ext_dma1__clr 1 -#define R_VECT_MASK_CLR__ext_dma1__nop 0 -#define R_VECT_MASK_CLR__ext_dma0__BITNR 12 -#define R_VECT_MASK_CLR__ext_dma0__WIDTH 1 -#define R_VECT_MASK_CLR__ext_dma0__clr 1 -#define R_VECT_MASK_CLR__ext_dma0__nop 0 -#define R_VECT_MASK_CLR__pa__BITNR 11 -#define R_VECT_MASK_CLR__pa__WIDTH 1 -#define R_VECT_MASK_CLR__pa__clr 1 -#define R_VECT_MASK_CLR__pa__nop 0 -#define R_VECT_MASK_CLR__irq_intnr__BITNR 10 -#define R_VECT_MASK_CLR__irq_intnr__WIDTH 1 -#define R_VECT_MASK_CLR__irq_intnr__clr 1 -#define R_VECT_MASK_CLR__irq_intnr__nop 0 -#define R_VECT_MASK_CLR__sw__BITNR 9 -#define R_VECT_MASK_CLR__sw__WIDTH 1 -#define R_VECT_MASK_CLR__sw__clr 1 -#define R_VECT_MASK_CLR__sw__nop 0 -#define R_VECT_MASK_CLR__serial__BITNR 8 -#define R_VECT_MASK_CLR__serial__WIDTH 1 -#define R_VECT_MASK_CLR__serial__clr 1 -#define R_VECT_MASK_CLR__serial__nop 0 -#define R_VECT_MASK_CLR__snmp__BITNR 7 -#define R_VECT_MASK_CLR__snmp__WIDTH 1 -#define R_VECT_MASK_CLR__snmp__clr 1 -#define R_VECT_MASK_CLR__snmp__nop 0 -#define R_VECT_MASK_CLR__network__BITNR 6 -#define R_VECT_MASK_CLR__network__WIDTH 1 -#define R_VECT_MASK_CLR__network__clr 1 -#define R_VECT_MASK_CLR__network__nop 0 -#define R_VECT_MASK_CLR__scsi1__BITNR 5 -#define R_VECT_MASK_CLR__scsi1__WIDTH 1 -#define R_VECT_MASK_CLR__scsi1__clr 1 -#define R_VECT_MASK_CLR__scsi1__nop 0 -#define R_VECT_MASK_CLR__par1__BITNR 5 -#define R_VECT_MASK_CLR__par1__WIDTH 1 -#define R_VECT_MASK_CLR__par1__clr 1 -#define R_VECT_MASK_CLR__par1__nop 0 -#define R_VECT_MASK_CLR__scsi0__BITNR 4 -#define R_VECT_MASK_CLR__scsi0__WIDTH 1 -#define R_VECT_MASK_CLR__scsi0__clr 1 -#define R_VECT_MASK_CLR__scsi0__nop 0 -#define R_VECT_MASK_CLR__par0__BITNR 4 -#define R_VECT_MASK_CLR__par0__WIDTH 1 -#define R_VECT_MASK_CLR__par0__clr 1 -#define R_VECT_MASK_CLR__par0__nop 0 -#define R_VECT_MASK_CLR__ata__BITNR 4 -#define R_VECT_MASK_CLR__ata__WIDTH 1 -#define R_VECT_MASK_CLR__ata__clr 1 -#define R_VECT_MASK_CLR__ata__nop 0 -#define R_VECT_MASK_CLR__mio__BITNR 4 -#define R_VECT_MASK_CLR__mio__WIDTH 1 -#define R_VECT_MASK_CLR__mio__clr 1 -#define R_VECT_MASK_CLR__mio__nop 0 -#define R_VECT_MASK_CLR__timer1__BITNR 3 -#define R_VECT_MASK_CLR__timer1__WIDTH 1 -#define R_VECT_MASK_CLR__timer1__clr 1 -#define R_VECT_MASK_CLR__timer1__nop 0 -#define R_VECT_MASK_CLR__timer0__BITNR 2 -#define R_VECT_MASK_CLR__timer0__WIDTH 1 -#define R_VECT_MASK_CLR__timer0__clr 1 -#define R_VECT_MASK_CLR__timer0__nop 0 -#define R_VECT_MASK_CLR__nmi__BITNR 1 -#define R_VECT_MASK_CLR__nmi__WIDTH 1 -#define R_VECT_MASK_CLR__nmi__clr 1 -#define R_VECT_MASK_CLR__nmi__nop 0 -#define R_VECT_MASK_CLR__some__BITNR 0 -#define R_VECT_MASK_CLR__some__WIDTH 1 -#define R_VECT_MASK_CLR__some__clr 1 -#define R_VECT_MASK_CLR__some__nop 0 - -#define R_VECT_READ (IO_TYPECAST_RO_UDWORD 0xb00000dc) -#define R_VECT_READ__usb__BITNR 31 -#define R_VECT_READ__usb__WIDTH 1 -#define R_VECT_READ__usb__active 1 -#define R_VECT_READ__usb__inactive 0 -#define R_VECT_READ__dma9__BITNR 25 -#define R_VECT_READ__dma9__WIDTH 1 -#define R_VECT_READ__dma9__active 1 -#define R_VECT_READ__dma9__inactive 0 -#define R_VECT_READ__dma8__BITNR 24 -#define R_VECT_READ__dma8__WIDTH 1 -#define R_VECT_READ__dma8__active 1 -#define R_VECT_READ__dma8__inactive 0 -#define R_VECT_READ__dma7__BITNR 23 -#define R_VECT_READ__dma7__WIDTH 1 -#define R_VECT_READ__dma7__active 1 -#define R_VECT_READ__dma7__inactive 0 -#define R_VECT_READ__dma6__BITNR 22 -#define R_VECT_READ__dma6__WIDTH 1 -#define R_VECT_READ__dma6__active 1 -#define R_VECT_READ__dma6__inactive 0 -#define R_VECT_READ__dma5__BITNR 21 -#define R_VECT_READ__dma5__WIDTH 1 -#define R_VECT_READ__dma5__active 1 -#define R_VECT_READ__dma5__inactive 0 -#define R_VECT_READ__dma4__BITNR 20 -#define R_VECT_READ__dma4__WIDTH 1 -#define R_VECT_READ__dma4__active 1 -#define R_VECT_READ__dma4__inactive 0 -#define R_VECT_READ__dma3__BITNR 19 -#define R_VECT_READ__dma3__WIDTH 1 -#define R_VECT_READ__dma3__active 1 -#define R_VECT_READ__dma3__inactive 0 -#define R_VECT_READ__dma2__BITNR 18 -#define R_VECT_READ__dma2__WIDTH 1 -#define R_VECT_READ__dma2__active 1 -#define R_VECT_READ__dma2__inactive 0 -#define R_VECT_READ__dma1__BITNR 17 -#define R_VECT_READ__dma1__WIDTH 1 -#define R_VECT_READ__dma1__active 1 -#define R_VECT_READ__dma1__inactive 0 -#define R_VECT_READ__dma0__BITNR 16 -#define R_VECT_READ__dma0__WIDTH 1 -#define R_VECT_READ__dma0__active 1 -#define R_VECT_READ__dma0__inactive 0 -#define R_VECT_READ__ext_dma1__BITNR 13 -#define R_VECT_READ__ext_dma1__WIDTH 1 -#define R_VECT_READ__ext_dma1__active 1 -#define R_VECT_READ__ext_dma1__inactive 0 -#define R_VECT_READ__ext_dma0__BITNR 12 -#define R_VECT_READ__ext_dma0__WIDTH 1 -#define R_VECT_READ__ext_dma0__active 1 -#define R_VECT_READ__ext_dma0__inactive 0 -#define R_VECT_READ__pa__BITNR 11 -#define R_VECT_READ__pa__WIDTH 1 -#define R_VECT_READ__pa__active 1 -#define R_VECT_READ__pa__inactive 0 -#define R_VECT_READ__irq_intnr__BITNR 10 -#define R_VECT_READ__irq_intnr__WIDTH 1 -#define R_VECT_READ__irq_intnr__active 1 -#define R_VECT_READ__irq_intnr__inactive 0 -#define R_VECT_READ__sw__BITNR 9 -#define R_VECT_READ__sw__WIDTH 1 -#define R_VECT_READ__sw__active 1 -#define R_VECT_READ__sw__inactive 0 -#define R_VECT_READ__serial__BITNR 8 -#define R_VECT_READ__serial__WIDTH 1 -#define R_VECT_READ__serial__active 1 -#define R_VECT_READ__serial__inactive 0 -#define R_VECT_READ__snmp__BITNR 7 -#define R_VECT_READ__snmp__WIDTH 1 -#define R_VECT_READ__snmp__active 1 -#define R_VECT_READ__snmp__inactive 0 -#define R_VECT_READ__network__BITNR 6 -#define R_VECT_READ__network__WIDTH 1 -#define R_VECT_READ__network__active 1 -#define R_VECT_READ__network__inactive 0 -#define R_VECT_READ__scsi1__BITNR 5 -#define R_VECT_READ__scsi1__WIDTH 1 -#define R_VECT_READ__scsi1__active 1 -#define R_VECT_READ__scsi1__inactive 0 -#define R_VECT_READ__par1__BITNR 5 -#define R_VECT_READ__par1__WIDTH 1 -#define R_VECT_READ__par1__active 1 -#define R_VECT_READ__par1__inactive 0 -#define R_VECT_READ__scsi0__BITNR 4 -#define R_VECT_READ__scsi0__WIDTH 1 -#define R_VECT_READ__scsi0__active 1 -#define R_VECT_READ__scsi0__inactive 0 -#define R_VECT_READ__par0__BITNR 4 -#define R_VECT_READ__par0__WIDTH 1 -#define R_VECT_READ__par0__active 1 -#define R_VECT_READ__par0__inactive 0 -#define R_VECT_READ__ata__BITNR 4 -#define R_VECT_READ__ata__WIDTH 1 -#define R_VECT_READ__ata__active 1 -#define R_VECT_READ__ata__inactive 0 -#define R_VECT_READ__mio__BITNR 4 -#define R_VECT_READ__mio__WIDTH 1 -#define R_VECT_READ__mio__active 1 -#define R_VECT_READ__mio__inactive 0 -#define R_VECT_READ__timer1__BITNR 3 -#define R_VECT_READ__timer1__WIDTH 1 -#define R_VECT_READ__timer1__active 1 -#define R_VECT_READ__timer1__inactive 0 -#define R_VECT_READ__timer0__BITNR 2 -#define R_VECT_READ__timer0__WIDTH 1 -#define R_VECT_READ__timer0__active 1 -#define R_VECT_READ__timer0__inactive 0 -#define R_VECT_READ__nmi__BITNR 1 -#define R_VECT_READ__nmi__WIDTH 1 -#define R_VECT_READ__nmi__active 1 -#define R_VECT_READ__nmi__inactive 0 -#define R_VECT_READ__some__BITNR 0 -#define R_VECT_READ__some__WIDTH 1 -#define R_VECT_READ__some__active 1 -#define R_VECT_READ__some__inactive 0 - -#define R_VECT_MASK_SET (IO_TYPECAST_UDWORD 0xb00000dc) -#define R_VECT_MASK_SET__usb__BITNR 31 -#define R_VECT_MASK_SET__usb__WIDTH 1 -#define R_VECT_MASK_SET__usb__set 1 -#define R_VECT_MASK_SET__usb__nop 0 -#define R_VECT_MASK_SET__dma9__BITNR 25 -#define R_VECT_MASK_SET__dma9__WIDTH 1 -#define R_VECT_MASK_SET__dma9__set 1 -#define R_VECT_MASK_SET__dma9__nop 0 -#define R_VECT_MASK_SET__dma8__BITNR 24 -#define R_VECT_MASK_SET__dma8__WIDTH 1 -#define R_VECT_MASK_SET__dma8__set 1 -#define R_VECT_MASK_SET__dma8__nop 0 -#define R_VECT_MASK_SET__dma7__BITNR 23 -#define R_VECT_MASK_SET__dma7__WIDTH 1 -#define R_VECT_MASK_SET__dma7__set 1 -#define R_VECT_MASK_SET__dma7__nop 0 -#define R_VECT_MASK_SET__dma6__BITNR 22 -#define R_VECT_MASK_SET__dma6__WIDTH 1 -#define R_VECT_MASK_SET__dma6__set 1 -#define R_VECT_MASK_SET__dma6__nop 0 -#define R_VECT_MASK_SET__dma5__BITNR 21 -#define R_VECT_MASK_SET__dma5__WIDTH 1 -#define R_VECT_MASK_SET__dma5__set 1 -#define R_VECT_MASK_SET__dma5__nop 0 -#define R_VECT_MASK_SET__dma4__BITNR 20 -#define R_VECT_MASK_SET__dma4__WIDTH 1 -#define R_VECT_MASK_SET__dma4__set 1 -#define R_VECT_MASK_SET__dma4__nop 0 -#define R_VECT_MASK_SET__dma3__BITNR 19 -#define R_VECT_MASK_SET__dma3__WIDTH 1 -#define R_VECT_MASK_SET__dma3__set 1 -#define R_VECT_MASK_SET__dma3__nop 0 -#define R_VECT_MASK_SET__dma2__BITNR 18 -#define R_VECT_MASK_SET__dma2__WIDTH 1 -#define R_VECT_MASK_SET__dma2__set 1 -#define R_VECT_MASK_SET__dma2__nop 0 -#define R_VECT_MASK_SET__dma1__BITNR 17 -#define R_VECT_MASK_SET__dma1__WIDTH 1 -#define R_VECT_MASK_SET__dma1__set 1 -#define R_VECT_MASK_SET__dma1__nop 0 -#define R_VECT_MASK_SET__dma0__BITNR 16 -#define R_VECT_MASK_SET__dma0__WIDTH 1 -#define R_VECT_MASK_SET__dma0__set 1 -#define R_VECT_MASK_SET__dma0__nop 0 -#define R_VECT_MASK_SET__ext_dma1__BITNR 13 -#define R_VECT_MASK_SET__ext_dma1__WIDTH 1 -#define R_VECT_MASK_SET__ext_dma1__set 1 -#define R_VECT_MASK_SET__ext_dma1__nop 0 -#define R_VECT_MASK_SET__ext_dma0__BITNR 12 -#define R_VECT_MASK_SET__ext_dma0__WIDTH 1 -#define R_VECT_MASK_SET__ext_dma0__set 1 -#define R_VECT_MASK_SET__ext_dma0__nop 0 -#define R_VECT_MASK_SET__pa__BITNR 11 -#define R_VECT_MASK_SET__pa__WIDTH 1 -#define R_VECT_MASK_SET__pa__set 1 -#define R_VECT_MASK_SET__pa__nop 0 -#define R_VECT_MASK_SET__irq_intnr__BITNR 10 -#define R_VECT_MASK_SET__irq_intnr__WIDTH 1 -#define R_VECT_MASK_SET__irq_intnr__set 1 -#define R_VECT_MASK_SET__irq_intnr__nop 0 -#define R_VECT_MASK_SET__sw__BITNR 9 -#define R_VECT_MASK_SET__sw__WIDTH 1 -#define R_VECT_MASK_SET__sw__set 1 -#define R_VECT_MASK_SET__sw__nop 0 -#define R_VECT_MASK_SET__serial__BITNR 8 -#define R_VECT_MASK_SET__serial__WIDTH 1 -#define R_VECT_MASK_SET__serial__set 1 -#define R_VECT_MASK_SET__serial__nop 0 -#define R_VECT_MASK_SET__snmp__BITNR 7 -#define R_VECT_MASK_SET__snmp__WIDTH 1 -#define R_VECT_MASK_SET__snmp__set 1 -#define R_VECT_MASK_SET__snmp__nop 0 -#define R_VECT_MASK_SET__network__BITNR 6 -#define R_VECT_MASK_SET__network__WIDTH 1 -#define R_VECT_MASK_SET__network__set 1 -#define R_VECT_MASK_SET__network__nop 0 -#define R_VECT_MASK_SET__scsi1__BITNR 5 -#define R_VECT_MASK_SET__scsi1__WIDTH 1 -#define R_VECT_MASK_SET__scsi1__set 1 -#define R_VECT_MASK_SET__scsi1__nop 0 -#define R_VECT_MASK_SET__par1__BITNR 5 -#define R_VECT_MASK_SET__par1__WIDTH 1 -#define R_VECT_MASK_SET__par1__set 1 -#define R_VECT_MASK_SET__par1__nop 0 -#define R_VECT_MASK_SET__scsi0__BITNR 4 -#define R_VECT_MASK_SET__scsi0__WIDTH 1 -#define R_VECT_MASK_SET__scsi0__set 1 -#define R_VECT_MASK_SET__scsi0__nop 0 -#define R_VECT_MASK_SET__par0__BITNR 4 -#define R_VECT_MASK_SET__par0__WIDTH 1 -#define R_VECT_MASK_SET__par0__set 1 -#define R_VECT_MASK_SET__par0__nop 0 -#define R_VECT_MASK_SET__ata__BITNR 4 -#define R_VECT_MASK_SET__ata__WIDTH 1 -#define R_VECT_MASK_SET__ata__set 1 -#define R_VECT_MASK_SET__ata__nop 0 -#define R_VECT_MASK_SET__mio__BITNR 4 -#define R_VECT_MASK_SET__mio__WIDTH 1 -#define R_VECT_MASK_SET__mio__set 1 -#define R_VECT_MASK_SET__mio__nop 0 -#define R_VECT_MASK_SET__timer1__BITNR 3 -#define R_VECT_MASK_SET__timer1__WIDTH 1 -#define R_VECT_MASK_SET__timer1__set 1 -#define R_VECT_MASK_SET__timer1__nop 0 -#define R_VECT_MASK_SET__timer0__BITNR 2 -#define R_VECT_MASK_SET__timer0__WIDTH 1 -#define R_VECT_MASK_SET__timer0__set 1 -#define R_VECT_MASK_SET__timer0__nop 0 -#define R_VECT_MASK_SET__nmi__BITNR 1 -#define R_VECT_MASK_SET__nmi__WIDTH 1 -#define R_VECT_MASK_SET__nmi__set 1 -#define R_VECT_MASK_SET__nmi__nop 0 -#define R_VECT_MASK_SET__some__BITNR 0 -#define R_VECT_MASK_SET__some__WIDTH 1 -#define R_VECT_MASK_SET__some__set 1 -#define R_VECT_MASK_SET__some__nop 0 - -/* -!* DMA registers -!*/ - -#define R_SET_EOP (IO_TYPECAST_UDWORD 0xb000003c) -#define R_SET_EOP__ch9_eop__BITNR 3 -#define R_SET_EOP__ch9_eop__WIDTH 1 -#define R_SET_EOP__ch9_eop__set 1 -#define R_SET_EOP__ch9_eop__nop 0 -#define R_SET_EOP__ch7_eop__BITNR 2 -#define R_SET_EOP__ch7_eop__WIDTH 1 -#define R_SET_EOP__ch7_eop__set 1 -#define R_SET_EOP__ch7_eop__nop 0 -#define R_SET_EOP__ch5_eop__BITNR 1 -#define R_SET_EOP__ch5_eop__WIDTH 1 -#define R_SET_EOP__ch5_eop__set 1 -#define R_SET_EOP__ch5_eop__nop 0 -#define R_SET_EOP__ch3_eop__BITNR 0 -#define R_SET_EOP__ch3_eop__WIDTH 1 -#define R_SET_EOP__ch3_eop__set 1 -#define R_SET_EOP__ch3_eop__nop 0 - -#define R_DMA_CH0_HWSW (IO_TYPECAST_UDWORD 0xb0000100) -#define R_DMA_CH0_HWSW__hw__BITNR 16 -#define R_DMA_CH0_HWSW__hw__WIDTH 16 -#define R_DMA_CH0_HWSW__sw__BITNR 0 -#define R_DMA_CH0_HWSW__sw__WIDTH 16 - -#define R_DMA_CH0_DESCR (IO_TYPECAST_UDWORD 0xb000010c) -#define R_DMA_CH0_DESCR__descr__BITNR 0 -#define R_DMA_CH0_DESCR__descr__WIDTH 32 - -#define R_DMA_CH0_NEXT (IO_TYPECAST_UDWORD 0xb0000104) -#define R_DMA_CH0_NEXT__next__BITNR 0 -#define R_DMA_CH0_NEXT__next__WIDTH 32 - -#define R_DMA_CH0_BUF (IO_TYPECAST_UDWORD 0xb0000108) -#define R_DMA_CH0_BUF__buf__BITNR 0 -#define R_DMA_CH0_BUF__buf__WIDTH 32 - -#define R_DMA_CH0_FIRST (IO_TYPECAST_UDWORD 0xb00001a0) -#define R_DMA_CH0_FIRST__first__BITNR 0 -#define R_DMA_CH0_FIRST__first__WIDTH 32 - -#define R_DMA_CH0_CMD (IO_TYPECAST_BYTE 0xb00001d0) -#define R_DMA_CH0_CMD__cmd__BITNR 0 -#define R_DMA_CH0_CMD__cmd__WIDTH 3 -#define R_DMA_CH0_CMD__cmd__hold 0 -#define R_DMA_CH0_CMD__cmd__start 1 -#define R_DMA_CH0_CMD__cmd__restart 3 -#define R_DMA_CH0_CMD__cmd__continue 3 -#define R_DMA_CH0_CMD__cmd__reset 4 - -#define R_DMA_CH0_CLR_INTR (IO_TYPECAST_BYTE 0xb00001d1) -#define R_DMA_CH0_CLR_INTR__clr_eop__BITNR 1 -#define R_DMA_CH0_CLR_INTR__clr_eop__WIDTH 1 -#define R_DMA_CH0_CLR_INTR__clr_eop__do 1 -#define R_DMA_CH0_CLR_INTR__clr_eop__dont 0 -#define R_DMA_CH0_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH0_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH0_CLR_INTR__clr_descr__do 1 -#define R_DMA_CH0_CLR_INTR__clr_descr__dont 0 - -#define R_DMA_CH0_STATUS (IO_TYPECAST_RO_BYTE 0xb00001d2) -#define R_DMA_CH0_STATUS__avail__BITNR 0 -#define R_DMA_CH0_STATUS__avail__WIDTH 7 - -#define R_DMA_CH1_HWSW (IO_TYPECAST_UDWORD 0xb0000110) -#define R_DMA_CH1_HWSW__hw__BITNR 16 -#define R_DMA_CH1_HWSW__hw__WIDTH 16 -#define R_DMA_CH1_HWSW__sw__BITNR 0 -#define R_DMA_CH1_HWSW__sw__WIDTH 16 - -#define R_DMA_CH1_DESCR (IO_TYPECAST_UDWORD 0xb000011c) -#define R_DMA_CH1_DESCR__descr__BITNR 0 -#define R_DMA_CH1_DESCR__descr__WIDTH 32 - -#define R_DMA_CH1_NEXT (IO_TYPECAST_UDWORD 0xb0000114) -#define R_DMA_CH1_NEXT__next__BITNR 0 -#define R_DMA_CH1_NEXT__next__WIDTH 32 - -#define R_DMA_CH1_BUF (IO_TYPECAST_UDWORD 0xb0000118) -#define R_DMA_CH1_BUF__buf__BITNR 0 -#define R_DMA_CH1_BUF__buf__WIDTH 32 - -#define R_DMA_CH1_FIRST (IO_TYPECAST_UDWORD 0xb00001a4) -#define R_DMA_CH1_FIRST__first__BITNR 0 -#define R_DMA_CH1_FIRST__first__WIDTH 32 - -#define R_DMA_CH1_CMD (IO_TYPECAST_BYTE 0xb00001d4) -#define R_DMA_CH1_CMD__cmd__BITNR 0 -#define R_DMA_CH1_CMD__cmd__WIDTH 3 -#define R_DMA_CH1_CMD__cmd__hold 0 -#define R_DMA_CH1_CMD__cmd__start 1 -#define R_DMA_CH1_CMD__cmd__restart 3 -#define R_DMA_CH1_CMD__cmd__continue 3 -#define R_DMA_CH1_CMD__cmd__reset 4 - -#define R_DMA_CH1_CLR_INTR (IO_TYPECAST_BYTE 0xb00001d5) -#define R_DMA_CH1_CLR_INTR__clr_eop__BITNR 1 -#define R_DMA_CH1_CLR_INTR__clr_eop__WIDTH 1 -#define R_DMA_CH1_CLR_INTR__clr_eop__do 1 -#define R_DMA_CH1_CLR_INTR__clr_eop__dont 0 -#define R_DMA_CH1_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH1_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH1_CLR_INTR__clr_descr__do 1 -#define R_DMA_CH1_CLR_INTR__clr_descr__dont 0 - -#define R_DMA_CH1_STATUS (IO_TYPECAST_RO_BYTE 0xb00001d6) -#define R_DMA_CH1_STATUS__avail__BITNR 0 -#define R_DMA_CH1_STATUS__avail__WIDTH 7 - -#define R_DMA_CH2_HWSW (IO_TYPECAST_UDWORD 0xb0000120) -#define R_DMA_CH2_HWSW__hw__BITNR 16 -#define R_DMA_CH2_HWSW__hw__WIDTH 16 -#define R_DMA_CH2_HWSW__sw__BITNR 0 -#define R_DMA_CH2_HWSW__sw__WIDTH 16 - -#define R_DMA_CH2_DESCR (IO_TYPECAST_UDWORD 0xb000012c) -#define R_DMA_CH2_DESCR__descr__BITNR 0 -#define R_DMA_CH2_DESCR__descr__WIDTH 32 - -#define R_DMA_CH2_NEXT (IO_TYPECAST_UDWORD 0xb0000124) -#define R_DMA_CH2_NEXT__next__BITNR 0 -#define R_DMA_CH2_NEXT__next__WIDTH 32 - -#define R_DMA_CH2_BUF (IO_TYPECAST_UDWORD 0xb0000128) -#define R_DMA_CH2_BUF__buf__BITNR 0 -#define R_DMA_CH2_BUF__buf__WIDTH 32 - -#define R_DMA_CH2_FIRST (IO_TYPECAST_UDWORD 0xb00001a8) -#define R_DMA_CH2_FIRST__first__BITNR 0 -#define R_DMA_CH2_FIRST__first__WIDTH 32 - -#define R_DMA_CH2_CMD (IO_TYPECAST_BYTE 0xb00001d8) -#define R_DMA_CH2_CMD__cmd__BITNR 0 -#define R_DMA_CH2_CMD__cmd__WIDTH 3 -#define R_DMA_CH2_CMD__cmd__hold 0 -#define R_DMA_CH2_CMD__cmd__start 1 -#define R_DMA_CH2_CMD__cmd__restart 3 -#define R_DMA_CH2_CMD__cmd__continue 3 -#define R_DMA_CH2_CMD__cmd__reset 4 - -#define R_DMA_CH2_CLR_INTR (IO_TYPECAST_BYTE 0xb00001d9) -#define R_DMA_CH2_CLR_INTR__clr_eop__BITNR 1 -#define R_DMA_CH2_CLR_INTR__clr_eop__WIDTH 1 -#define R_DMA_CH2_CLR_INTR__clr_eop__do 1 -#define R_DMA_CH2_CLR_INTR__clr_eop__dont 0 -#define R_DMA_CH2_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH2_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH2_CLR_INTR__clr_descr__do 1 -#define R_DMA_CH2_CLR_INTR__clr_descr__dont 0 - -#define R_DMA_CH2_STATUS (IO_TYPECAST_RO_BYTE 0xb00001da) -#define R_DMA_CH2_STATUS__avail__BITNR 0 -#define R_DMA_CH2_STATUS__avail__WIDTH 7 - -#define R_DMA_CH3_HWSW (IO_TYPECAST_UDWORD 0xb0000130) -#define R_DMA_CH3_HWSW__hw__BITNR 16 -#define R_DMA_CH3_HWSW__hw__WIDTH 16 -#define R_DMA_CH3_HWSW__sw__BITNR 0 -#define R_DMA_CH3_HWSW__sw__WIDTH 16 - -#define R_DMA_CH3_DESCR (IO_TYPECAST_UDWORD 0xb000013c) -#define R_DMA_CH3_DESCR__descr__BITNR 0 -#define R_DMA_CH3_DESCR__descr__WIDTH 32 - -#define R_DMA_CH3_NEXT (IO_TYPECAST_UDWORD 0xb0000134) -#define R_DMA_CH3_NEXT__next__BITNR 0 -#define R_DMA_CH3_NEXT__next__WIDTH 32 - -#define R_DMA_CH3_BUF (IO_TYPECAST_UDWORD 0xb0000138) -#define R_DMA_CH3_BUF__buf__BITNR 0 -#define R_DMA_CH3_BUF__buf__WIDTH 32 - -#define R_DMA_CH3_FIRST (IO_TYPECAST_UDWORD 0xb00001ac) -#define R_DMA_CH3_FIRST__first__BITNR 0 -#define R_DMA_CH3_FIRST__first__WIDTH 32 - -#define R_DMA_CH3_CMD (IO_TYPECAST_BYTE 0xb00001dc) -#define R_DMA_CH3_CMD__cmd__BITNR 0 -#define R_DMA_CH3_CMD__cmd__WIDTH 3 -#define R_DMA_CH3_CMD__cmd__hold 0 -#define R_DMA_CH3_CMD__cmd__start 1 -#define R_DMA_CH3_CMD__cmd__restart 3 -#define R_DMA_CH3_CMD__cmd__continue 3 -#define R_DMA_CH3_CMD__cmd__reset 4 - -#define R_DMA_CH3_CLR_INTR (IO_TYPECAST_BYTE 0xb00001dd) -#define R_DMA_CH3_CLR_INTR__clr_eop__BITNR 1 -#define R_DMA_CH3_CLR_INTR__clr_eop__WIDTH 1 -#define R_DMA_CH3_CLR_INTR__clr_eop__do 1 -#define R_DMA_CH3_CLR_INTR__clr_eop__dont 0 -#define R_DMA_CH3_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH3_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH3_CLR_INTR__clr_descr__do 1 -#define R_DMA_CH3_CLR_INTR__clr_descr__dont 0 - -#define R_DMA_CH3_STATUS (IO_TYPECAST_RO_BYTE 0xb00001de) -#define R_DMA_CH3_STATUS__avail__BITNR 0 -#define R_DMA_CH3_STATUS__avail__WIDTH 7 - -#define R_DMA_CH4_HWSW (IO_TYPECAST_UDWORD 0xb0000140) -#define R_DMA_CH4_HWSW__hw__BITNR 16 -#define R_DMA_CH4_HWSW__hw__WIDTH 16 -#define R_DMA_CH4_HWSW__sw__BITNR 0 -#define R_DMA_CH4_HWSW__sw__WIDTH 16 - -#define R_DMA_CH4_DESCR (IO_TYPECAST_UDWORD 0xb000014c) -#define R_DMA_CH4_DESCR__descr__BITNR 0 -#define R_DMA_CH4_DESCR__descr__WIDTH 32 - -#define R_DMA_CH4_NEXT (IO_TYPECAST_UDWORD 0xb0000144) -#define R_DMA_CH4_NEXT__next__BITNR 0 -#define R_DMA_CH4_NEXT__next__WIDTH 32 - -#define R_DMA_CH4_BUF (IO_TYPECAST_UDWORD 0xb0000148) -#define R_DMA_CH4_BUF__buf__BITNR 0 -#define R_DMA_CH4_BUF__buf__WIDTH 32 - -#define R_DMA_CH4_FIRST (IO_TYPECAST_UDWORD 0xb00001b0) -#define R_DMA_CH4_FIRST__first__BITNR 0 -#define R_DMA_CH4_FIRST__first__WIDTH 32 - -#define R_DMA_CH4_CMD (IO_TYPECAST_BYTE 0xb00001e0) -#define R_DMA_CH4_CMD__cmd__BITNR 0 -#define R_DMA_CH4_CMD__cmd__WIDTH 3 -#define R_DMA_CH4_CMD__cmd__hold 0 -#define R_DMA_CH4_CMD__cmd__start 1 -#define R_DMA_CH4_CMD__cmd__restart 3 -#define R_DMA_CH4_CMD__cmd__continue 3 -#define R_DMA_CH4_CMD__cmd__reset 4 - -#define R_DMA_CH4_CLR_INTR (IO_TYPECAST_BYTE 0xb00001e1) -#define R_DMA_CH4_CLR_INTR__clr_eop__BITNR 1 -#define R_DMA_CH4_CLR_INTR__clr_eop__WIDTH 1 -#define R_DMA_CH4_CLR_INTR__clr_eop__do 1 -#define R_DMA_CH4_CLR_INTR__clr_eop__dont 0 -#define R_DMA_CH4_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH4_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH4_CLR_INTR__clr_descr__do 1 -#define R_DMA_CH4_CLR_INTR__clr_descr__dont 0 - -#define R_DMA_CH4_STATUS (IO_TYPECAST_RO_BYTE 0xb00001e2) -#define R_DMA_CH4_STATUS__avail__BITNR 0 -#define R_DMA_CH4_STATUS__avail__WIDTH 7 - -#define R_DMA_CH5_HWSW (IO_TYPECAST_UDWORD 0xb0000150) -#define R_DMA_CH5_HWSW__hw__BITNR 16 -#define R_DMA_CH5_HWSW__hw__WIDTH 16 -#define R_DMA_CH5_HWSW__sw__BITNR 0 -#define R_DMA_CH5_HWSW__sw__WIDTH 16 - -#define R_DMA_CH5_DESCR (IO_TYPECAST_UDWORD 0xb000015c) -#define R_DMA_CH5_DESCR__descr__BITNR 0 -#define R_DMA_CH5_DESCR__descr__WIDTH 32 - -#define R_DMA_CH5_NEXT (IO_TYPECAST_UDWORD 0xb0000154) -#define R_DMA_CH5_NEXT__next__BITNR 0 -#define R_DMA_CH5_NEXT__next__WIDTH 32 - -#define R_DMA_CH5_BUF (IO_TYPECAST_UDWORD 0xb0000158) -#define R_DMA_CH5_BUF__buf__BITNR 0 -#define R_DMA_CH5_BUF__buf__WIDTH 32 - -#define R_DMA_CH5_FIRST (IO_TYPECAST_UDWORD 0xb00001b4) -#define R_DMA_CH5_FIRST__first__BITNR 0 -#define R_DMA_CH5_FIRST__first__WIDTH 32 - -#define R_DMA_CH5_CMD (IO_TYPECAST_BYTE 0xb00001e4) -#define R_DMA_CH5_CMD__cmd__BITNR 0 -#define R_DMA_CH5_CMD__cmd__WIDTH 3 -#define R_DMA_CH5_CMD__cmd__hold 0 -#define R_DMA_CH5_CMD__cmd__start 1 -#define R_DMA_CH5_CMD__cmd__restart 3 -#define R_DMA_CH5_CMD__cmd__continue 3 -#define R_DMA_CH5_CMD__cmd__reset 4 - -#define R_DMA_CH5_CLR_INTR (IO_TYPECAST_BYTE 0xb00001e5) -#define R_DMA_CH5_CLR_INTR__clr_eop__BITNR 1 -#define R_DMA_CH5_CLR_INTR__clr_eop__WIDTH 1 -#define R_DMA_CH5_CLR_INTR__clr_eop__do 1 -#define R_DMA_CH5_CLR_INTR__clr_eop__dont 0 -#define R_DMA_CH5_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH5_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH5_CLR_INTR__clr_descr__do 1 -#define R_DMA_CH5_CLR_INTR__clr_descr__dont 0 - -#define R_DMA_CH5_STATUS (IO_TYPECAST_RO_BYTE 0xb00001e6) -#define R_DMA_CH5_STATUS__avail__BITNR 0 -#define R_DMA_CH5_STATUS__avail__WIDTH 7 - -#define R_DMA_CH6_HWSW (IO_TYPECAST_UDWORD 0xb0000160) -#define R_DMA_CH6_HWSW__hw__BITNR 16 -#define R_DMA_CH6_HWSW__hw__WIDTH 16 -#define R_DMA_CH6_HWSW__sw__BITNR 0 -#define R_DMA_CH6_HWSW__sw__WIDTH 16 - -#define R_DMA_CH6_DESCR (IO_TYPECAST_UDWORD 0xb000016c) -#define R_DMA_CH6_DESCR__descr__BITNR 0 -#define R_DMA_CH6_DESCR__descr__WIDTH 32 - -#define R_DMA_CH6_NEXT (IO_TYPECAST_UDWORD 0xb0000164) -#define R_DMA_CH6_NEXT__next__BITNR 0 -#define R_DMA_CH6_NEXT__next__WIDTH 32 - -#define R_DMA_CH6_BUF (IO_TYPECAST_UDWORD 0xb0000168) -#define R_DMA_CH6_BUF__buf__BITNR 0 -#define R_DMA_CH6_BUF__buf__WIDTH 32 - -#define R_DMA_CH6_FIRST (IO_TYPECAST_UDWORD 0xb00001b8) -#define R_DMA_CH6_FIRST__first__BITNR 0 -#define R_DMA_CH6_FIRST__first__WIDTH 32 - -#define R_DMA_CH6_CMD (IO_TYPECAST_BYTE 0xb00001e8) -#define R_DMA_CH6_CMD__cmd__BITNR 0 -#define R_DMA_CH6_CMD__cmd__WIDTH 3 -#define R_DMA_CH6_CMD__cmd__hold 0 -#define R_DMA_CH6_CMD__cmd__start 1 -#define R_DMA_CH6_CMD__cmd__restart 3 -#define R_DMA_CH6_CMD__cmd__continue 3 -#define R_DMA_CH6_CMD__cmd__reset 4 - -#define R_DMA_CH6_CLR_INTR (IO_TYPECAST_BYTE 0xb00001e9) -#define R_DMA_CH6_CLR_INTR__clr_eop__BITNR 1 -#define R_DMA_CH6_CLR_INTR__clr_eop__WIDTH 1 -#define R_DMA_CH6_CLR_INTR__clr_eop__do 1 -#define R_DMA_CH6_CLR_INTR__clr_eop__dont 0 -#define R_DMA_CH6_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH6_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH6_CLR_INTR__clr_descr__do 1 -#define R_DMA_CH6_CLR_INTR__clr_descr__dont 0 - -#define R_DMA_CH6_STATUS (IO_TYPECAST_RO_BYTE 0xb00001ea) -#define R_DMA_CH6_STATUS__avail__BITNR 0 -#define R_DMA_CH6_STATUS__avail__WIDTH 7 - -#define R_DMA_CH7_HWSW (IO_TYPECAST_UDWORD 0xb0000170) -#define R_DMA_CH7_HWSW__hw__BITNR 16 -#define R_DMA_CH7_HWSW__hw__WIDTH 16 -#define R_DMA_CH7_HWSW__sw__BITNR 0 -#define R_DMA_CH7_HWSW__sw__WIDTH 16 - -#define R_DMA_CH7_DESCR (IO_TYPECAST_UDWORD 0xb000017c) -#define R_DMA_CH7_DESCR__descr__BITNR 0 -#define R_DMA_CH7_DESCR__descr__WIDTH 32 - -#define R_DMA_CH7_NEXT (IO_TYPECAST_UDWORD 0xb0000174) -#define R_DMA_CH7_NEXT__next__BITNR 0 -#define R_DMA_CH7_NEXT__next__WIDTH 32 - -#define R_DMA_CH7_BUF (IO_TYPECAST_UDWORD 0xb0000178) -#define R_DMA_CH7_BUF__buf__BITNR 0 -#define R_DMA_CH7_BUF__buf__WIDTH 32 - -#define R_DMA_CH7_FIRST (IO_TYPECAST_UDWORD 0xb00001bc) -#define R_DMA_CH7_FIRST__first__BITNR 0 -#define R_DMA_CH7_FIRST__first__WIDTH 32 - -#define R_DMA_CH7_CMD (IO_TYPECAST_BYTE 0xb00001ec) -#define R_DMA_CH7_CMD__cmd__BITNR 0 -#define R_DMA_CH7_CMD__cmd__WIDTH 3 -#define R_DMA_CH7_CMD__cmd__hold 0 -#define R_DMA_CH7_CMD__cmd__start 1 -#define R_DMA_CH7_CMD__cmd__restart 3 -#define R_DMA_CH7_CMD__cmd__continue 3 -#define R_DMA_CH7_CMD__cmd__reset 4 - -#define R_DMA_CH7_CLR_INTR (IO_TYPECAST_BYTE 0xb00001ed) -#define R_DMA_CH7_CLR_INTR__clr_eop__BITNR 1 -#define R_DMA_CH7_CLR_INTR__clr_eop__WIDTH 1 -#define R_DMA_CH7_CLR_INTR__clr_eop__do 1 -#define R_DMA_CH7_CLR_INTR__clr_eop__dont 0 -#define R_DMA_CH7_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH7_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH7_CLR_INTR__clr_descr__do 1 -#define R_DMA_CH7_CLR_INTR__clr_descr__dont 0 - -#define R_DMA_CH7_STATUS (IO_TYPECAST_RO_BYTE 0xb00001ee) -#define R_DMA_CH7_STATUS__avail__BITNR 0 -#define R_DMA_CH7_STATUS__avail__WIDTH 7 - -#define R_DMA_CH8_HWSW (IO_TYPECAST_UDWORD 0xb0000180) -#define R_DMA_CH8_HWSW__hw__BITNR 16 -#define R_DMA_CH8_HWSW__hw__WIDTH 16 -#define R_DMA_CH8_HWSW__sw__BITNR 0 -#define R_DMA_CH8_HWSW__sw__WIDTH 16 - -#define R_DMA_CH8_DESCR (IO_TYPECAST_UDWORD 0xb000018c) -#define R_DMA_CH8_DESCR__descr__BITNR 0 -#define R_DMA_CH8_DESCR__descr__WIDTH 32 - -#define R_DMA_CH8_NEXT (IO_TYPECAST_UDWORD 0xb0000184) -#define R_DMA_CH8_NEXT__next__BITNR 0 -#define R_DMA_CH8_NEXT__next__WIDTH 32 - -#define R_DMA_CH8_BUF (IO_TYPECAST_UDWORD 0xb0000188) -#define R_DMA_CH8_BUF__buf__BITNR 0 -#define R_DMA_CH8_BUF__buf__WIDTH 32 - -#define R_DMA_CH8_FIRST (IO_TYPECAST_UDWORD 0xb00001c0) -#define R_DMA_CH8_FIRST__first__BITNR 0 -#define R_DMA_CH8_FIRST__first__WIDTH 32 - -#define R_DMA_CH8_CMD (IO_TYPECAST_BYTE 0xb00001f0) -#define R_DMA_CH8_CMD__cmd__BITNR 0 -#define R_DMA_CH8_CMD__cmd__WIDTH 3 -#define R_DMA_CH8_CMD__cmd__hold 0 -#define R_DMA_CH8_CMD__cmd__start 1 -#define R_DMA_CH8_CMD__cmd__restart 3 -#define R_DMA_CH8_CMD__cmd__continue 3 -#define R_DMA_CH8_CMD__cmd__reset 4 - -#define R_DMA_CH8_CLR_INTR (IO_TYPECAST_BYTE 0xb00001f1) -#define R_DMA_CH8_CLR_INTR__clr_eop__BITNR 1 -#define R_DMA_CH8_CLR_INTR__clr_eop__WIDTH 1 -#define R_DMA_CH8_CLR_INTR__clr_eop__do 1 -#define R_DMA_CH8_CLR_INTR__clr_eop__dont 0 -#define R_DMA_CH8_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH8_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH8_CLR_INTR__clr_descr__do 1 -#define R_DMA_CH8_CLR_INTR__clr_descr__dont 0 - -#define R_DMA_CH8_STATUS (IO_TYPECAST_RO_BYTE 0xb00001f2) -#define R_DMA_CH8_STATUS__avail__BITNR 0 -#define R_DMA_CH8_STATUS__avail__WIDTH 7 - -#define R_DMA_CH8_SUB (IO_TYPECAST_UDWORD 0xb000018c) -#define R_DMA_CH8_SUB__sub__BITNR 0 -#define R_DMA_CH8_SUB__sub__WIDTH 32 - -#define R_DMA_CH8_NEP (IO_TYPECAST_UDWORD 0xb00001c0) -#define R_DMA_CH8_NEP__nep__BITNR 0 -#define R_DMA_CH8_NEP__nep__WIDTH 32 - -#define R_DMA_CH8_SUB0_EP (IO_TYPECAST_UDWORD 0xb00001c8) -#define R_DMA_CH8_SUB0_EP__ep__BITNR 0 -#define R_DMA_CH8_SUB0_EP__ep__WIDTH 32 - -#define R_DMA_CH8_SUB0_CMD (IO_TYPECAST_BYTE 0xb00001d3) -#define R_DMA_CH8_SUB0_CMD__cmd__BITNR 0 -#define R_DMA_CH8_SUB0_CMD__cmd__WIDTH 1 -#define R_DMA_CH8_SUB0_CMD__cmd__stop 0 -#define R_DMA_CH8_SUB0_CMD__cmd__start 1 - -#define R_DMA_CH8_SUB0_CLR_INTR (IO_TYPECAST_BYTE 0xb00001e3) -#define R_DMA_CH8_SUB0_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH8_SUB0_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH8_SUB0_CLR_INTR__clr_descr__dont 0 -#define R_DMA_CH8_SUB0_CLR_INTR__clr_descr__do 1 - -#define R_DMA_CH8_SUB1_EP (IO_TYPECAST_UDWORD 0xb00001cc) -#define R_DMA_CH8_SUB1_EP__ep__BITNR 0 -#define R_DMA_CH8_SUB1_EP__ep__WIDTH 32 - -#define R_DMA_CH8_SUB1_CMD (IO_TYPECAST_BYTE 0xb00001d7) -#define R_DMA_CH8_SUB1_CMD__cmd__BITNR 0 -#define R_DMA_CH8_SUB1_CMD__cmd__WIDTH 1 -#define R_DMA_CH8_SUB1_CMD__cmd__stop 0 -#define R_DMA_CH8_SUB1_CMD__cmd__start 1 - -#define R_DMA_CH8_SUB1_CLR_INTR (IO_TYPECAST_BYTE 0xb00001e7) -#define R_DMA_CH8_SUB1_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH8_SUB1_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH8_SUB1_CLR_INTR__clr_descr__dont 0 -#define R_DMA_CH8_SUB1_CLR_INTR__clr_descr__do 1 - -#define R_DMA_CH8_SUB2_EP (IO_TYPECAST_UDWORD 0xb00001f8) -#define R_DMA_CH8_SUB2_EP__ep__BITNR 0 -#define R_DMA_CH8_SUB2_EP__ep__WIDTH 32 - -#define R_DMA_CH8_SUB2_CMD (IO_TYPECAST_BYTE 0xb00001db) -#define R_DMA_CH8_SUB2_CMD__cmd__BITNR 0 -#define R_DMA_CH8_SUB2_CMD__cmd__WIDTH 1 -#define R_DMA_CH8_SUB2_CMD__cmd__stop 0 -#define R_DMA_CH8_SUB2_CMD__cmd__start 1 - -#define R_DMA_CH8_SUB2_CLR_INTR (IO_TYPECAST_BYTE 0xb00001eb) -#define R_DMA_CH8_SUB2_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH8_SUB2_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH8_SUB2_CLR_INTR__clr_descr__dont 0 -#define R_DMA_CH8_SUB2_CLR_INTR__clr_descr__do 1 - -#define R_DMA_CH8_SUB3_EP (IO_TYPECAST_UDWORD 0xb00001fc) -#define R_DMA_CH8_SUB3_EP__ep__BITNR 0 -#define R_DMA_CH8_SUB3_EP__ep__WIDTH 32 - -#define R_DMA_CH8_SUB3_CMD (IO_TYPECAST_BYTE 0xb00001df) -#define R_DMA_CH8_SUB3_CMD__cmd__BITNR 0 -#define R_DMA_CH8_SUB3_CMD__cmd__WIDTH 1 -#define R_DMA_CH8_SUB3_CMD__cmd__stop 0 -#define R_DMA_CH8_SUB3_CMD__cmd__start 1 - -#define R_DMA_CH8_SUB3_CLR_INTR (IO_TYPECAST_BYTE 0xb00001ef) -#define R_DMA_CH8_SUB3_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH8_SUB3_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH8_SUB3_CLR_INTR__clr_descr__dont 0 -#define R_DMA_CH8_SUB3_CLR_INTR__clr_descr__do 1 - -#define R_DMA_CH9_HWSW (IO_TYPECAST_UDWORD 0xb0000190) -#define R_DMA_CH9_HWSW__hw__BITNR 16 -#define R_DMA_CH9_HWSW__hw__WIDTH 16 -#define R_DMA_CH9_HWSW__sw__BITNR 0 -#define R_DMA_CH9_HWSW__sw__WIDTH 16 - -#define R_DMA_CH9_DESCR (IO_TYPECAST_UDWORD 0xb000019c) -#define R_DMA_CH9_DESCR__descr__BITNR 0 -#define R_DMA_CH9_DESCR__descr__WIDTH 32 - -#define R_DMA_CH9_NEXT (IO_TYPECAST_UDWORD 0xb0000194) -#define R_DMA_CH9_NEXT__next__BITNR 0 -#define R_DMA_CH9_NEXT__next__WIDTH 32 - -#define R_DMA_CH9_BUF (IO_TYPECAST_UDWORD 0xb0000198) -#define R_DMA_CH9_BUF__buf__BITNR 0 -#define R_DMA_CH9_BUF__buf__WIDTH 32 - -#define R_DMA_CH9_FIRST (IO_TYPECAST_UDWORD 0xb00001c4) -#define R_DMA_CH9_FIRST__first__BITNR 0 -#define R_DMA_CH9_FIRST__first__WIDTH 32 - -#define R_DMA_CH9_CMD (IO_TYPECAST_BYTE 0xb00001f4) -#define R_DMA_CH9_CMD__cmd__BITNR 0 -#define R_DMA_CH9_CMD__cmd__WIDTH 3 -#define R_DMA_CH9_CMD__cmd__hold 0 -#define R_DMA_CH9_CMD__cmd__start 1 -#define R_DMA_CH9_CMD__cmd__restart 3 -#define R_DMA_CH9_CMD__cmd__continue 3 -#define R_DMA_CH9_CMD__cmd__reset 4 - -#define R_DMA_CH9_CLR_INTR (IO_TYPECAST_BYTE 0xb00001f5) -#define R_DMA_CH9_CLR_INTR__clr_eop__BITNR 1 -#define R_DMA_CH9_CLR_INTR__clr_eop__WIDTH 1 -#define R_DMA_CH9_CLR_INTR__clr_eop__do 1 -#define R_DMA_CH9_CLR_INTR__clr_eop__dont 0 -#define R_DMA_CH9_CLR_INTR__clr_descr__BITNR 0 -#define R_DMA_CH9_CLR_INTR__clr_descr__WIDTH 1 -#define R_DMA_CH9_CLR_INTR__clr_descr__do 1 -#define R_DMA_CH9_CLR_INTR__clr_descr__dont 0 - -#define R_DMA_CH9_STATUS (IO_TYPECAST_RO_BYTE 0xb00001f6) -#define R_DMA_CH9_STATUS__avail__BITNR 0 -#define R_DMA_CH9_STATUS__avail__WIDTH 7 - -/* -!* Test mode registers -!*/ - -#define R_TEST_MODE (IO_TYPECAST_UDWORD 0xb00000fc) -#define R_TEST_MODE__single_step__BITNR 19 -#define R_TEST_MODE__single_step__WIDTH 1 -#define R_TEST_MODE__single_step__on 1 -#define R_TEST_MODE__single_step__off 0 -#define R_TEST_MODE__step_wr__BITNR 18 -#define R_TEST_MODE__step_wr__WIDTH 1 -#define R_TEST_MODE__step_wr__on 1 -#define R_TEST_MODE__step_wr__off 0 -#define R_TEST_MODE__step_rd__BITNR 17 -#define R_TEST_MODE__step_rd__WIDTH 1 -#define R_TEST_MODE__step_rd__on 1 -#define R_TEST_MODE__step_rd__off 0 -#define R_TEST_MODE__step_fetch__BITNR 16 -#define R_TEST_MODE__step_fetch__WIDTH 1 -#define R_TEST_MODE__step_fetch__on 1 -#define R_TEST_MODE__step_fetch__off 0 -#define R_TEST_MODE__mmu_test__BITNR 12 -#define R_TEST_MODE__mmu_test__WIDTH 1 -#define R_TEST_MODE__mmu_test__on 1 -#define R_TEST_MODE__mmu_test__off 0 -#define R_TEST_MODE__usb_test__BITNR 11 -#define R_TEST_MODE__usb_test__WIDTH 1 -#define R_TEST_MODE__usb_test__on 1 -#define R_TEST_MODE__usb_test__off 0 -#define R_TEST_MODE__scsi_timer_test__BITNR 10 -#define R_TEST_MODE__scsi_timer_test__WIDTH 1 -#define R_TEST_MODE__scsi_timer_test__on 1 -#define R_TEST_MODE__scsi_timer_test__off 0 -#define R_TEST_MODE__backoff__BITNR 9 -#define R_TEST_MODE__backoff__WIDTH 1 -#define R_TEST_MODE__backoff__on 1 -#define R_TEST_MODE__backoff__off 0 -#define R_TEST_MODE__snmp_test__BITNR 8 -#define R_TEST_MODE__snmp_test__WIDTH 1 -#define R_TEST_MODE__snmp_test__on 1 -#define R_TEST_MODE__snmp_test__off 0 -#define R_TEST_MODE__snmp_inc__BITNR 7 -#define R_TEST_MODE__snmp_inc__WIDTH 1 -#define R_TEST_MODE__snmp_inc__do 1 -#define R_TEST_MODE__snmp_inc__dont 0 -#define R_TEST_MODE__ser_loop__BITNR 6 -#define R_TEST_MODE__ser_loop__WIDTH 1 -#define R_TEST_MODE__ser_loop__on 1 -#define R_TEST_MODE__ser_loop__off 0 -#define R_TEST_MODE__baudrate__BITNR 5 -#define R_TEST_MODE__baudrate__WIDTH 1 -#define R_TEST_MODE__baudrate__on 1 -#define R_TEST_MODE__baudrate__off 0 -#define R_TEST_MODE__timer__BITNR 3 -#define R_TEST_MODE__timer__WIDTH 2 -#define R_TEST_MODE__timer__off 0 -#define R_TEST_MODE__timer__even 1 -#define R_TEST_MODE__timer__odd 2 -#define R_TEST_MODE__timer__all 3 -#define R_TEST_MODE__cache_test__BITNR 2 -#define R_TEST_MODE__cache_test__WIDTH 1 -#define R_TEST_MODE__cache_test__normal 0 -#define R_TEST_MODE__cache_test__test 1 -#define R_TEST_MODE__tag_test__BITNR 1 -#define R_TEST_MODE__tag_test__WIDTH 1 -#define R_TEST_MODE__tag_test__normal 0 -#define R_TEST_MODE__tag_test__test 1 -#define R_TEST_MODE__cache_enable__BITNR 0 -#define R_TEST_MODE__cache_enable__WIDTH 1 -#define R_TEST_MODE__cache_enable__enable 1 -#define R_TEST_MODE__cache_enable__disable 0 - -#define R_SINGLE_STEP (IO_TYPECAST_BYTE 0xb00000fe) -#define R_SINGLE_STEP__single_step__BITNR 3 -#define R_SINGLE_STEP__single_step__WIDTH 1 -#define R_SINGLE_STEP__single_step__on 1 -#define R_SINGLE_STEP__single_step__off 0 -#define R_SINGLE_STEP__step_wr__BITNR 2 -#define R_SINGLE_STEP__step_wr__WIDTH 1 -#define R_SINGLE_STEP__step_wr__on 1 -#define R_SINGLE_STEP__step_wr__off 0 -#define R_SINGLE_STEP__step_rd__BITNR 1 -#define R_SINGLE_STEP__step_rd__WIDTH 1 -#define R_SINGLE_STEP__step_rd__on 1 -#define R_SINGLE_STEP__step_rd__off 0 -#define R_SINGLE_STEP__step_fetch__BITNR 0 -#define R_SINGLE_STEP__step_fetch__WIDTH 1 -#define R_SINGLE_STEP__step_fetch__on 1 -#define R_SINGLE_STEP__step_fetch__off 0 - -/* -!* USB interface control registers -!*/ - -#define R_USB_REVISION (IO_TYPECAST_RO_BYTE 0xb0000200) -#define R_USB_REVISION__major__BITNR 4 -#define R_USB_REVISION__major__WIDTH 4 -#define R_USB_REVISION__minor__BITNR 0 -#define R_USB_REVISION__minor__WIDTH 4 - -#define R_USB_COMMAND (IO_TYPECAST_BYTE 0xb0000201) -#define R_USB_COMMAND__port_sel__BITNR 6 -#define R_USB_COMMAND__port_sel__WIDTH 2 -#define R_USB_COMMAND__port_sel__nop 0 -#define R_USB_COMMAND__port_sel__port1 1 -#define R_USB_COMMAND__port_sel__port2 2 -#define R_USB_COMMAND__port_sel__both 3 -#define R_USB_COMMAND__port_cmd__BITNR 4 -#define R_USB_COMMAND__port_cmd__WIDTH 2 -#define R_USB_COMMAND__port_cmd__reset 0 -#define R_USB_COMMAND__port_cmd__disable 1 -#define R_USB_COMMAND__port_cmd__suspend 2 -#define R_USB_COMMAND__port_cmd__resume 3 -#define R_USB_COMMAND__busy__BITNR 3 -#define R_USB_COMMAND__busy__WIDTH 1 -#define R_USB_COMMAND__busy__no 0 -#define R_USB_COMMAND__busy__yes 1 -#define R_USB_COMMAND__ctrl_cmd__BITNR 0 -#define R_USB_COMMAND__ctrl_cmd__WIDTH 3 -#define R_USB_COMMAND__ctrl_cmd__nop 0 -#define R_USB_COMMAND__ctrl_cmd__reset 1 -#define R_USB_COMMAND__ctrl_cmd__deconfig 2 -#define R_USB_COMMAND__ctrl_cmd__host_config 3 -#define R_USB_COMMAND__ctrl_cmd__dev_config 4 -#define R_USB_COMMAND__ctrl_cmd__host_nop 5 -#define R_USB_COMMAND__ctrl_cmd__host_run 6 -#define R_USB_COMMAND__ctrl_cmd__host_stop 7 - -#define R_USB_COMMAND_DEV (IO_TYPECAST_BYTE 0xb0000201) -#define R_USB_COMMAND_DEV__port_sel__BITNR 6 -#define R_USB_COMMAND_DEV__port_sel__WIDTH 2 -#define R_USB_COMMAND_DEV__port_sel__nop 0 -#define R_USB_COMMAND_DEV__port_sel__dummy1 1 -#define R_USB_COMMAND_DEV__port_sel__dummy2 2 -#define R_USB_COMMAND_DEV__port_sel__any 3 -#define R_USB_COMMAND_DEV__port_cmd__BITNR 4 -#define R_USB_COMMAND_DEV__port_cmd__WIDTH 2 -#define R_USB_COMMAND_DEV__port_cmd__active 0 -#define R_USB_COMMAND_DEV__port_cmd__passive 1 -#define R_USB_COMMAND_DEV__port_cmd__nop 2 -#define R_USB_COMMAND_DEV__port_cmd__wakeup 3 -#define R_USB_COMMAND_DEV__busy__BITNR 3 -#define R_USB_COMMAND_DEV__busy__WIDTH 1 -#define R_USB_COMMAND_DEV__busy__no 0 -#define R_USB_COMMAND_DEV__busy__yes 1 -#define R_USB_COMMAND_DEV__ctrl_cmd__BITNR 0 -#define R_USB_COMMAND_DEV__ctrl_cmd__WIDTH 3 -#define R_USB_COMMAND_DEV__ctrl_cmd__nop 0 -#define R_USB_COMMAND_DEV__ctrl_cmd__reset 1 -#define R_USB_COMMAND_DEV__ctrl_cmd__deconfig 2 -#define R_USB_COMMAND_DEV__ctrl_cmd__host_config 3 -#define R_USB_COMMAND_DEV__ctrl_cmd__dev_config 4 -#define R_USB_COMMAND_DEV__ctrl_cmd__dev_active 5 -#define R_USB_COMMAND_DEV__ctrl_cmd__dev_passive 6 -#define R_USB_COMMAND_DEV__ctrl_cmd__dev_nop 7 - -#define R_USB_STATUS (IO_TYPECAST_RO_BYTE 0xb0000202) -#define R_USB_STATUS__ourun__BITNR 5 -#define R_USB_STATUS__ourun__WIDTH 1 -#define R_USB_STATUS__ourun__no 0 -#define R_USB_STATUS__ourun__yes 1 -#define R_USB_STATUS__perror__BITNR 4 -#define R_USB_STATUS__perror__WIDTH 1 -#define R_USB_STATUS__perror__no 0 -#define R_USB_STATUS__perror__yes 1 -#define R_USB_STATUS__device_mode__BITNR 3 -#define R_USB_STATUS__device_mode__WIDTH 1 -#define R_USB_STATUS__device_mode__no 0 -#define R_USB_STATUS__device_mode__yes 1 -#define R_USB_STATUS__host_mode__BITNR 2 -#define R_USB_STATUS__host_mode__WIDTH 1 -#define R_USB_STATUS__host_mode__no 0 -#define R_USB_STATUS__host_mode__yes 1 -#define R_USB_STATUS__started__BITNR 1 -#define R_USB_STATUS__started__WIDTH 1 -#define R_USB_STATUS__started__no 0 -#define R_USB_STATUS__started__yes 1 -#define R_USB_STATUS__running__BITNR 0 -#define R_USB_STATUS__running__WIDTH 1 -#define R_USB_STATUS__running__no 0 -#define R_USB_STATUS__running__yes 1 - -#define R_USB_IRQ_MASK_SET (IO_TYPECAST_UWORD 0xb0000204) -#define R_USB_IRQ_MASK_SET__iso_eof__BITNR 13 -#define R_USB_IRQ_MASK_SET__iso_eof__WIDTH 1 -#define R_USB_IRQ_MASK_SET__iso_eof__nop 0 -#define R_USB_IRQ_MASK_SET__iso_eof__set 1 -#define R_USB_IRQ_MASK_SET__intr_eof__BITNR 12 -#define R_USB_IRQ_MASK_SET__intr_eof__WIDTH 1 -#define R_USB_IRQ_MASK_SET__intr_eof__nop 0 -#define R_USB_IRQ_MASK_SET__intr_eof__set 1 -#define R_USB_IRQ_MASK_SET__iso_eot__BITNR 11 -#define R_USB_IRQ_MASK_SET__iso_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET__iso_eot__nop 0 -#define R_USB_IRQ_MASK_SET__iso_eot__set 1 -#define R_USB_IRQ_MASK_SET__intr_eot__BITNR 10 -#define R_USB_IRQ_MASK_SET__intr_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET__intr_eot__nop 0 -#define R_USB_IRQ_MASK_SET__intr_eot__set 1 -#define R_USB_IRQ_MASK_SET__ctl_eot__BITNR 9 -#define R_USB_IRQ_MASK_SET__ctl_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET__ctl_eot__nop 0 -#define R_USB_IRQ_MASK_SET__ctl_eot__set 1 -#define R_USB_IRQ_MASK_SET__bulk_eot__BITNR 8 -#define R_USB_IRQ_MASK_SET__bulk_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET__bulk_eot__nop 0 -#define R_USB_IRQ_MASK_SET__bulk_eot__set 1 -#define R_USB_IRQ_MASK_SET__epid_attn__BITNR 3 -#define R_USB_IRQ_MASK_SET__epid_attn__WIDTH 1 -#define R_USB_IRQ_MASK_SET__epid_attn__nop 0 -#define R_USB_IRQ_MASK_SET__epid_attn__set 1 -#define R_USB_IRQ_MASK_SET__sof__BITNR 2 -#define R_USB_IRQ_MASK_SET__sof__WIDTH 1 -#define R_USB_IRQ_MASK_SET__sof__nop 0 -#define R_USB_IRQ_MASK_SET__sof__set 1 -#define R_USB_IRQ_MASK_SET__port_status__BITNR 1 -#define R_USB_IRQ_MASK_SET__port_status__WIDTH 1 -#define R_USB_IRQ_MASK_SET__port_status__nop 0 -#define R_USB_IRQ_MASK_SET__port_status__set 1 -#define R_USB_IRQ_MASK_SET__ctl_status__BITNR 0 -#define R_USB_IRQ_MASK_SET__ctl_status__WIDTH 1 -#define R_USB_IRQ_MASK_SET__ctl_status__nop 0 -#define R_USB_IRQ_MASK_SET__ctl_status__set 1 - -#define R_USB_IRQ_MASK_READ (IO_TYPECAST_RO_UWORD 0xb0000204) -#define R_USB_IRQ_MASK_READ__iso_eof__BITNR 13 -#define R_USB_IRQ_MASK_READ__iso_eof__WIDTH 1 -#define R_USB_IRQ_MASK_READ__iso_eof__no_pend 0 -#define R_USB_IRQ_MASK_READ__iso_eof__pend 1 -#define R_USB_IRQ_MASK_READ__intr_eof__BITNR 12 -#define R_USB_IRQ_MASK_READ__intr_eof__WIDTH 1 -#define R_USB_IRQ_MASK_READ__intr_eof__no_pend 0 -#define R_USB_IRQ_MASK_READ__intr_eof__pend 1 -#define R_USB_IRQ_MASK_READ__iso_eot__BITNR 11 -#define R_USB_IRQ_MASK_READ__iso_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ__iso_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ__iso_eot__pend 1 -#define R_USB_IRQ_MASK_READ__intr_eot__BITNR 10 -#define R_USB_IRQ_MASK_READ__intr_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ__intr_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ__intr_eot__pend 1 -#define R_USB_IRQ_MASK_READ__ctl_eot__BITNR 9 -#define R_USB_IRQ_MASK_READ__ctl_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ__ctl_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ__ctl_eot__pend 1 -#define R_USB_IRQ_MASK_READ__bulk_eot__BITNR 8 -#define R_USB_IRQ_MASK_READ__bulk_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ__bulk_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ__bulk_eot__pend 1 -#define R_USB_IRQ_MASK_READ__epid_attn__BITNR 3 -#define R_USB_IRQ_MASK_READ__epid_attn__WIDTH 1 -#define R_USB_IRQ_MASK_READ__epid_attn__no_pend 0 -#define R_USB_IRQ_MASK_READ__epid_attn__pend 1 -#define R_USB_IRQ_MASK_READ__sof__BITNR 2 -#define R_USB_IRQ_MASK_READ__sof__WIDTH 1 -#define R_USB_IRQ_MASK_READ__sof__no_pend 0 -#define R_USB_IRQ_MASK_READ__sof__pend 1 -#define R_USB_IRQ_MASK_READ__port_status__BITNR 1 -#define R_USB_IRQ_MASK_READ__port_status__WIDTH 1 -#define R_USB_IRQ_MASK_READ__port_status__no_pend 0 -#define R_USB_IRQ_MASK_READ__port_status__pend 1 -#define R_USB_IRQ_MASK_READ__ctl_status__BITNR 0 -#define R_USB_IRQ_MASK_READ__ctl_status__WIDTH 1 -#define R_USB_IRQ_MASK_READ__ctl_status__no_pend 0 -#define R_USB_IRQ_MASK_READ__ctl_status__pend 1 - -#define R_USB_IRQ_MASK_CLR (IO_TYPECAST_UWORD 0xb0000206) -#define R_USB_IRQ_MASK_CLR__iso_eof__BITNR 13 -#define R_USB_IRQ_MASK_CLR__iso_eof__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__iso_eof__nop 0 -#define R_USB_IRQ_MASK_CLR__iso_eof__clr 1 -#define R_USB_IRQ_MASK_CLR__intr_eof__BITNR 12 -#define R_USB_IRQ_MASK_CLR__intr_eof__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__intr_eof__nop 0 -#define R_USB_IRQ_MASK_CLR__intr_eof__clr 1 -#define R_USB_IRQ_MASK_CLR__iso_eot__BITNR 11 -#define R_USB_IRQ_MASK_CLR__iso_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__iso_eot__nop 0 -#define R_USB_IRQ_MASK_CLR__iso_eot__clr 1 -#define R_USB_IRQ_MASK_CLR__intr_eot__BITNR 10 -#define R_USB_IRQ_MASK_CLR__intr_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__intr_eot__nop 0 -#define R_USB_IRQ_MASK_CLR__intr_eot__clr 1 -#define R_USB_IRQ_MASK_CLR__ctl_eot__BITNR 9 -#define R_USB_IRQ_MASK_CLR__ctl_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__ctl_eot__nop 0 -#define R_USB_IRQ_MASK_CLR__ctl_eot__clr 1 -#define R_USB_IRQ_MASK_CLR__bulk_eot__BITNR 8 -#define R_USB_IRQ_MASK_CLR__bulk_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__bulk_eot__nop 0 -#define R_USB_IRQ_MASK_CLR__bulk_eot__clr 1 -#define R_USB_IRQ_MASK_CLR__epid_attn__BITNR 3 -#define R_USB_IRQ_MASK_CLR__epid_attn__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__epid_attn__nop 0 -#define R_USB_IRQ_MASK_CLR__epid_attn__clr 1 -#define R_USB_IRQ_MASK_CLR__sof__BITNR 2 -#define R_USB_IRQ_MASK_CLR__sof__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__sof__nop 0 -#define R_USB_IRQ_MASK_CLR__sof__clr 1 -#define R_USB_IRQ_MASK_CLR__port_status__BITNR 1 -#define R_USB_IRQ_MASK_CLR__port_status__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__port_status__nop 0 -#define R_USB_IRQ_MASK_CLR__port_status__clr 1 -#define R_USB_IRQ_MASK_CLR__ctl_status__BITNR 0 -#define R_USB_IRQ_MASK_CLR__ctl_status__WIDTH 1 -#define R_USB_IRQ_MASK_CLR__ctl_status__nop 0 -#define R_USB_IRQ_MASK_CLR__ctl_status__clr 1 - -#define R_USB_IRQ_READ (IO_TYPECAST_RO_UWORD 0xb0000206) -#define R_USB_IRQ_READ__iso_eof__BITNR 13 -#define R_USB_IRQ_READ__iso_eof__WIDTH 1 -#define R_USB_IRQ_READ__iso_eof__no_pend 0 -#define R_USB_IRQ_READ__iso_eof__pend 1 -#define R_USB_IRQ_READ__intr_eof__BITNR 12 -#define R_USB_IRQ_READ__intr_eof__WIDTH 1 -#define R_USB_IRQ_READ__intr_eof__no_pend 0 -#define R_USB_IRQ_READ__intr_eof__pend 1 -#define R_USB_IRQ_READ__iso_eot__BITNR 11 -#define R_USB_IRQ_READ__iso_eot__WIDTH 1 -#define R_USB_IRQ_READ__iso_eot__no_pend 0 -#define R_USB_IRQ_READ__iso_eot__pend 1 -#define R_USB_IRQ_READ__intr_eot__BITNR 10 -#define R_USB_IRQ_READ__intr_eot__WIDTH 1 -#define R_USB_IRQ_READ__intr_eot__no_pend 0 -#define R_USB_IRQ_READ__intr_eot__pend 1 -#define R_USB_IRQ_READ__ctl_eot__BITNR 9 -#define R_USB_IRQ_READ__ctl_eot__WIDTH 1 -#define R_USB_IRQ_READ__ctl_eot__no_pend 0 -#define R_USB_IRQ_READ__ctl_eot__pend 1 -#define R_USB_IRQ_READ__bulk_eot__BITNR 8 -#define R_USB_IRQ_READ__bulk_eot__WIDTH 1 -#define R_USB_IRQ_READ__bulk_eot__no_pend 0 -#define R_USB_IRQ_READ__bulk_eot__pend 1 -#define R_USB_IRQ_READ__epid_attn__BITNR 3 -#define R_USB_IRQ_READ__epid_attn__WIDTH 1 -#define R_USB_IRQ_READ__epid_attn__no_pend 0 -#define R_USB_IRQ_READ__epid_attn__pend 1 -#define R_USB_IRQ_READ__sof__BITNR 2 -#define R_USB_IRQ_READ__sof__WIDTH 1 -#define R_USB_IRQ_READ__sof__no_pend 0 -#define R_USB_IRQ_READ__sof__pend 1 -#define R_USB_IRQ_READ__port_status__BITNR 1 -#define R_USB_IRQ_READ__port_status__WIDTH 1 -#define R_USB_IRQ_READ__port_status__no_pend 0 -#define R_USB_IRQ_READ__port_status__pend 1 -#define R_USB_IRQ_READ__ctl_status__BITNR 0 -#define R_USB_IRQ_READ__ctl_status__WIDTH 1 -#define R_USB_IRQ_READ__ctl_status__no_pend 0 -#define R_USB_IRQ_READ__ctl_status__pend 1 - -#define R_USB_IRQ_MASK_SET_DEV (IO_TYPECAST_UWORD 0xb0000204) -#define R_USB_IRQ_MASK_SET_DEV__out_eot__BITNR 12 -#define R_USB_IRQ_MASK_SET_DEV__out_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET_DEV__out_eot__nop 0 -#define R_USB_IRQ_MASK_SET_DEV__out_eot__set 1 -#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__BITNR 11 -#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__nop 0 -#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__set 1 -#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__BITNR 10 -#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__nop 0 -#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__set 1 -#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__BITNR 9 -#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__nop 0 -#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__set 1 -#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__BITNR 8 -#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__nop 0 -#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__set 1 -#define R_USB_IRQ_MASK_SET_DEV__epid_attn__BITNR 3 -#define R_USB_IRQ_MASK_SET_DEV__epid_attn__WIDTH 1 -#define R_USB_IRQ_MASK_SET_DEV__epid_attn__nop 0 -#define R_USB_IRQ_MASK_SET_DEV__epid_attn__set 1 -#define R_USB_IRQ_MASK_SET_DEV__sof__BITNR 2 -#define R_USB_IRQ_MASK_SET_DEV__sof__WIDTH 1 -#define R_USB_IRQ_MASK_SET_DEV__sof__nop 0 -#define R_USB_IRQ_MASK_SET_DEV__sof__set 1 -#define R_USB_IRQ_MASK_SET_DEV__port_status__BITNR 1 -#define R_USB_IRQ_MASK_SET_DEV__port_status__WIDTH 1 -#define R_USB_IRQ_MASK_SET_DEV__port_status__nop 0 -#define R_USB_IRQ_MASK_SET_DEV__port_status__set 1 -#define R_USB_IRQ_MASK_SET_DEV__ctl_status__BITNR 0 -#define R_USB_IRQ_MASK_SET_DEV__ctl_status__WIDTH 1 -#define R_USB_IRQ_MASK_SET_DEV__ctl_status__nop 0 -#define R_USB_IRQ_MASK_SET_DEV__ctl_status__set 1 - -#define R_USB_IRQ_MASK_READ_DEV (IO_TYPECAST_RO_UWORD 0xb0000204) -#define R_USB_IRQ_MASK_READ_DEV__out_eot__BITNR 12 -#define R_USB_IRQ_MASK_READ_DEV__out_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ_DEV__out_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ_DEV__out_eot__pend 1 -#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__BITNR 11 -#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__pend 1 -#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__BITNR 10 -#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__pend 1 -#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__BITNR 9 -#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__pend 1 -#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__BITNR 8 -#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__no_pend 0 -#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__pend 1 -#define R_USB_IRQ_MASK_READ_DEV__epid_attn__BITNR 3 -#define R_USB_IRQ_MASK_READ_DEV__epid_attn__WIDTH 1 -#define R_USB_IRQ_MASK_READ_DEV__epid_attn__no_pend 0 -#define R_USB_IRQ_MASK_READ_DEV__epid_attn__pend 1 -#define R_USB_IRQ_MASK_READ_DEV__sof__BITNR 2 -#define R_USB_IRQ_MASK_READ_DEV__sof__WIDTH 1 -#define R_USB_IRQ_MASK_READ_DEV__sof__no_pend 0 -#define R_USB_IRQ_MASK_READ_DEV__sof__pend 1 -#define R_USB_IRQ_MASK_READ_DEV__port_status__BITNR 1 -#define R_USB_IRQ_MASK_READ_DEV__port_status__WIDTH 1 -#define R_USB_IRQ_MASK_READ_DEV__port_status__no_pend 0 -#define R_USB_IRQ_MASK_READ_DEV__port_status__pend 1 -#define R_USB_IRQ_MASK_READ_DEV__ctl_status__BITNR 0 -#define R_USB_IRQ_MASK_READ_DEV__ctl_status__WIDTH 1 -#define R_USB_IRQ_MASK_READ_DEV__ctl_status__no_pend 0 -#define R_USB_IRQ_MASK_READ_DEV__ctl_status__pend 1 - -#define R_USB_IRQ_MASK_CLR_DEV (IO_TYPECAST_UWORD 0xb0000206) -#define R_USB_IRQ_MASK_CLR_DEV__out_eot__BITNR 12 -#define R_USB_IRQ_MASK_CLR_DEV__out_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR_DEV__out_eot__nop 0 -#define R_USB_IRQ_MASK_CLR_DEV__out_eot__clr 1 -#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__BITNR 11 -#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__nop 0 -#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__clr 1 -#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__BITNR 10 -#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__nop 0 -#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__clr 1 -#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__BITNR 9 -#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__nop 0 -#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__clr 1 -#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__BITNR 8 -#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__WIDTH 1 -#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__nop 0 -#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__clr 1 -#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__BITNR 3 -#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__WIDTH 1 -#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__nop 0 -#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__clr 1 -#define R_USB_IRQ_MASK_CLR_DEV__sof__BITNR 2 -#define R_USB_IRQ_MASK_CLR_DEV__sof__WIDTH 1 -#define R_USB_IRQ_MASK_CLR_DEV__sof__nop 0 -#define R_USB_IRQ_MASK_CLR_DEV__sof__clr 1 -#define R_USB_IRQ_MASK_CLR_DEV__port_status__BITNR 1 -#define R_USB_IRQ_MASK_CLR_DEV__port_status__WIDTH 1 -#define R_USB_IRQ_MASK_CLR_DEV__port_status__nop 0 -#define R_USB_IRQ_MASK_CLR_DEV__port_status__clr 1 -#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__BITNR 0 -#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__WIDTH 1 -#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__nop 0 -#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__clr 1 - -#define R_USB_IRQ_READ_DEV (IO_TYPECAST_RO_UWORD 0xb0000206) -#define R_USB_IRQ_READ_DEV__out_eot__BITNR 12 -#define R_USB_IRQ_READ_DEV__out_eot__WIDTH 1 -#define R_USB_IRQ_READ_DEV__out_eot__no_pend 0 -#define R_USB_IRQ_READ_DEV__out_eot__pend 1 -#define R_USB_IRQ_READ_DEV__ep3_in_eot__BITNR 11 -#define R_USB_IRQ_READ_DEV__ep3_in_eot__WIDTH 1 -#define R_USB_IRQ_READ_DEV__ep3_in_eot__no_pend 0 -#define R_USB_IRQ_READ_DEV__ep3_in_eot__pend 1 -#define R_USB_IRQ_READ_DEV__ep2_in_eot__BITNR 10 -#define R_USB_IRQ_READ_DEV__ep2_in_eot__WIDTH 1 -#define R_USB_IRQ_READ_DEV__ep2_in_eot__no_pend 0 -#define R_USB_IRQ_READ_DEV__ep2_in_eot__pend 1 -#define R_USB_IRQ_READ_DEV__ep1_in_eot__BITNR 9 -#define R_USB_IRQ_READ_DEV__ep1_in_eot__WIDTH 1 -#define R_USB_IRQ_READ_DEV__ep1_in_eot__no_pend 0 -#define R_USB_IRQ_READ_DEV__ep1_in_eot__pend 1 -#define R_USB_IRQ_READ_DEV__ep0_in_eot__BITNR 8 -#define R_USB_IRQ_READ_DEV__ep0_in_eot__WIDTH 1 -#define R_USB_IRQ_READ_DEV__ep0_in_eot__no_pend 0 -#define R_USB_IRQ_READ_DEV__ep0_in_eot__pend 1 -#define R_USB_IRQ_READ_DEV__epid_attn__BITNR 3 -#define R_USB_IRQ_READ_DEV__epid_attn__WIDTH 1 -#define R_USB_IRQ_READ_DEV__epid_attn__no_pend 0 -#define R_USB_IRQ_READ_DEV__epid_attn__pend 1 -#define R_USB_IRQ_READ_DEV__sof__BITNR 2 -#define R_USB_IRQ_READ_DEV__sof__WIDTH 1 -#define R_USB_IRQ_READ_DEV__sof__no_pend 0 -#define R_USB_IRQ_READ_DEV__sof__pend 1 -#define R_USB_IRQ_READ_DEV__port_status__BITNR 1 -#define R_USB_IRQ_READ_DEV__port_status__WIDTH 1 -#define R_USB_IRQ_READ_DEV__port_status__no_pend 0 -#define R_USB_IRQ_READ_DEV__port_status__pend 1 -#define R_USB_IRQ_READ_DEV__ctl_status__BITNR 0 -#define R_USB_IRQ_READ_DEV__ctl_status__WIDTH 1 -#define R_USB_IRQ_READ_DEV__ctl_status__no_pend 0 -#define R_USB_IRQ_READ_DEV__ctl_status__pend 1 - -#define R_USB_FM_NUMBER (IO_TYPECAST_UDWORD 0xb000020c) -#define R_USB_FM_NUMBER__value__BITNR 0 -#define R_USB_FM_NUMBER__value__WIDTH 32 - -#define R_USB_FM_INTERVAL (IO_TYPECAST_UWORD 0xb0000210) -#define R_USB_FM_INTERVAL__fixed__BITNR 6 -#define R_USB_FM_INTERVAL__fixed__WIDTH 8 -#define R_USB_FM_INTERVAL__adj__BITNR 0 -#define R_USB_FM_INTERVAL__adj__WIDTH 6 - -#define R_USB_FM_REMAINING (IO_TYPECAST_RO_UWORD 0xb0000212) -#define R_USB_FM_REMAINING__value__BITNR 0 -#define R_USB_FM_REMAINING__value__WIDTH 14 - -#define R_USB_FM_PSTART (IO_TYPECAST_UWORD 0xb0000214) -#define R_USB_FM_PSTART__value__BITNR 0 -#define R_USB_FM_PSTART__value__WIDTH 14 - -#define R_USB_RH_STATUS (IO_TYPECAST_RO_BYTE 0xb0000203) -#define R_USB_RH_STATUS__babble2__BITNR 7 -#define R_USB_RH_STATUS__babble2__WIDTH 1 -#define R_USB_RH_STATUS__babble2__no 0 -#define R_USB_RH_STATUS__babble2__yes 1 -#define R_USB_RH_STATUS__babble1__BITNR 6 -#define R_USB_RH_STATUS__babble1__WIDTH 1 -#define R_USB_RH_STATUS__babble1__no 0 -#define R_USB_RH_STATUS__babble1__yes 1 -#define R_USB_RH_STATUS__bus1__BITNR 4 -#define R_USB_RH_STATUS__bus1__WIDTH 2 -#define R_USB_RH_STATUS__bus1__SE0 0 -#define R_USB_RH_STATUS__bus1__Diff0 1 -#define R_USB_RH_STATUS__bus1__Diff1 2 -#define R_USB_RH_STATUS__bus1__SE1 3 -#define R_USB_RH_STATUS__bus2__BITNR 2 -#define R_USB_RH_STATUS__bus2__WIDTH 2 -#define R_USB_RH_STATUS__bus2__SE0 0 -#define R_USB_RH_STATUS__bus2__Diff0 1 -#define R_USB_RH_STATUS__bus2__Diff1 2 -#define R_USB_RH_STATUS__bus2__SE1 3 -#define R_USB_RH_STATUS__nports__BITNR 0 -#define R_USB_RH_STATUS__nports__WIDTH 2 - -#define R_USB_RH_PORT_STATUS_1 (IO_TYPECAST_RO_UWORD 0xb0000218) -#define R_USB_RH_PORT_STATUS_1__speed__BITNR 9 -#define R_USB_RH_PORT_STATUS_1__speed__WIDTH 1 -#define R_USB_RH_PORT_STATUS_1__speed__full 0 -#define R_USB_RH_PORT_STATUS_1__speed__low 1 -#define R_USB_RH_PORT_STATUS_1__power__BITNR 8 -#define R_USB_RH_PORT_STATUS_1__power__WIDTH 1 -#define R_USB_RH_PORT_STATUS_1__reset__BITNR 4 -#define R_USB_RH_PORT_STATUS_1__reset__WIDTH 1 -#define R_USB_RH_PORT_STATUS_1__reset__no 0 -#define R_USB_RH_PORT_STATUS_1__reset__yes 1 -#define R_USB_RH_PORT_STATUS_1__overcurrent__BITNR 3 -#define R_USB_RH_PORT_STATUS_1__overcurrent__WIDTH 1 -#define R_USB_RH_PORT_STATUS_1__overcurrent__no 0 -#define R_USB_RH_PORT_STATUS_1__overcurrent__yes 1 -#define R_USB_RH_PORT_STATUS_1__suspended__BITNR 2 -#define R_USB_RH_PORT_STATUS_1__suspended__WIDTH 1 -#define R_USB_RH_PORT_STATUS_1__suspended__no 0 -#define R_USB_RH_PORT_STATUS_1__suspended__yes 1 -#define R_USB_RH_PORT_STATUS_1__enabled__BITNR 1 -#define R_USB_RH_PORT_STATUS_1__enabled__WIDTH 1 -#define R_USB_RH_PORT_STATUS_1__enabled__no 0 -#define R_USB_RH_PORT_STATUS_1__enabled__yes 1 -#define R_USB_RH_PORT_STATUS_1__connected__BITNR 0 -#define R_USB_RH_PORT_STATUS_1__connected__WIDTH 1 -#define R_USB_RH_PORT_STATUS_1__connected__no 0 -#define R_USB_RH_PORT_STATUS_1__connected__yes 1 - -#define R_USB_RH_PORT_STATUS_2 (IO_TYPECAST_RO_UWORD 0xb000021a) -#define R_USB_RH_PORT_STATUS_2__speed__BITNR 9 -#define R_USB_RH_PORT_STATUS_2__speed__WIDTH 1 -#define R_USB_RH_PORT_STATUS_2__speed__full 0 -#define R_USB_RH_PORT_STATUS_2__speed__low 1 -#define R_USB_RH_PORT_STATUS_2__power__BITNR 8 -#define R_USB_RH_PORT_STATUS_2__power__WIDTH 1 -#define R_USB_RH_PORT_STATUS_2__reset__BITNR 4 -#define R_USB_RH_PORT_STATUS_2__reset__WIDTH 1 -#define R_USB_RH_PORT_STATUS_2__reset__no 0 -#define R_USB_RH_PORT_STATUS_2__reset__yes 1 -#define R_USB_RH_PORT_STATUS_2__overcurrent__BITNR 3 -#define R_USB_RH_PORT_STATUS_2__overcurrent__WIDTH 1 -#define R_USB_RH_PORT_STATUS_2__overcurrent__no 0 -#define R_USB_RH_PORT_STATUS_2__overcurrent__yes 1 -#define R_USB_RH_PORT_STATUS_2__suspended__BITNR 2 -#define R_USB_RH_PORT_STATUS_2__suspended__WIDTH 1 -#define R_USB_RH_PORT_STATUS_2__suspended__no 0 -#define R_USB_RH_PORT_STATUS_2__suspended__yes 1 -#define R_USB_RH_PORT_STATUS_2__enabled__BITNR 1 -#define R_USB_RH_PORT_STATUS_2__enabled__WIDTH 1 -#define R_USB_RH_PORT_STATUS_2__enabled__no 0 -#define R_USB_RH_PORT_STATUS_2__enabled__yes 1 -#define R_USB_RH_PORT_STATUS_2__connected__BITNR 0 -#define R_USB_RH_PORT_STATUS_2__connected__WIDTH 1 -#define R_USB_RH_PORT_STATUS_2__connected__no 0 -#define R_USB_RH_PORT_STATUS_2__connected__yes 1 - -#define R_USB_EPT_INDEX (IO_TYPECAST_BYTE 0xb0000208) -#define R_USB_EPT_INDEX__value__BITNR 0 -#define R_USB_EPT_INDEX__value__WIDTH 5 - -#define R_USB_EPT_DATA (IO_TYPECAST_UDWORD 0xb000021c) -#define R_USB_EPT_DATA__valid__BITNR 31 -#define R_USB_EPT_DATA__valid__WIDTH 1 -#define R_USB_EPT_DATA__valid__no 0 -#define R_USB_EPT_DATA__valid__yes 1 -#define R_USB_EPT_DATA__hold__BITNR 30 -#define R_USB_EPT_DATA__hold__WIDTH 1 -#define R_USB_EPT_DATA__hold__no 0 -#define R_USB_EPT_DATA__hold__yes 1 -#define R_USB_EPT_DATA__error_count_in__BITNR 28 -#define R_USB_EPT_DATA__error_count_in__WIDTH 2 -#define R_USB_EPT_DATA__t_in__BITNR 27 -#define R_USB_EPT_DATA__t_in__WIDTH 1 -#define R_USB_EPT_DATA__low_speed__BITNR 26 -#define R_USB_EPT_DATA__low_speed__WIDTH 1 -#define R_USB_EPT_DATA__low_speed__no 0 -#define R_USB_EPT_DATA__low_speed__yes 1 -#define R_USB_EPT_DATA__port__BITNR 24 -#define R_USB_EPT_DATA__port__WIDTH 2 -#define R_USB_EPT_DATA__port__any 0 -#define R_USB_EPT_DATA__port__p1 1 -#define R_USB_EPT_DATA__port__p2 2 -#define R_USB_EPT_DATA__port__undef 3 -#define R_USB_EPT_DATA__error_code__BITNR 22 -#define R_USB_EPT_DATA__error_code__WIDTH 2 -#define R_USB_EPT_DATA__error_code__no_error 0 -#define R_USB_EPT_DATA__error_code__stall 1 -#define R_USB_EPT_DATA__error_code__bus_error 2 -#define R_USB_EPT_DATA__error_code__buffer_error 3 -#define R_USB_EPT_DATA__t_out__BITNR 21 -#define R_USB_EPT_DATA__t_out__WIDTH 1 -#define R_USB_EPT_DATA__error_count_out__BITNR 19 -#define R_USB_EPT_DATA__error_count_out__WIDTH 2 -#define R_USB_EPT_DATA__max_len__BITNR 11 -#define R_USB_EPT_DATA__max_len__WIDTH 7 -#define R_USB_EPT_DATA__ep__BITNR 7 -#define R_USB_EPT_DATA__ep__WIDTH 4 -#define R_USB_EPT_DATA__dev__BITNR 0 -#define R_USB_EPT_DATA__dev__WIDTH 7 - -#define R_USB_EPT_DATA_ISO (IO_TYPECAST_UDWORD 0xb000021c) -#define R_USB_EPT_DATA_ISO__valid__BITNR 31 -#define R_USB_EPT_DATA_ISO__valid__WIDTH 1 -#define R_USB_EPT_DATA_ISO__valid__no 0 -#define R_USB_EPT_DATA_ISO__valid__yes 1 -#define R_USB_EPT_DATA_ISO__port__BITNR 24 -#define R_USB_EPT_DATA_ISO__port__WIDTH 2 -#define R_USB_EPT_DATA_ISO__port__any 0 -#define R_USB_EPT_DATA_ISO__port__p1 1 -#define R_USB_EPT_DATA_ISO__port__p2 2 -#define R_USB_EPT_DATA_ISO__port__undef 3 -#define R_USB_EPT_DATA_ISO__error_code__BITNR 22 -#define R_USB_EPT_DATA_ISO__error_code__WIDTH 2 -#define R_USB_EPT_DATA_ISO__error_code__no_error 0 -#define R_USB_EPT_DATA_ISO__error_code__stall 1 -#define R_USB_EPT_DATA_ISO__error_code__bus_error 2 -#define R_USB_EPT_DATA_ISO__error_code__TBD3 3 -#define R_USB_EPT_DATA_ISO__max_len__BITNR 11 -#define R_USB_EPT_DATA_ISO__max_len__WIDTH 10 -#define R_USB_EPT_DATA_ISO__ep__BITNR 7 -#define R_USB_EPT_DATA_ISO__ep__WIDTH 4 -#define R_USB_EPT_DATA_ISO__dev__BITNR 0 -#define R_USB_EPT_DATA_ISO__dev__WIDTH 7 - -#define R_USB_EPT_DATA_DEV (IO_TYPECAST_UDWORD 0xb000021c) -#define R_USB_EPT_DATA_DEV__valid__BITNR 31 -#define R_USB_EPT_DATA_DEV__valid__WIDTH 1 -#define R_USB_EPT_DATA_DEV__valid__no 0 -#define R_USB_EPT_DATA_DEV__valid__yes 1 -#define R_USB_EPT_DATA_DEV__hold__BITNR 30 -#define R_USB_EPT_DATA_DEV__hold__WIDTH 1 -#define R_USB_EPT_DATA_DEV__hold__no 0 -#define R_USB_EPT_DATA_DEV__hold__yes 1 -#define R_USB_EPT_DATA_DEV__stall__BITNR 29 -#define R_USB_EPT_DATA_DEV__stall__WIDTH 1 -#define R_USB_EPT_DATA_DEV__stall__no 0 -#define R_USB_EPT_DATA_DEV__stall__yes 1 -#define R_USB_EPT_DATA_DEV__iso_resp__BITNR 28 -#define R_USB_EPT_DATA_DEV__iso_resp__WIDTH 1 -#define R_USB_EPT_DATA_DEV__iso_resp__quiet 0 -#define R_USB_EPT_DATA_DEV__iso_resp__yes 1 -#define R_USB_EPT_DATA_DEV__ctrl__BITNR 27 -#define R_USB_EPT_DATA_DEV__ctrl__WIDTH 1 -#define R_USB_EPT_DATA_DEV__ctrl__no 0 -#define R_USB_EPT_DATA_DEV__ctrl__yes 1 -#define R_USB_EPT_DATA_DEV__iso__BITNR 26 -#define R_USB_EPT_DATA_DEV__iso__WIDTH 1 -#define R_USB_EPT_DATA_DEV__iso__no 0 -#define R_USB_EPT_DATA_DEV__iso__yes 1 -#define R_USB_EPT_DATA_DEV__port__BITNR 24 -#define R_USB_EPT_DATA_DEV__port__WIDTH 2 -#define R_USB_EPT_DATA_DEV__control_phase__BITNR 22 -#define R_USB_EPT_DATA_DEV__control_phase__WIDTH 1 -#define R_USB_EPT_DATA_DEV__t__BITNR 21 -#define R_USB_EPT_DATA_DEV__t__WIDTH 1 -#define R_USB_EPT_DATA_DEV__max_len__BITNR 11 -#define R_USB_EPT_DATA_DEV__max_len__WIDTH 10 -#define R_USB_EPT_DATA_DEV__ep__BITNR 7 -#define R_USB_EPT_DATA_DEV__ep__WIDTH 4 -#define R_USB_EPT_DATA_DEV__dev__BITNR 0 -#define R_USB_EPT_DATA_DEV__dev__WIDTH 7 - -#define R_USB_SNMP_TERROR (IO_TYPECAST_UDWORD 0xb0000220) -#define R_USB_SNMP_TERROR__value__BITNR 0 -#define R_USB_SNMP_TERROR__value__WIDTH 32 - -#define R_USB_EPID_ATTN (IO_TYPECAST_RO_UDWORD 0xb0000224) -#define R_USB_EPID_ATTN__value__BITNR 0 -#define R_USB_EPID_ATTN__value__WIDTH 32 - -#define R_USB_PORT1_DISABLE (IO_TYPECAST_BYTE 0xb000006a) -#define R_USB_PORT1_DISABLE__disable__BITNR 0 -#define R_USB_PORT1_DISABLE__disable__WIDTH 1 -#define R_USB_PORT1_DISABLE__disable__yes 0 -#define R_USB_PORT1_DISABLE__disable__no 1 - -#define R_USB_PORT2_DISABLE (IO_TYPECAST_BYTE 0xb0000052) -#define R_USB_PORT2_DISABLE__disable__BITNR 0 -#define R_USB_PORT2_DISABLE__disable__WIDTH 1 -#define R_USB_PORT2_DISABLE__disable__yes 0 -#define R_USB_PORT2_DISABLE__disable__no 1 - -/* -!* MMU registers -!*/ - -#define R_MMU_CONFIG (IO_TYPECAST_UDWORD 0xb0000240) -#define R_MMU_CONFIG__mmu_enable__BITNR 31 -#define R_MMU_CONFIG__mmu_enable__WIDTH 1 -#define R_MMU_CONFIG__mmu_enable__enable 1 -#define R_MMU_CONFIG__mmu_enable__disable 0 -#define R_MMU_CONFIG__inv_excp__BITNR 18 -#define R_MMU_CONFIG__inv_excp__WIDTH 1 -#define R_MMU_CONFIG__inv_excp__enable 1 -#define R_MMU_CONFIG__inv_excp__disable 0 -#define R_MMU_CONFIG__acc_excp__BITNR 17 -#define R_MMU_CONFIG__acc_excp__WIDTH 1 -#define R_MMU_CONFIG__acc_excp__enable 1 -#define R_MMU_CONFIG__acc_excp__disable 0 -#define R_MMU_CONFIG__we_excp__BITNR 16 -#define R_MMU_CONFIG__we_excp__WIDTH 1 -#define R_MMU_CONFIG__we_excp__enable 1 -#define R_MMU_CONFIG__we_excp__disable 0 -#define R_MMU_CONFIG__seg_f__BITNR 15 -#define R_MMU_CONFIG__seg_f__WIDTH 1 -#define R_MMU_CONFIG__seg_f__seg 1 -#define R_MMU_CONFIG__seg_f__page 0 -#define R_MMU_CONFIG__seg_e__BITNR 14 -#define R_MMU_CONFIG__seg_e__WIDTH 1 -#define R_MMU_CONFIG__seg_e__seg 1 -#define R_MMU_CONFIG__seg_e__page 0 -#define R_MMU_CONFIG__seg_d__BITNR 13 -#define R_MMU_CONFIG__seg_d__WIDTH 1 -#define R_MMU_CONFIG__seg_d__seg 1 -#define R_MMU_CONFIG__seg_d__page 0 -#define R_MMU_CONFIG__seg_c__BITNR 12 -#define R_MMU_CONFIG__seg_c__WIDTH 1 -#define R_MMU_CONFIG__seg_c__seg 1 -#define R_MMU_CONFIG__seg_c__page 0 -#define R_MMU_CONFIG__seg_b__BITNR 11 -#define R_MMU_CONFIG__seg_b__WIDTH 1 -#define R_MMU_CONFIG__seg_b__seg 1 -#define R_MMU_CONFIG__seg_b__page 0 -#define R_MMU_CONFIG__seg_a__BITNR 10 -#define R_MMU_CONFIG__seg_a__WIDTH 1 -#define R_MMU_CONFIG__seg_a__seg 1 -#define R_MMU_CONFIG__seg_a__page 0 -#define R_MMU_CONFIG__seg_9__BITNR 9 -#define R_MMU_CONFIG__seg_9__WIDTH 1 -#define R_MMU_CONFIG__seg_9__seg 1 -#define R_MMU_CONFIG__seg_9__page 0 -#define R_MMU_CONFIG__seg_8__BITNR 8 -#define R_MMU_CONFIG__seg_8__WIDTH 1 -#define R_MMU_CONFIG__seg_8__seg 1 -#define R_MMU_CONFIG__seg_8__page 0 -#define R_MMU_CONFIG__seg_7__BITNR 7 -#define R_MMU_CONFIG__seg_7__WIDTH 1 -#define R_MMU_CONFIG__seg_7__seg 1 -#define R_MMU_CONFIG__seg_7__page 0 -#define R_MMU_CONFIG__seg_6__BITNR 6 -#define R_MMU_CONFIG__seg_6__WIDTH 1 -#define R_MMU_CONFIG__seg_6__seg 1 -#define R_MMU_CONFIG__seg_6__page 0 -#define R_MMU_CONFIG__seg_5__BITNR 5 -#define R_MMU_CONFIG__seg_5__WIDTH 1 -#define R_MMU_CONFIG__seg_5__seg 1 -#define R_MMU_CONFIG__seg_5__page 0 -#define R_MMU_CONFIG__seg_4__BITNR 4 -#define R_MMU_CONFIG__seg_4__WIDTH 1 -#define R_MMU_CONFIG__seg_4__seg 1 -#define R_MMU_CONFIG__seg_4__page 0 -#define R_MMU_CONFIG__seg_3__BITNR 3 -#define R_MMU_CONFIG__seg_3__WIDTH 1 -#define R_MMU_CONFIG__seg_3__seg 1 -#define R_MMU_CONFIG__seg_3__page 0 -#define R_MMU_CONFIG__seg_2__BITNR 2 -#define R_MMU_CONFIG__seg_2__WIDTH 1 -#define R_MMU_CONFIG__seg_2__seg 1 -#define R_MMU_CONFIG__seg_2__page 0 -#define R_MMU_CONFIG__seg_1__BITNR 1 -#define R_MMU_CONFIG__seg_1__WIDTH 1 -#define R_MMU_CONFIG__seg_1__seg 1 -#define R_MMU_CONFIG__seg_1__page 0 -#define R_MMU_CONFIG__seg_0__BITNR 0 -#define R_MMU_CONFIG__seg_0__WIDTH 1 -#define R_MMU_CONFIG__seg_0__seg 1 -#define R_MMU_CONFIG__seg_0__page 0 - -#define R_MMU_KSEG (IO_TYPECAST_UWORD 0xb0000240) -#define R_MMU_KSEG__seg_f__BITNR 15 -#define R_MMU_KSEG__seg_f__WIDTH 1 -#define R_MMU_KSEG__seg_f__seg 1 -#define R_MMU_KSEG__seg_f__page 0 -#define R_MMU_KSEG__seg_e__BITNR 14 -#define R_MMU_KSEG__seg_e__WIDTH 1 -#define R_MMU_KSEG__seg_e__seg 1 -#define R_MMU_KSEG__seg_e__page 0 -#define R_MMU_KSEG__seg_d__BITNR 13 -#define R_MMU_KSEG__seg_d__WIDTH 1 -#define R_MMU_KSEG__seg_d__seg 1 -#define R_MMU_KSEG__seg_d__page 0 -#define R_MMU_KSEG__seg_c__BITNR 12 -#define R_MMU_KSEG__seg_c__WIDTH 1 -#define R_MMU_KSEG__seg_c__seg 1 -#define R_MMU_KSEG__seg_c__page 0 -#define R_MMU_KSEG__seg_b__BITNR 11 -#define R_MMU_KSEG__seg_b__WIDTH 1 -#define R_MMU_KSEG__seg_b__seg 1 -#define R_MMU_KSEG__seg_b__page 0 -#define R_MMU_KSEG__seg_a__BITNR 10 -#define R_MMU_KSEG__seg_a__WIDTH 1 -#define R_MMU_KSEG__seg_a__seg 1 -#define R_MMU_KSEG__seg_a__page 0 -#define R_MMU_KSEG__seg_9__BITNR 9 -#define R_MMU_KSEG__seg_9__WIDTH 1 -#define R_MMU_KSEG__seg_9__seg 1 -#define R_MMU_KSEG__seg_9__page 0 -#define R_MMU_KSEG__seg_8__BITNR 8 -#define R_MMU_KSEG__seg_8__WIDTH 1 -#define R_MMU_KSEG__seg_8__seg 1 -#define R_MMU_KSEG__seg_8__page 0 -#define R_MMU_KSEG__seg_7__BITNR 7 -#define R_MMU_KSEG__seg_7__WIDTH 1 -#define R_MMU_KSEG__seg_7__seg 1 -#define R_MMU_KSEG__seg_7__page 0 -#define R_MMU_KSEG__seg_6__BITNR 6 -#define R_MMU_KSEG__seg_6__WIDTH 1 -#define R_MMU_KSEG__seg_6__seg 1 -#define R_MMU_KSEG__seg_6__page 0 -#define R_MMU_KSEG__seg_5__BITNR 5 -#define R_MMU_KSEG__seg_5__WIDTH 1 -#define R_MMU_KSEG__seg_5__seg 1 -#define R_MMU_KSEG__seg_5__page 0 -#define R_MMU_KSEG__seg_4__BITNR 4 -#define R_MMU_KSEG__seg_4__WIDTH 1 -#define R_MMU_KSEG__seg_4__seg 1 -#define R_MMU_KSEG__seg_4__page 0 -#define R_MMU_KSEG__seg_3__BITNR 3 -#define R_MMU_KSEG__seg_3__WIDTH 1 -#define R_MMU_KSEG__seg_3__seg 1 -#define R_MMU_KSEG__seg_3__page 0 -#define R_MMU_KSEG__seg_2__BITNR 2 -#define R_MMU_KSEG__seg_2__WIDTH 1 -#define R_MMU_KSEG__seg_2__seg 1 -#define R_MMU_KSEG__seg_2__page 0 -#define R_MMU_KSEG__seg_1__BITNR 1 -#define R_MMU_KSEG__seg_1__WIDTH 1 -#define R_MMU_KSEG__seg_1__seg 1 -#define R_MMU_KSEG__seg_1__page 0 -#define R_MMU_KSEG__seg_0__BITNR 0 -#define R_MMU_KSEG__seg_0__WIDTH 1 -#define R_MMU_KSEG__seg_0__seg 1 -#define R_MMU_KSEG__seg_0__page 0 - -#define R_MMU_CTRL (IO_TYPECAST_BYTE 0xb0000242) -#define R_MMU_CTRL__inv_excp__BITNR 2 -#define R_MMU_CTRL__inv_excp__WIDTH 1 -#define R_MMU_CTRL__inv_excp__enable 1 -#define R_MMU_CTRL__inv_excp__disable 0 -#define R_MMU_CTRL__acc_excp__BITNR 1 -#define R_MMU_CTRL__acc_excp__WIDTH 1 -#define R_MMU_CTRL__acc_excp__enable 1 -#define R_MMU_CTRL__acc_excp__disable 0 -#define R_MMU_CTRL__we_excp__BITNR 0 -#define R_MMU_CTRL__we_excp__WIDTH 1 -#define R_MMU_CTRL__we_excp__enable 1 -#define R_MMU_CTRL__we_excp__disable 0 - -#define R_MMU_ENABLE (IO_TYPECAST_BYTE 0xb0000243) -#define R_MMU_ENABLE__mmu_enable__BITNR 7 -#define R_MMU_ENABLE__mmu_enable__WIDTH 1 -#define R_MMU_ENABLE__mmu_enable__enable 1 -#define R_MMU_ENABLE__mmu_enable__disable 0 - -#define R_MMU_KBASE_LO (IO_TYPECAST_UDWORD 0xb0000244) -#define R_MMU_KBASE_LO__base_7__BITNR 28 -#define R_MMU_KBASE_LO__base_7__WIDTH 4 -#define R_MMU_KBASE_LO__base_6__BITNR 24 -#define R_MMU_KBASE_LO__base_6__WIDTH 4 -#define R_MMU_KBASE_LO__base_5__BITNR 20 -#define R_MMU_KBASE_LO__base_5__WIDTH 4 -#define R_MMU_KBASE_LO__base_4__BITNR 16 -#define R_MMU_KBASE_LO__base_4__WIDTH 4 -#define R_MMU_KBASE_LO__base_3__BITNR 12 -#define R_MMU_KBASE_LO__base_3__WIDTH 4 -#define R_MMU_KBASE_LO__base_2__BITNR 8 -#define R_MMU_KBASE_LO__base_2__WIDTH 4 -#define R_MMU_KBASE_LO__base_1__BITNR 4 -#define R_MMU_KBASE_LO__base_1__WIDTH 4 -#define R_MMU_KBASE_LO__base_0__BITNR 0 -#define R_MMU_KBASE_LO__base_0__WIDTH 4 - -#define R_MMU_KBASE_HI (IO_TYPECAST_UDWORD 0xb0000248) -#define R_MMU_KBASE_HI__base_f__BITNR 28 -#define R_MMU_KBASE_HI__base_f__WIDTH 4 -#define R_MMU_KBASE_HI__base_e__BITNR 24 -#define R_MMU_KBASE_HI__base_e__WIDTH 4 -#define R_MMU_KBASE_HI__base_d__BITNR 20 -#define R_MMU_KBASE_HI__base_d__WIDTH 4 -#define R_MMU_KBASE_HI__base_c__BITNR 16 -#define R_MMU_KBASE_HI__base_c__WIDTH 4 -#define R_MMU_KBASE_HI__base_b__BITNR 12 -#define R_MMU_KBASE_HI__base_b__WIDTH 4 -#define R_MMU_KBASE_HI__base_a__BITNR 8 -#define R_MMU_KBASE_HI__base_a__WIDTH 4 -#define R_MMU_KBASE_HI__base_9__BITNR 4 -#define R_MMU_KBASE_HI__base_9__WIDTH 4 -#define R_MMU_KBASE_HI__base_8__BITNR 0 -#define R_MMU_KBASE_HI__base_8__WIDTH 4 - -#define R_MMU_CONTEXT (IO_TYPECAST_BYTE 0xb000024c) -#define R_MMU_CONTEXT__page_id__BITNR 0 -#define R_MMU_CONTEXT__page_id__WIDTH 6 - -#define R_MMU_CAUSE (IO_TYPECAST_RO_UDWORD 0xb0000250) -#define R_MMU_CAUSE__vpn__BITNR 13 -#define R_MMU_CAUSE__vpn__WIDTH 19 -#define R_MMU_CAUSE__miss_excp__BITNR 12 -#define R_MMU_CAUSE__miss_excp__WIDTH 1 -#define R_MMU_CAUSE__miss_excp__yes 1 -#define R_MMU_CAUSE__miss_excp__no 0 -#define R_MMU_CAUSE__inv_excp__BITNR 11 -#define R_MMU_CAUSE__inv_excp__WIDTH 1 -#define R_MMU_CAUSE__inv_excp__yes 1 -#define R_MMU_CAUSE__inv_excp__no 0 -#define R_MMU_CAUSE__acc_excp__BITNR 10 -#define R_MMU_CAUSE__acc_excp__WIDTH 1 -#define R_MMU_CAUSE__acc_excp__yes 1 -#define R_MMU_CAUSE__acc_excp__no 0 -#define R_MMU_CAUSE__we_excp__BITNR 9 -#define R_MMU_CAUSE__we_excp__WIDTH 1 -#define R_MMU_CAUSE__we_excp__yes 1 -#define R_MMU_CAUSE__we_excp__no 0 -#define R_MMU_CAUSE__wr_rd__BITNR 8 -#define R_MMU_CAUSE__wr_rd__WIDTH 1 -#define R_MMU_CAUSE__wr_rd__write 1 -#define R_MMU_CAUSE__wr_rd__read 0 -#define R_MMU_CAUSE__page_id__BITNR 0 -#define R_MMU_CAUSE__page_id__WIDTH 6 - -#define R_TLB_SELECT (IO_TYPECAST_BYTE 0xb0000254) -#define R_TLB_SELECT__index__BITNR 0 -#define R_TLB_SELECT__index__WIDTH 6 - -#define R_TLB_LO (IO_TYPECAST_UDWORD 0xb0000258) -#define R_TLB_LO__pfn__BITNR 13 -#define R_TLB_LO__pfn__WIDTH 19 -#define R_TLB_LO__global__BITNR 3 -#define R_TLB_LO__global__WIDTH 1 -#define R_TLB_LO__global__yes 1 -#define R_TLB_LO__global__no 0 -#define R_TLB_LO__valid__BITNR 2 -#define R_TLB_LO__valid__WIDTH 1 -#define R_TLB_LO__valid__yes 1 -#define R_TLB_LO__valid__no 0 -#define R_TLB_LO__kernel__BITNR 1 -#define R_TLB_LO__kernel__WIDTH 1 -#define R_TLB_LO__kernel__yes 1 -#define R_TLB_LO__kernel__no 0 -#define R_TLB_LO__we__BITNR 0 -#define R_TLB_LO__we__WIDTH 1 -#define R_TLB_LO__we__yes 1 -#define R_TLB_LO__we__no 0 - -#define R_TLB_HI (IO_TYPECAST_UDWORD 0xb000025c) -#define R_TLB_HI__vpn__BITNR 13 -#define R_TLB_HI__vpn__WIDTH 19 -#define R_TLB_HI__page_id__BITNR 0 -#define R_TLB_HI__page_id__WIDTH 6 - -/* -!* Syncrounous serial port registers -!*/ - -#define R_SYNC_SERIAL1_REC_DATA (IO_TYPECAST_RO_UDWORD 0xb000006c) -#define R_SYNC_SERIAL1_REC_DATA__data_in__BITNR 0 -#define R_SYNC_SERIAL1_REC_DATA__data_in__WIDTH 32 - -#define R_SYNC_SERIAL1_REC_WORD (IO_TYPECAST_RO_UWORD 0xb000006c) -#define R_SYNC_SERIAL1_REC_WORD__data_in__BITNR 0 -#define R_SYNC_SERIAL1_REC_WORD__data_in__WIDTH 16 - -#define R_SYNC_SERIAL1_REC_BYTE (IO_TYPECAST_RO_BYTE 0xb000006c) -#define R_SYNC_SERIAL1_REC_BYTE__data_in__BITNR 0 -#define R_SYNC_SERIAL1_REC_BYTE__data_in__WIDTH 8 - -#define R_SYNC_SERIAL1_STATUS (IO_TYPECAST_RO_UDWORD 0xb0000068) -#define R_SYNC_SERIAL1_STATUS__rec_status__BITNR 15 -#define R_SYNC_SERIAL1_STATUS__rec_status__WIDTH 1 -#define R_SYNC_SERIAL1_STATUS__rec_status__running 0 -#define R_SYNC_SERIAL1_STATUS__rec_status__idle 1 -#define R_SYNC_SERIAL1_STATUS__tr_empty__BITNR 14 -#define R_SYNC_SERIAL1_STATUS__tr_empty__WIDTH 1 -#define R_SYNC_SERIAL1_STATUS__tr_empty__empty 1 -#define R_SYNC_SERIAL1_STATUS__tr_empty__not_empty 0 -#define R_SYNC_SERIAL1_STATUS__tr_ready__BITNR 13 -#define R_SYNC_SERIAL1_STATUS__tr_ready__WIDTH 1 -#define R_SYNC_SERIAL1_STATUS__tr_ready__full 0 -#define R_SYNC_SERIAL1_STATUS__tr_ready__ready 1 -#define R_SYNC_SERIAL1_STATUS__pin_1__BITNR 12 -#define R_SYNC_SERIAL1_STATUS__pin_1__WIDTH 1 -#define R_SYNC_SERIAL1_STATUS__pin_1__low 0 -#define R_SYNC_SERIAL1_STATUS__pin_1__high 1 -#define R_SYNC_SERIAL1_STATUS__pin_0__BITNR 11 -#define R_SYNC_SERIAL1_STATUS__pin_0__WIDTH 1 -#define R_SYNC_SERIAL1_STATUS__pin_0__low 0 -#define R_SYNC_SERIAL1_STATUS__pin_0__high 1 -#define R_SYNC_SERIAL1_STATUS__underflow__BITNR 10 -#define R_SYNC_SERIAL1_STATUS__underflow__WIDTH 1 -#define R_SYNC_SERIAL1_STATUS__underflow__no 0 -#define R_SYNC_SERIAL1_STATUS__underflow__yes 1 -#define R_SYNC_SERIAL1_STATUS__overrun__BITNR 9 -#define R_SYNC_SERIAL1_STATUS__overrun__WIDTH 1 -#define R_SYNC_SERIAL1_STATUS__overrun__no 0 -#define R_SYNC_SERIAL1_STATUS__overrun__yes 1 -#define R_SYNC_SERIAL1_STATUS__data_avail__BITNR 8 -#define R_SYNC_SERIAL1_STATUS__data_avail__WIDTH 1 -#define R_SYNC_SERIAL1_STATUS__data_avail__no 0 -#define R_SYNC_SERIAL1_STATUS__data_avail__yes 1 -#define R_SYNC_SERIAL1_STATUS__data__BITNR 0 -#define R_SYNC_SERIAL1_STATUS__data__WIDTH 8 - -#define R_SYNC_SERIAL1_TR_DATA (IO_TYPECAST_UDWORD 0xb000006c) -#define R_SYNC_SERIAL1_TR_DATA__data_out__BITNR 0 -#define R_SYNC_SERIAL1_TR_DATA__data_out__WIDTH 32 - -#define R_SYNC_SERIAL1_TR_WORD (IO_TYPECAST_UWORD 0xb000006c) -#define R_SYNC_SERIAL1_TR_WORD__data_out__BITNR 0 -#define R_SYNC_SERIAL1_TR_WORD__data_out__WIDTH 16 - -#define R_SYNC_SERIAL1_TR_BYTE (IO_TYPECAST_BYTE 0xb000006c) -#define R_SYNC_SERIAL1_TR_BYTE__data_out__BITNR 0 -#define R_SYNC_SERIAL1_TR_BYTE__data_out__WIDTH 8 - -#define R_SYNC_SERIAL1_CTRL (IO_TYPECAST_UDWORD 0xb0000068) -#define R_SYNC_SERIAL1_CTRL__tr_baud__BITNR 28 -#define R_SYNC_SERIAL1_CTRL__tr_baud__WIDTH 4 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c150Hz 0 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c300Hz 1 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c600Hz 2 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c1200Hz 3 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c2400Hz 4 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c4800Hz 5 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c9600Hz 6 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c19k2Hz 7 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c28k8Hz 8 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c57k6Hz 9 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c115k2Hz 10 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c230k4Hz 11 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c460k8Hz 12 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c921k6Hz 13 -#define R_SYNC_SERIAL1_CTRL__tr_baud__c3125kHz 14 -#define R_SYNC_SERIAL1_CTRL__tr_baud__reserved 15 -#define R_SYNC_SERIAL1_CTRL__dma_enable__BITNR 27 -#define R_SYNC_SERIAL1_CTRL__dma_enable__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__dma_enable__on 1 -#define R_SYNC_SERIAL1_CTRL__dma_enable__off 0 -#define R_SYNC_SERIAL1_CTRL__mode__BITNR 24 -#define R_SYNC_SERIAL1_CTRL__mode__WIDTH 3 -#define R_SYNC_SERIAL1_CTRL__mode__master_output 0 -#define R_SYNC_SERIAL1_CTRL__mode__slave_output 1 -#define R_SYNC_SERIAL1_CTRL__mode__master_input 2 -#define R_SYNC_SERIAL1_CTRL__mode__slave_input 3 -#define R_SYNC_SERIAL1_CTRL__mode__master_bidir 4 -#define R_SYNC_SERIAL1_CTRL__mode__slave_bidir 5 -#define R_SYNC_SERIAL1_CTRL__error__BITNR 23 -#define R_SYNC_SERIAL1_CTRL__error__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__error__normal 0 -#define R_SYNC_SERIAL1_CTRL__error__ignore 1 -#define R_SYNC_SERIAL1_CTRL__rec_enable__BITNR 22 -#define R_SYNC_SERIAL1_CTRL__rec_enable__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__rec_enable__disable 0 -#define R_SYNC_SERIAL1_CTRL__rec_enable__enable 1 -#define R_SYNC_SERIAL1_CTRL__f_synctype__BITNR 21 -#define R_SYNC_SERIAL1_CTRL__f_synctype__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__f_synctype__normal 0 -#define R_SYNC_SERIAL1_CTRL__f_synctype__early 1 -#define R_SYNC_SERIAL1_CTRL__f_syncsize__BITNR 19 -#define R_SYNC_SERIAL1_CTRL__f_syncsize__WIDTH 2 -#define R_SYNC_SERIAL1_CTRL__f_syncsize__bit 0 -#define R_SYNC_SERIAL1_CTRL__f_syncsize__word 1 -#define R_SYNC_SERIAL1_CTRL__f_syncsize__extended 2 -#define R_SYNC_SERIAL1_CTRL__f_syncsize__reserved 3 -#define R_SYNC_SERIAL1_CTRL__f_sync__BITNR 18 -#define R_SYNC_SERIAL1_CTRL__f_sync__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__f_sync__on 0 -#define R_SYNC_SERIAL1_CTRL__f_sync__off 1 -#define R_SYNC_SERIAL1_CTRL__clk_mode__BITNR 17 -#define R_SYNC_SERIAL1_CTRL__clk_mode__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__clk_mode__normal 0 -#define R_SYNC_SERIAL1_CTRL__clk_mode__gated 1 -#define R_SYNC_SERIAL1_CTRL__clk_halt__BITNR 16 -#define R_SYNC_SERIAL1_CTRL__clk_halt__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__clk_halt__running 0 -#define R_SYNC_SERIAL1_CTRL__clk_halt__stopped 1 -#define R_SYNC_SERIAL1_CTRL__bitorder__BITNR 15 -#define R_SYNC_SERIAL1_CTRL__bitorder__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__bitorder__lsb 0 -#define R_SYNC_SERIAL1_CTRL__bitorder__msb 1 -#define R_SYNC_SERIAL1_CTRL__tr_enable__BITNR 14 -#define R_SYNC_SERIAL1_CTRL__tr_enable__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__tr_enable__disable 0 -#define R_SYNC_SERIAL1_CTRL__tr_enable__enable 1 -#define R_SYNC_SERIAL1_CTRL__wordsize__BITNR 11 -#define R_SYNC_SERIAL1_CTRL__wordsize__WIDTH 3 -#define R_SYNC_SERIAL1_CTRL__wordsize__size8bit 0 -#define R_SYNC_SERIAL1_CTRL__wordsize__size12bit 1 -#define R_SYNC_SERIAL1_CTRL__wordsize__size16bit 2 -#define R_SYNC_SERIAL1_CTRL__wordsize__size24bit 3 -#define R_SYNC_SERIAL1_CTRL__wordsize__size32bit 4 -#define R_SYNC_SERIAL1_CTRL__buf_empty__BITNR 10 -#define R_SYNC_SERIAL1_CTRL__buf_empty__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__buf_empty__lmt_8 0 -#define R_SYNC_SERIAL1_CTRL__buf_empty__lmt_0 1 -#define R_SYNC_SERIAL1_CTRL__buf_full__BITNR 9 -#define R_SYNC_SERIAL1_CTRL__buf_full__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__buf_full__lmt_32 0 -#define R_SYNC_SERIAL1_CTRL__buf_full__lmt_8 1 -#define R_SYNC_SERIAL1_CTRL__flow_ctrl__BITNR 8 -#define R_SYNC_SERIAL1_CTRL__flow_ctrl__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__flow_ctrl__disabled 0 -#define R_SYNC_SERIAL1_CTRL__flow_ctrl__enabled 1 -#define R_SYNC_SERIAL1_CTRL__clk_polarity__BITNR 6 -#define R_SYNC_SERIAL1_CTRL__clk_polarity__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__clk_polarity__pos 0 -#define R_SYNC_SERIAL1_CTRL__clk_polarity__neg 1 -#define R_SYNC_SERIAL1_CTRL__frame_polarity__BITNR 5 -#define R_SYNC_SERIAL1_CTRL__frame_polarity__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__frame_polarity__normal 0 -#define R_SYNC_SERIAL1_CTRL__frame_polarity__inverted 1 -#define R_SYNC_SERIAL1_CTRL__status_polarity__BITNR 4 -#define R_SYNC_SERIAL1_CTRL__status_polarity__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__status_polarity__normal 0 -#define R_SYNC_SERIAL1_CTRL__status_polarity__inverted 1 -#define R_SYNC_SERIAL1_CTRL__clk_driver__BITNR 3 -#define R_SYNC_SERIAL1_CTRL__clk_driver__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__clk_driver__normal 0 -#define R_SYNC_SERIAL1_CTRL__clk_driver__inverted 1 -#define R_SYNC_SERIAL1_CTRL__frame_driver__BITNR 2 -#define R_SYNC_SERIAL1_CTRL__frame_driver__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__frame_driver__normal 0 -#define R_SYNC_SERIAL1_CTRL__frame_driver__inverted 1 -#define R_SYNC_SERIAL1_CTRL__status_driver__BITNR 1 -#define R_SYNC_SERIAL1_CTRL__status_driver__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__status_driver__normal 0 -#define R_SYNC_SERIAL1_CTRL__status_driver__inverted 1 -#define R_SYNC_SERIAL1_CTRL__def_out0__BITNR 0 -#define R_SYNC_SERIAL1_CTRL__def_out0__WIDTH 1 -#define R_SYNC_SERIAL1_CTRL__def_out0__high 1 -#define R_SYNC_SERIAL1_CTRL__def_out0__low 0 - -#define R_SYNC_SERIAL3_REC_DATA (IO_TYPECAST_RO_UDWORD 0xb000007c) -#define R_SYNC_SERIAL3_REC_DATA__data_in__BITNR 0 -#define R_SYNC_SERIAL3_REC_DATA__data_in__WIDTH 32 - -#define R_SYNC_SERIAL3_REC_WORD (IO_TYPECAST_RO_UWORD 0xb000007c) -#define R_SYNC_SERIAL3_REC_WORD__data_in__BITNR 0 -#define R_SYNC_SERIAL3_REC_WORD__data_in__WIDTH 16 - -#define R_SYNC_SERIAL3_REC_BYTE (IO_TYPECAST_RO_BYTE 0xb000007c) -#define R_SYNC_SERIAL3_REC_BYTE__data_in__BITNR 0 -#define R_SYNC_SERIAL3_REC_BYTE__data_in__WIDTH 8 - -#define R_SYNC_SERIAL3_STATUS (IO_TYPECAST_RO_UDWORD 0xb0000078) -#define R_SYNC_SERIAL3_STATUS__rec_status__BITNR 15 -#define R_SYNC_SERIAL3_STATUS__rec_status__WIDTH 1 -#define R_SYNC_SERIAL3_STATUS__rec_status__running 0 -#define R_SYNC_SERIAL3_STATUS__rec_status__idle 1 -#define R_SYNC_SERIAL3_STATUS__tr_empty__BITNR 14 -#define R_SYNC_SERIAL3_STATUS__tr_empty__WIDTH 1 -#define R_SYNC_SERIAL3_STATUS__tr_empty__empty 1 -#define R_SYNC_SERIAL3_STATUS__tr_empty__not_empty 0 -#define R_SYNC_SERIAL3_STATUS__tr_ready__BITNR 13 -#define R_SYNC_SERIAL3_STATUS__tr_ready__WIDTH 1 -#define R_SYNC_SERIAL3_STATUS__tr_ready__full 0 -#define R_SYNC_SERIAL3_STATUS__tr_ready__ready 1 -#define R_SYNC_SERIAL3_STATUS__pin_1__BITNR 12 -#define R_SYNC_SERIAL3_STATUS__pin_1__WIDTH 1 -#define R_SYNC_SERIAL3_STATUS__pin_1__low 0 -#define R_SYNC_SERIAL3_STATUS__pin_1__high 1 -#define R_SYNC_SERIAL3_STATUS__pin_0__BITNR 11 -#define R_SYNC_SERIAL3_STATUS__pin_0__WIDTH 1 -#define R_SYNC_SERIAL3_STATUS__pin_0__low 0 -#define R_SYNC_SERIAL3_STATUS__pin_0__high 1 -#define R_SYNC_SERIAL3_STATUS__underflow__BITNR 10 -#define R_SYNC_SERIAL3_STATUS__underflow__WIDTH 1 -#define R_SYNC_SERIAL3_STATUS__underflow__no 0 -#define R_SYNC_SERIAL3_STATUS__underflow__yes 1 -#define R_SYNC_SERIAL3_STATUS__overrun__BITNR 9 -#define R_SYNC_SERIAL3_STATUS__overrun__WIDTH 1 -#define R_SYNC_SERIAL3_STATUS__overrun__no 0 -#define R_SYNC_SERIAL3_STATUS__overrun__yes 1 -#define R_SYNC_SERIAL3_STATUS__data_avail__BITNR 8 -#define R_SYNC_SERIAL3_STATUS__data_avail__WIDTH 1 -#define R_SYNC_SERIAL3_STATUS__data_avail__no 0 -#define R_SYNC_SERIAL3_STATUS__data_avail__yes 1 -#define R_SYNC_SERIAL3_STATUS__data__BITNR 0 -#define R_SYNC_SERIAL3_STATUS__data__WIDTH 8 - -#define R_SYNC_SERIAL3_TR_DATA (IO_TYPECAST_UDWORD 0xb000007c) -#define R_SYNC_SERIAL3_TR_DATA__data_out__BITNR 0 -#define R_SYNC_SERIAL3_TR_DATA__data_out__WIDTH 32 - -#define R_SYNC_SERIAL3_TR_WORD (IO_TYPECAST_UWORD 0xb000007c) -#define R_SYNC_SERIAL3_TR_WORD__data_out__BITNR 0 -#define R_SYNC_SERIAL3_TR_WORD__data_out__WIDTH 16 - -#define R_SYNC_SERIAL3_TR_BYTE (IO_TYPECAST_BYTE 0xb000007c) -#define R_SYNC_SERIAL3_TR_BYTE__data_out__BITNR 0 -#define R_SYNC_SERIAL3_TR_BYTE__data_out__WIDTH 8 - -#define R_SYNC_SERIAL3_CTRL (IO_TYPECAST_UDWORD 0xb0000078) -#define R_SYNC_SERIAL3_CTRL__tr_baud__BITNR 28 -#define R_SYNC_SERIAL3_CTRL__tr_baud__WIDTH 4 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c150Hz 0 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c300Hz 1 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c600Hz 2 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c1200Hz 3 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c2400Hz 4 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c4800Hz 5 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c9600Hz 6 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c19k2Hz 7 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c28k8Hz 8 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c57k6Hz 9 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c115k2Hz 10 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c230k4Hz 11 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c460k8Hz 12 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c921k6Hz 13 -#define R_SYNC_SERIAL3_CTRL__tr_baud__c3125kHz 14 -#define R_SYNC_SERIAL3_CTRL__tr_baud__reserved 15 -#define R_SYNC_SERIAL3_CTRL__dma_enable__BITNR 27 -#define R_SYNC_SERIAL3_CTRL__dma_enable__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__dma_enable__on 1 -#define R_SYNC_SERIAL3_CTRL__dma_enable__off 0 -#define R_SYNC_SERIAL3_CTRL__mode__BITNR 24 -#define R_SYNC_SERIAL3_CTRL__mode__WIDTH 3 -#define R_SYNC_SERIAL3_CTRL__mode__master_output 0 -#define R_SYNC_SERIAL3_CTRL__mode__slave_output 1 -#define R_SYNC_SERIAL3_CTRL__mode__master_input 2 -#define R_SYNC_SERIAL3_CTRL__mode__slave_input 3 -#define R_SYNC_SERIAL3_CTRL__mode__master_bidir 4 -#define R_SYNC_SERIAL3_CTRL__mode__slave_bidir 5 -#define R_SYNC_SERIAL3_CTRL__error__BITNR 23 -#define R_SYNC_SERIAL3_CTRL__error__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__error__normal 0 -#define R_SYNC_SERIAL3_CTRL__error__ignore 1 -#define R_SYNC_SERIAL3_CTRL__rec_enable__BITNR 22 -#define R_SYNC_SERIAL3_CTRL__rec_enable__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__rec_enable__disable 0 -#define R_SYNC_SERIAL3_CTRL__rec_enable__enable 1 -#define R_SYNC_SERIAL3_CTRL__f_synctype__BITNR 21 -#define R_SYNC_SERIAL3_CTRL__f_synctype__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__f_synctype__normal 0 -#define R_SYNC_SERIAL3_CTRL__f_synctype__early 1 -#define R_SYNC_SERIAL3_CTRL__f_syncsize__BITNR 19 -#define R_SYNC_SERIAL3_CTRL__f_syncsize__WIDTH 2 -#define R_SYNC_SERIAL3_CTRL__f_syncsize__bit 0 -#define R_SYNC_SERIAL3_CTRL__f_syncsize__word 1 -#define R_SYNC_SERIAL3_CTRL__f_syncsize__extended 2 -#define R_SYNC_SERIAL3_CTRL__f_syncsize__reserved 3 -#define R_SYNC_SERIAL3_CTRL__f_sync__BITNR 18 -#define R_SYNC_SERIAL3_CTRL__f_sync__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__f_sync__on 0 -#define R_SYNC_SERIAL3_CTRL__f_sync__off 1 -#define R_SYNC_SERIAL3_CTRL__clk_mode__BITNR 17 -#define R_SYNC_SERIAL3_CTRL__clk_mode__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__clk_mode__normal 0 -#define R_SYNC_SERIAL3_CTRL__clk_mode__gated 1 -#define R_SYNC_SERIAL3_CTRL__clk_halt__BITNR 16 -#define R_SYNC_SERIAL3_CTRL__clk_halt__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__clk_halt__running 0 -#define R_SYNC_SERIAL3_CTRL__clk_halt__stopped 1 -#define R_SYNC_SERIAL3_CTRL__bitorder__BITNR 15 -#define R_SYNC_SERIAL3_CTRL__bitorder__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__bitorder__lsb 0 -#define R_SYNC_SERIAL3_CTRL__bitorder__msb 1 -#define R_SYNC_SERIAL3_CTRL__tr_enable__BITNR 14 -#define R_SYNC_SERIAL3_CTRL__tr_enable__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__tr_enable__disable 0 -#define R_SYNC_SERIAL3_CTRL__tr_enable__enable 1 -#define R_SYNC_SERIAL3_CTRL__wordsize__BITNR 11 -#define R_SYNC_SERIAL3_CTRL__wordsize__WIDTH 3 -#define R_SYNC_SERIAL3_CTRL__wordsize__size8bit 0 -#define R_SYNC_SERIAL3_CTRL__wordsize__size12bit 1 -#define R_SYNC_SERIAL3_CTRL__wordsize__size16bit 2 -#define R_SYNC_SERIAL3_CTRL__wordsize__size24bit 3 -#define R_SYNC_SERIAL3_CTRL__wordsize__size32bit 4 -#define R_SYNC_SERIAL3_CTRL__buf_empty__BITNR 10 -#define R_SYNC_SERIAL3_CTRL__buf_empty__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__buf_empty__lmt_8 0 -#define R_SYNC_SERIAL3_CTRL__buf_empty__lmt_0 1 -#define R_SYNC_SERIAL3_CTRL__buf_full__BITNR 9 -#define R_SYNC_SERIAL3_CTRL__buf_full__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__buf_full__lmt_32 0 -#define R_SYNC_SERIAL3_CTRL__buf_full__lmt_8 1 -#define R_SYNC_SERIAL3_CTRL__flow_ctrl__BITNR 8 -#define R_SYNC_SERIAL3_CTRL__flow_ctrl__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__flow_ctrl__disabled 0 -#define R_SYNC_SERIAL3_CTRL__flow_ctrl__enabled 1 -#define R_SYNC_SERIAL3_CTRL__clk_polarity__BITNR 6 -#define R_SYNC_SERIAL3_CTRL__clk_polarity__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__clk_polarity__pos 0 -#define R_SYNC_SERIAL3_CTRL__clk_polarity__neg 1 -#define R_SYNC_SERIAL3_CTRL__frame_polarity__BITNR 5 -#define R_SYNC_SERIAL3_CTRL__frame_polarity__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__frame_polarity__normal 0 -#define R_SYNC_SERIAL3_CTRL__frame_polarity__inverted 1 -#define R_SYNC_SERIAL3_CTRL__status_polarity__BITNR 4 -#define R_SYNC_SERIAL3_CTRL__status_polarity__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__status_polarity__normal 0 -#define R_SYNC_SERIAL3_CTRL__status_polarity__inverted 1 -#define R_SYNC_SERIAL3_CTRL__clk_driver__BITNR 3 -#define R_SYNC_SERIAL3_CTRL__clk_driver__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__clk_driver__normal 0 -#define R_SYNC_SERIAL3_CTRL__clk_driver__inverted 1 -#define R_SYNC_SERIAL3_CTRL__frame_driver__BITNR 2 -#define R_SYNC_SERIAL3_CTRL__frame_driver__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__frame_driver__normal 0 -#define R_SYNC_SERIAL3_CTRL__frame_driver__inverted 1 -#define R_SYNC_SERIAL3_CTRL__status_driver__BITNR 1 -#define R_SYNC_SERIAL3_CTRL__status_driver__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__status_driver__normal 0 -#define R_SYNC_SERIAL3_CTRL__status_driver__inverted 1 -#define R_SYNC_SERIAL3_CTRL__def_out0__BITNR 0 -#define R_SYNC_SERIAL3_CTRL__def_out0__WIDTH 1 -#define R_SYNC_SERIAL3_CTRL__def_out0__high 1 -#define R_SYNC_SERIAL3_CTRL__def_out0__low 0 - diff --git a/arch/cris/include/arch-v10/arch/sv_addr_ag.h b/arch/cris/include/arch-v10/arch/sv_addr_ag.h deleted file mode 100644 index 5517f04..0000000 --- a/arch/cris/include/arch-v10/arch/sv_addr_ag.h +++ /dev/null @@ -1,139 +0,0 @@ -/*!************************************************************************** -*! -*! MACROS: -*! IO_MASK(reg,field) -*! IO_STATE(reg,field,state) -*! IO_EXTRACT(reg,field,val) -*! IO_STATE_VALUE(reg,field,state) -*! IO_BITNR(reg,field) -*! IO_WIDTH(reg,field) -*! IO_FIELD(reg,field,val) -*! IO_RD(reg) -*! All moderegister addresses and fields of these. -*! -*!**************************************************************************/ - -#ifndef __sv_addr_ag_h__ -#define __sv_addr_ag_h__ - - -#define __test_sv_addr__ 0 - -/*------------------------------------------------------------ -!* General macros to manipulate moderegisters. -!*-----------------------------------------------------------*/ - -/* IO_MASK returns a mask for a specified bitfield in a register. - Note that this macro doesn't work when field width is 32 bits. */ -#define IO_MASK(reg, field) IO_MASK_ (reg##_, field##_) -#define IO_MASK_(reg_, field_) \ - ( ( ( 1 << reg_##_##field_##_WIDTH ) - 1 ) << reg_##_##field_##_BITNR ) - -/* IO_STATE returns a constant corresponding to a one of the symbolic - states that the bitfield can have. (Shifted to correct position) */ -#define IO_STATE(reg, field, state) IO_STATE_ (reg##_, field##_, _##state) -#define IO_STATE_(reg_, field_, _state) \ - ( reg_##_##field_##_state << reg_##_##field_##_BITNR ) - -/* IO_EXTRACT returns the masked and shifted value corresponding to the - bitfield can have. */ -#define IO_EXTRACT(reg, field, val) IO_EXTRACT_ (reg##_, field##_, val) -#define IO_EXTRACT_(reg_, field_, val) ( (( ( ( 1 << reg_##_##field_##_WIDTH ) \ - - 1 ) << reg_##_##field_##_BITNR ) & (val)) >> reg_##_##field_##_BITNR ) - -/* IO_STATE_VALUE returns a constant corresponding to a one of the symbolic - states that the bitfield can have. (Not shifted) */ -#define IO_STATE_VALUE(reg, field, state) \ - IO_STATE_VALUE_ (reg##_, field##_, _##state) -#define IO_STATE_VALUE_(reg_, field_, _state) ( reg_##_##field_##_state ) - -/* IO_FIELD shifts the val parameter to be aligned with the bitfield - specified. */ -#define IO_FIELD(reg, field, val) IO_FIELD_ (reg##_, field##_, val) -#define IO_FIELD_(reg_, field_, val) ((val) << reg_##_##field_##_BITNR) - -/* IO_BITNR returns the starting bitnumber of a bitfield. Bit 0 is - LSB and the returned bitnumber is LSB of the field. */ -#define IO_BITNR(reg, field) IO_BITNR_ (reg##_, field##_) -#define IO_BITNR_(reg_, field_) (reg_##_##field_##_BITNR) - -/* IO_WIDTH returns the width, in bits, of a bitfield. */ -#define IO_WIDTH(reg, field) IO_WIDTH_ (reg##_, field##_) -#define IO_WIDTH_(reg_, field_) (reg_##_##field_##_WIDTH) - -/*--- Obsolete. Kept for backw compatibility. ---*/ -/* Reads (or writes) a byte/uword/udword from the specified mode - register. */ -#define IO_RD(reg) (*(volatile u32*)(reg)) -#define IO_RD_B(reg) (*(volatile u8*)(reg)) -#define IO_RD_W(reg) (*(volatile u16*)(reg)) -#define IO_RD_D(reg) (*(volatile u32*)(reg)) - -/*------------------------------------------------------------ -!* Start addresses of the different memory areas. -!*-----------------------------------------------------------*/ - -#define MEM_CSE0_START (0x00000000) -#define MEM_CSE0_SIZE (0x04000000) -#define MEM_CSE1_START (0x04000000) -#define MEM_CSE1_SIZE (0x04000000) -#define MEM_CSR0_START (0x08000000) -#define MEM_CSR1_START (0x0c000000) -#define MEM_CSP0_START (0x10000000) -#define MEM_CSP1_START (0x14000000) -#define MEM_CSP2_START (0x18000000) -#define MEM_CSP3_START (0x1c000000) -#define MEM_CSP4_START (0x20000000) -#define MEM_CSP5_START (0x24000000) -#define MEM_CSP6_START (0x28000000) -#define MEM_CSP7_START (0x2c000000) -#define MEM_DRAM_START (0x40000000) - -#define MEM_NON_CACHEABLE (0x80000000) - -/*------------------------------------------------------------ -!* Type casts used in mode register macros, making pointer -!* dereferencing possible. Empty in assembler. -!*-----------------------------------------------------------*/ - -#ifndef __ASSEMBLER__ -# define IO_TYPECAST_UDWORD (volatile u32*) -# define IO_TYPECAST_RO_UDWORD (const volatile u32*) -# define IO_TYPECAST_UWORD (volatile u16*) -# define IO_TYPECAST_RO_UWORD (const volatile u16*) -# define IO_TYPECAST_BYTE (volatile u8*) -# define IO_TYPECAST_RO_BYTE (const volatile u8*) -#else -# define IO_TYPECAST_UDWORD -# define IO_TYPECAST_RO_UDWORD -# define IO_TYPECAST_UWORD -# define IO_TYPECAST_RO_UWORD -# define IO_TYPECAST_BYTE -# define IO_TYPECAST_RO_BYTE -#endif - -/*------------------------------------------------------------*/ - -#include - -#if __test_sv_addr__ -/* IO_MASK( R_BUS_CONFIG , CE ) */ -IO_MASK( R_WAITSTATES , SRAM_WS ) -IO_MASK( R_TEST , W32 ) - -IO_STATE( R_BUS_CONFIG, CE, DISABLE ) -IO_STATE( R_BUS_CONFIG, CE, ENABLE ) - -IO_STATE( R_DRAM_TIMING, REF, IVAL2 ) - -IO_MASK( R_DRAM_TIMING, REF ) - -IO_MASK( R_EXT_DMA_0_STAT, TFR_COUNT ) >> IO_BITNR( R_EXT_DMA_0_STAT, TFR_COUNT ) - -IO_RD(R_EXT_DMA_0_STAT) & IO_MASK( R_EXT_DMA_0_STAT, S ) - == IO_STATE( R_EXT_DMA_0_STAT, S, STARTED ) -#endif - - -#endif /* ifndef __sv_addr_ag_h__ */ - diff --git a/arch/cris/include/arch-v10/arch/svinto.h b/arch/cris/include/arch-v10/arch/svinto.h deleted file mode 100644 index da5c152..0000000 --- a/arch/cris/include/arch-v10/arch/svinto.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef _ASM_CRIS_SVINTO_H -#define _ASM_CRIS_SVINTO_H - -#include - -extern unsigned int genconfig_shadow; /* defined and set in head.S */ - -/* dma stuff */ - -enum { /* Available in: */ - d_eol = (1 << 0), /* flags */ - d_eop = (1 << 1), /* flags & status */ - d_wait = (1 << 2), /* flags */ - d_int = (1 << 3), /* flags */ - d_txerr = (1 << 4), /* flags */ - d_stop = (1 << 4), /* status */ - d_ecp = (1 << 4), /* flags & status */ - d_pri = (1 << 5), /* flags & status */ - d_alignerr = (1 << 6), /* status */ - d_crcerr = (1 << 7) /* status */ -}; - -/* Do remember that DMA does not go through the MMU and needs - * a real physical address, not an address virtually mapped or - * paged. Therefore the buf/next ptrs below are unsigned long instead - * of void * to give a warning if you try to put a pointer directly - * to them instead of going through virt_to_phys/phys_to_virt. - */ - -typedef struct etrax_dma_descr { - unsigned short sw_len; /* 0-1 */ - unsigned short ctrl; /* 2-3 */ - unsigned long next; /* 4-7 */ - unsigned long buf; /* 8-11 */ - unsigned short hw_len; /* 12-13 */ - unsigned char status; /* 14 */ - unsigned char fifo_len; /* 15 */ -} etrax_dma_descr; - - -/* Use this for constant numbers only */ -#define RESET_DMA_NUM( n ) \ - *R_DMA_CH##n##_CMD = IO_STATE( R_DMA_CH0_CMD, cmd, reset ) - -/* Use this for constant numbers or symbols, - * having two macros makes it possible to use constant expressions. - */ -#define RESET_DMA( n ) RESET_DMA_NUM( n ) - - -/* Use this for constant numbers only */ -#define WAIT_DMA_NUM( n ) \ - while( (*R_DMA_CH##n##_CMD & IO_MASK( R_DMA_CH0_CMD, cmd )) != \ - IO_STATE( R_DMA_CH0_CMD, cmd, hold ) ) - -/* Use this for constant numbers or symbols - * having two macros makes it possible to use constant expressions. - */ -#define WAIT_DMA( n ) WAIT_DMA_NUM( n ) - -extern void prepare_rx_descriptor(struct etrax_dma_descr *desc); -extern void flush_etrax_cache(void); - -#endif diff --git a/arch/cris/include/arch-v10/arch/user.h b/arch/cris/include/arch-v10/arch/user.h deleted file mode 100644 index 9303ea7..0000000 --- a/arch/cris/include/arch-v10/arch/user.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __ASM_CRIS_ARCH_USER_H -#define __ASM_CRIS_ARCH_USER_H - -/* User mode registers, used for core dumps. In order to keep ELF_NGREG - sensible we let all registers be 32 bits. The csr registers are included - for future use. */ -struct user_regs_struct { - unsigned long r0; /* General registers. */ - unsigned long r1; - unsigned long r2; - unsigned long r3; - unsigned long r4; - unsigned long r5; - unsigned long r6; - unsigned long r7; - unsigned long r8; - unsigned long r9; - unsigned long r10; - unsigned long r11; - unsigned long r12; - unsigned long r13; - unsigned long sp; /* Stack pointer. */ - unsigned long pc; /* Program counter. */ - unsigned long p0; /* Constant zero (only 8 bits). */ - unsigned long vr; /* Version register (only 8 bits). */ - unsigned long p2; /* Reserved. */ - unsigned long p3; /* Reserved. */ - unsigned long p4; /* Constant zero (only 16 bits). */ - unsigned long ccr; /* Condition code register (only 16 bits). */ - unsigned long p6; /* Reserved. */ - unsigned long mof; /* Multiply overflow register. */ - unsigned long p8; /* Constant zero. */ - unsigned long ibr; /* Not accessible. */ - unsigned long irp; /* Not accessible. */ - unsigned long srp; /* Subroutine return pointer. */ - unsigned long bar; /* Not accessible. */ - unsigned long dccr; /* Dword condition code register. */ - unsigned long brp; /* Not accessible. */ - unsigned long usp; /* User-mode stack pointer. Same as sp when - in user mode. */ - unsigned long csrinstr; /* Internal status registers. */ - unsigned long csraddr; - unsigned long csrdata; -}; - -#endif diff --git a/arch/cris/include/uapi/arch-v10/arch/Kbuild b/arch/cris/include/uapi/arch-v10/arch/Kbuild index aafaa5a..9048c87 100644 --- a/arch/cris/include/uapi/arch-v10/arch/Kbuild +++ b/arch/cris/include/uapi/arch-v10/arch/Kbuild @@ -1 +1,5 @@ # UAPI Header export list +header-y += sv_addr.agh +header-y += sv_addr_ag.h +header-y += svinto.h +header-y += user.h diff --git a/arch/cris/include/uapi/arch-v10/arch/sv_addr.agh b/arch/cris/include/uapi/arch-v10/arch/sv_addr.agh new file mode 100644 index 0000000..6ac3a7b --- /dev/null +++ b/arch/cris/include/uapi/arch-v10/arch/sv_addr.agh @@ -0,0 +1,7306 @@ +/* +!* This file was automatically generated by /n/asic/bin/reg_macro_gen +!* from the file `/n/asic/projects/etrax_ng/doc/work/etrax_ng_regs.rd'. +!* Editing within this file is thus not recommended, +!* make the changes in `/n/asic/projects/etrax_ng/doc/work/etrax_ng_regs.rd' instead. +!*/ + + +/* +!* Bus interface configuration registers +!*/ + +#define R_WAITSTATES (IO_TYPECAST_UDWORD 0xb0000000) +#define R_WAITSTATES__pcs4_7_zw__BITNR 30 +#define R_WAITSTATES__pcs4_7_zw__WIDTH 2 +#define R_WAITSTATES__pcs4_7_ew__BITNR 28 +#define R_WAITSTATES__pcs4_7_ew__WIDTH 2 +#define R_WAITSTATES__pcs4_7_lw__BITNR 24 +#define R_WAITSTATES__pcs4_7_lw__WIDTH 4 +#define R_WAITSTATES__pcs0_3_zw__BITNR 22 +#define R_WAITSTATES__pcs0_3_zw__WIDTH 2 +#define R_WAITSTATES__pcs0_3_ew__BITNR 20 +#define R_WAITSTATES__pcs0_3_ew__WIDTH 2 +#define R_WAITSTATES__pcs0_3_lw__BITNR 16 +#define R_WAITSTATES__pcs0_3_lw__WIDTH 4 +#define R_WAITSTATES__sram_zw__BITNR 14 +#define R_WAITSTATES__sram_zw__WIDTH 2 +#define R_WAITSTATES__sram_ew__BITNR 12 +#define R_WAITSTATES__sram_ew__WIDTH 2 +#define R_WAITSTATES__sram_lw__BITNR 8 +#define R_WAITSTATES__sram_lw__WIDTH 4 +#define R_WAITSTATES__flash_zw__BITNR 6 +#define R_WAITSTATES__flash_zw__WIDTH 2 +#define R_WAITSTATES__flash_ew__BITNR 4 +#define R_WAITSTATES__flash_ew__WIDTH 2 +#define R_WAITSTATES__flash_lw__BITNR 0 +#define R_WAITSTATES__flash_lw__WIDTH 4 + +#define R_BUS_CONFIG (IO_TYPECAST_UDWORD 0xb0000004) +#define R_BUS_CONFIG__sram_type__BITNR 9 +#define R_BUS_CONFIG__sram_type__WIDTH 1 +#define R_BUS_CONFIG__sram_type__cwe 1 +#define R_BUS_CONFIG__sram_type__bwe 0 +#define R_BUS_CONFIG__dma_burst__BITNR 8 +#define R_BUS_CONFIG__dma_burst__WIDTH 1 +#define R_BUS_CONFIG__dma_burst__burst16 1 +#define R_BUS_CONFIG__dma_burst__burst32 0 +#define R_BUS_CONFIG__pcs4_7_wr__BITNR 7 +#define R_BUS_CONFIG__pcs4_7_wr__WIDTH 1 +#define R_BUS_CONFIG__pcs4_7_wr__ext 1 +#define R_BUS_CONFIG__pcs4_7_wr__norm 0 +#define R_BUS_CONFIG__pcs0_3_wr__BITNR 6 +#define R_BUS_CONFIG__pcs0_3_wr__WIDTH 1 +#define R_BUS_CONFIG__pcs0_3_wr__ext 1 +#define R_BUS_CONFIG__pcs0_3_wr__norm 0 +#define R_BUS_CONFIG__sram_wr__BITNR 5 +#define R_BUS_CONFIG__sram_wr__WIDTH 1 +#define R_BUS_CONFIG__sram_wr__ext 1 +#define R_BUS_CONFIG__sram_wr__norm 0 +#define R_BUS_CONFIG__flash_wr__BITNR 4 +#define R_BUS_CONFIG__flash_wr__WIDTH 1 +#define R_BUS_CONFIG__flash_wr__ext 1 +#define R_BUS_CONFIG__flash_wr__norm 0 +#define R_BUS_CONFIG__pcs4_7_bw__BITNR 3 +#define R_BUS_CONFIG__pcs4_7_bw__WIDTH 1 +#define R_BUS_CONFIG__pcs4_7_bw__bw32 1 +#define R_BUS_CONFIG__pcs4_7_bw__bw16 0 +#define R_BUS_CONFIG__pcs0_3_bw__BITNR 2 +#define R_BUS_CONFIG__pcs0_3_bw__WIDTH 1 +#define R_BUS_CONFIG__pcs0_3_bw__bw32 1 +#define R_BUS_CONFIG__pcs0_3_bw__bw16 0 +#define R_BUS_CONFIG__sram_bw__BITNR 1 +#define R_BUS_CONFIG__sram_bw__WIDTH 1 +#define R_BUS_CONFIG__sram_bw__bw32 1 +#define R_BUS_CONFIG__sram_bw__bw16 0 +#define R_BUS_CONFIG__flash_bw__BITNR 0 +#define R_BUS_CONFIG__flash_bw__WIDTH 1 +#define R_BUS_CONFIG__flash_bw__bw32 1 +#define R_BUS_CONFIG__flash_bw__bw16 0 + +#define R_BUS_STATUS (IO_TYPECAST_RO_UDWORD 0xb0000004) +#define R_BUS_STATUS__pll_lock_tm__BITNR 5 +#define R_BUS_STATUS__pll_lock_tm__WIDTH 1 +#define R_BUS_STATUS__pll_lock_tm__expired 0 +#define R_BUS_STATUS__pll_lock_tm__counting 1 +#define R_BUS_STATUS__both_faults__BITNR 4 +#define R_BUS_STATUS__both_faults__WIDTH 1 +#define R_BUS_STATUS__both_faults__no 0 +#define R_BUS_STATUS__both_faults__yes 1 +#define R_BUS_STATUS__bsen___BITNR 3 +#define R_BUS_STATUS__bsen___WIDTH 1 +#define R_BUS_STATUS__bsen___enable 0 +#define R_BUS_STATUS__bsen___disable 1 +#define R_BUS_STATUS__boot__BITNR 1 +#define R_BUS_STATUS__boot__WIDTH 2 +#define R_BUS_STATUS__boot__uncached 0 +#define R_BUS_STATUS__boot__serial 1 +#define R_BUS_STATUS__boot__network 2 +#define R_BUS_STATUS__boot__parallel 3 +#define R_BUS_STATUS__flashw__BITNR 0 +#define R_BUS_STATUS__flashw__WIDTH 1 +#define R_BUS_STATUS__flashw__bw32 1 +#define R_BUS_STATUS__flashw__bw16 0 + +#define R_DRAM_TIMING (IO_TYPECAST_UDWORD 0xb0000008) +#define R_DRAM_TIMING__sdram__BITNR 31 +#define R_DRAM_TIMING__sdram__WIDTH 1 +#define R_DRAM_TIMING__sdram__enable 1 +#define R_DRAM_TIMING__sdram__disable 0 +#define R_DRAM_TIMING__ref__BITNR 14 +#define R_DRAM_TIMING__ref__WIDTH 2 +#define R_DRAM_TIMING__ref__e52us 0 +#define R_DRAM_TIMING__ref__e13us 1 +#define R_DRAM_TIMING__ref__e8700ns 2 +#define R_DRAM_TIMING__ref__disable 3 +#define R_DRAM_TIMING__rp__BITNR 12 +#define R_DRAM_TIMING__rp__WIDTH 2 +#define R_DRAM_TIMING__rs__BITNR 10 +#define R_DRAM_TIMING__rs__WIDTH 2 +#define R_DRAM_TIMING__rh__BITNR 8 +#define R_DRAM_TIMING__rh__WIDTH 2 +#define R_DRAM_TIMING__w__BITNR 7 +#define R_DRAM_TIMING__w__WIDTH 1 +#define R_DRAM_TIMING__w__norm 0 +#define R_DRAM_TIMING__w__ext 1 +#define R_DRAM_TIMING__c__BITNR 6 +#define R_DRAM_TIMING__c__WIDTH 1 +#define R_DRAM_TIMING__c__norm 0 +#define R_DRAM_TIMING__c__ext 1 +#define R_DRAM_TIMING__cz__BITNR 4 +#define R_DRAM_TIMING__cz__WIDTH 2 +#define R_DRAM_TIMING__cp__BITNR 2 +#define R_DRAM_TIMING__cp__WIDTH 2 +#define R_DRAM_TIMING__cw__BITNR 0 +#define R_DRAM_TIMING__cw__WIDTH 2 + +#define R_SDRAM_TIMING (IO_TYPECAST_UDWORD 0xb0000008) +#define R_SDRAM_TIMING__sdram__BITNR 31 +#define R_SDRAM_TIMING__sdram__WIDTH 1 +#define R_SDRAM_TIMING__sdram__enable 1 +#define R_SDRAM_TIMING__sdram__disable 0 +#define R_SDRAM_TIMING__mrs_data__BITNR 16 +#define R_SDRAM_TIMING__mrs_data__WIDTH 15 +#define R_SDRAM_TIMING__ref__BITNR 14 +#define R_SDRAM_TIMING__ref__WIDTH 2 +#define R_SDRAM_TIMING__ref__e52us 0 +#define R_SDRAM_TIMING__ref__e13us 1 +#define R_SDRAM_TIMING__ref__e6500ns 2 +#define R_SDRAM_TIMING__ref__disable 3 +#define R_SDRAM_TIMING__ddr__BITNR 13 +#define R_SDRAM_TIMING__ddr__WIDTH 1 +#define R_SDRAM_TIMING__ddr__on 1 +#define R_SDRAM_TIMING__ddr__off 0 +#define R_SDRAM_TIMING__clk100__BITNR 12 +#define R_SDRAM_TIMING__clk100__WIDTH 1 +#define R_SDRAM_TIMING__clk100__on 1 +#define R_SDRAM_TIMING__clk100__off 0 +#define R_SDRAM_TIMING__ps__BITNR 11 +#define R_SDRAM_TIMING__ps__WIDTH 1 +#define R_SDRAM_TIMING__ps__on 1 +#define R_SDRAM_TIMING__ps__off 0 +#define R_SDRAM_TIMING__cmd__BITNR 9 +#define R_SDRAM_TIMING__cmd__WIDTH 2 +#define R_SDRAM_TIMING__cmd__pre 3 +#define R_SDRAM_TIMING__cmd__ref 2 +#define R_SDRAM_TIMING__cmd__mrs 1 +#define R_SDRAM_TIMING__cmd__nop 0 +#define R_SDRAM_TIMING__pde__BITNR 8 +#define R_SDRAM_TIMING__pde__WIDTH 1 +#define R_SDRAM_TIMING__rc__BITNR 6 +#define R_SDRAM_TIMING__rc__WIDTH 2 +#define R_SDRAM_TIMING__rp__BITNR 4 +#define R_SDRAM_TIMING__rp__WIDTH 2 +#define R_SDRAM_TIMING__rcd__BITNR 2 +#define R_SDRAM_TIMING__rcd__WIDTH 2 +#define R_SDRAM_TIMING__cl__BITNR 0 +#define R_SDRAM_TIMING__cl__WIDTH 2 + +#define R_DRAM_CONFIG (IO_TYPECAST_UDWORD 0xb000000c) +#define R_DRAM_CONFIG__wmm1__BITNR 31 +#define R_DRAM_CONFIG__wmm1__WIDTH 1 +#define R_DRAM_CONFIG__wmm1__wmm 1 +#define R_DRAM_CONFIG__wmm1__norm 0 +#define R_DRAM_CONFIG__wmm0__BITNR 30 +#define R_DRAM_CONFIG__wmm0__WIDTH 1 +#define R_DRAM_CONFIG__wmm0__wmm 1 +#define R_DRAM_CONFIG__wmm0__norm 0 +#define R_DRAM_CONFIG__sh1__BITNR 27 +#define R_DRAM_CONFIG__sh1__WIDTH 3 +#define R_DRAM_CONFIG__sh0__BITNR 24 +#define R_DRAM_CONFIG__sh0__WIDTH 3 +#define R_DRAM_CONFIG__w__BITNR 23 +#define R_DRAM_CONFIG__w__WIDTH 1 +#define R_DRAM_CONFIG__w__bw16 0 +#define R_DRAM_CONFIG__w__bw32 1 +#define R_DRAM_CONFIG__c__BITNR 22 +#define R_DRAM_CONFIG__c__WIDTH 1 +#define R_DRAM_CONFIG__c__byte 0 +#define R_DRAM_CONFIG__c__bank 1 +#define R_DRAM_CONFIG__e__BITNR 21 +#define R_DRAM_CONFIG__e__WIDTH 1 +#define R_DRAM_CONFIG__e__fast 0 +#define R_DRAM_CONFIG__e__edo 1 +#define R_DRAM_CONFIG__group_sel__BITNR 16 +#define R_DRAM_CONFIG__group_sel__WIDTH 5 +#define R_DRAM_CONFIG__group_sel__grp0 0 +#define R_DRAM_CONFIG__group_sel__grp1 1 +#define R_DRAM_CONFIG__group_sel__bit9 9 +#define R_DRAM_CONFIG__group_sel__bit10 10 +#define R_DRAM_CONFIG__group_sel__bit11 11 +#define R_DRAM_CONFIG__group_sel__bit12 12 +#define R_DRAM_CONFIG__group_sel__bit13 13 +#define R_DRAM_CONFIG__group_sel__bit14 14 +#define R_DRAM_CONFIG__group_sel__bit15 15 +#define R_DRAM_CONFIG__group_sel__bit16 16 +#define R_DRAM_CONFIG__group_sel__bit17 17 +#define R_DRAM_CONFIG__group_sel__bit18 18 +#define R_DRAM_CONFIG__group_sel__bit19 19 +#define R_DRAM_CONFIG__group_sel__bit20 20 +#define R_DRAM_CONFIG__group_sel__bit21 21 +#define R_DRAM_CONFIG__group_sel__bit22 22 +#define R_DRAM_CONFIG__group_sel__bit23 23 +#define R_DRAM_CONFIG__group_sel__bit24 24 +#define R_DRAM_CONFIG__group_sel__bit25 25 +#define R_DRAM_CONFIG__group_sel__bit26 26 +#define R_DRAM_CONFIG__group_sel__bit27 27 +#define R_DRAM_CONFIG__group_sel__bit28 28 +#define R_DRAM_CONFIG__group_sel__bit29 29 +#define R_DRAM_CONFIG__ca1__BITNR 13 +#define R_DRAM_CONFIG__ca1__WIDTH 3 +#define R_DRAM_CONFIG__bank23sel__BITNR 8 +#define R_DRAM_CONFIG__bank23sel__WIDTH 5 +#define R_DRAM_CONFIG__bank23sel__bank0 0 +#define R_DRAM_CONFIG__bank23sel__bank1 1 +#define R_DRAM_CONFIG__bank23sel__bit9 9 +#define R_DRAM_CONFIG__bank23sel__bit10 10 +#define R_DRAM_CONFIG__bank23sel__bit11 11 +#define R_DRAM_CONFIG__bank23sel__bit12 12 +#define R_DRAM_CONFIG__bank23sel__bit13 13 +#define R_DRAM_CONFIG__bank23sel__bit14 14 +#define R_DRAM_CONFIG__bank23sel__bit15 15 +#define R_DRAM_CONFIG__bank23sel__bit16 16 +#define R_DRAM_CONFIG__bank23sel__bit17 17 +#define R_DRAM_CONFIG__bank23sel__bit18 18 +#define R_DRAM_CONFIG__bank23sel__bit19 19 +#define R_DRAM_CONFIG__bank23sel__bit20 20 +#define R_DRAM_CONFIG__bank23sel__bit21 21 +#define R_DRAM_CONFIG__bank23sel__bit22 22 +#define R_DRAM_CONFIG__bank23sel__bit23 23 +#define R_DRAM_CONFIG__bank23sel__bit24 24 +#define R_DRAM_CONFIG__bank23sel__bit25 25 +#define R_DRAM_CONFIG__bank23sel__bit26 26 +#define R_DRAM_CONFIG__bank23sel__bit27 27 +#define R_DRAM_CONFIG__bank23sel__bit28 28 +#define R_DRAM_CONFIG__bank23sel__bit29 29 +#define R_DRAM_CONFIG__ca0__BITNR 5 +#define R_DRAM_CONFIG__ca0__WIDTH 3 +#define R_DRAM_CONFIG__bank01sel__BITNR 0 +#define R_DRAM_CONFIG__bank01sel__WIDTH 5 +#define R_DRAM_CONFIG__bank01sel__bank0 0 +#define R_DRAM_CONFIG__bank01sel__bank1 1 +#define R_DRAM_CONFIG__bank01sel__bit9 9 +#define R_DRAM_CONFIG__bank01sel__bit10 10 +#define R_DRAM_CONFIG__bank01sel__bit11 11 +#define R_DRAM_CONFIG__bank01sel__bit12 12 +#define R_DRAM_CONFIG__bank01sel__bit13 13 +#define R_DRAM_CONFIG__bank01sel__bit14 14 +#define R_DRAM_CONFIG__bank01sel__bit15 15 +#define R_DRAM_CONFIG__bank01sel__bit16 16 +#define R_DRAM_CONFIG__bank01sel__bit17 17 +#define R_DRAM_CONFIG__bank01sel__bit18 18 +#define R_DRAM_CONFIG__bank01sel__bit19 19 +#define R_DRAM_CONFIG__bank01sel__bit20 20 +#define R_DRAM_CONFIG__bank01sel__bit21 21 +#define R_DRAM_CONFIG__bank01sel__bit22 22 +#define R_DRAM_CONFIG__bank01sel__bit23 23 +#define R_DRAM_CONFIG__bank01sel__bit24 24 +#define R_DRAM_CONFIG__bank01sel__bit25 25 +#define R_DRAM_CONFIG__bank01sel__bit26 26 +#define R_DRAM_CONFIG__bank01sel__bit27 27 +#define R_DRAM_CONFIG__bank01sel__bit28 28 +#define R_DRAM_CONFIG__bank01sel__bit29 29 + +#define R_SDRAM_CONFIG (IO_TYPECAST_UDWORD 0xb000000c) +#define R_SDRAM_CONFIG__wmm1__BITNR 31 +#define R_SDRAM_CONFIG__wmm1__WIDTH 1 +#define R_SDRAM_CONFIG__wmm1__wmm 1 +#define R_SDRAM_CONFIG__wmm1__norm 0 +#define R_SDRAM_CONFIG__wmm0__BITNR 30 +#define R_SDRAM_CONFIG__wmm0__WIDTH 1 +#define R_SDRAM_CONFIG__wmm0__wmm 1 +#define R_SDRAM_CONFIG__wmm0__norm 0 +#define R_SDRAM_CONFIG__sh1__BITNR 27 +#define R_SDRAM_CONFIG__sh1__WIDTH 3 +#define R_SDRAM_CONFIG__sh0__BITNR 24 +#define R_SDRAM_CONFIG__sh0__WIDTH 3 +#define R_SDRAM_CONFIG__w__BITNR 23 +#define R_SDRAM_CONFIG__w__WIDTH 1 +#define R_SDRAM_CONFIG__w__bw16 0 +#define R_SDRAM_CONFIG__w__bw32 1 +#define R_SDRAM_CONFIG__type1__BITNR 22 +#define R_SDRAM_CONFIG__type1__WIDTH 1 +#define R_SDRAM_CONFIG__type1__bank2 0 +#define R_SDRAM_CONFIG__type1__bank4 1 +#define R_SDRAM_CONFIG__type0__BITNR 21 +#define R_SDRAM_CONFIG__type0__WIDTH 1 +#define R_SDRAM_CONFIG__type0__bank2 0 +#define R_SDRAM_CONFIG__type0__bank4 1 +#define R_SDRAM_CONFIG__group_sel__BITNR 16 +#define R_SDRAM_CONFIG__group_sel__WIDTH 5 +#define R_SDRAM_CONFIG__group_sel__grp0 0 +#define R_SDRAM_CONFIG__group_sel__grp1 1 +#define R_SDRAM_CONFIG__group_sel__bit9 9 +#define R_SDRAM_CONFIG__group_sel__bit10 10 +#define R_SDRAM_CONFIG__group_sel__bit11 11 +#define R_SDRAM_CONFIG__group_sel__bit12 12 +#define R_SDRAM_CONFIG__group_sel__bit13 13 +#define R_SDRAM_CONFIG__group_sel__bit14 14 +#define R_SDRAM_CONFIG__group_sel__bit15 15 +#define R_SDRAM_CONFIG__group_sel__bit16 16 +#define R_SDRAM_CONFIG__group_sel__bit17 17 +#define R_SDRAM_CONFIG__group_sel__bit18 18 +#define R_SDRAM_CONFIG__group_sel__bit19 19 +#define R_SDRAM_CONFIG__group_sel__bit20 20 +#define R_SDRAM_CONFIG__group_sel__bit21 21 +#define R_SDRAM_CONFIG__group_sel__bit22 22 +#define R_SDRAM_CONFIG__group_sel__bit23 23 +#define R_SDRAM_CONFIG__group_sel__bit24 24 +#define R_SDRAM_CONFIG__group_sel__bit25 25 +#define R_SDRAM_CONFIG__group_sel__bit26 26 +#define R_SDRAM_CONFIG__group_sel__bit27 27 +#define R_SDRAM_CONFIG__group_sel__bit28 28 +#define R_SDRAM_CONFIG__group_sel__bit29 29 +#define R_SDRAM_CONFIG__ca1__BITNR 13 +#define R_SDRAM_CONFIG__ca1__WIDTH 3 +#define R_SDRAM_CONFIG__bank_sel1__BITNR 8 +#define R_SDRAM_CONFIG__bank_sel1__WIDTH 5 +#define R_SDRAM_CONFIG__bank_sel1__bit9 9 +#define R_SDRAM_CONFIG__bank_sel1__bit10 10 +#define R_SDRAM_CONFIG__bank_sel1__bit11 11 +#define R_SDRAM_CONFIG__bank_sel1__bit12 12 +#define R_SDRAM_CONFIG__bank_sel1__bit13 13 +#define R_SDRAM_CONFIG__bank_sel1__bit14 14 +#define R_SDRAM_CONFIG__bank_sel1__bit15 15 +#define R_SDRAM_CONFIG__bank_sel1__bit16 16 +#define R_SDRAM_CONFIG__bank_sel1__bit17 17 +#define R_SDRAM_CONFIG__bank_sel1__bit18 18 +#define R_SDRAM_CONFIG__bank_sel1__bit19 19 +#define R_SDRAM_CONFIG__bank_sel1__bit20 20 +#define R_SDRAM_CONFIG__bank_sel1__bit21 21 +#define R_SDRAM_CONFIG__bank_sel1__bit22 22 +#define R_SDRAM_CONFIG__bank_sel1__bit23 23 +#define R_SDRAM_CONFIG__bank_sel1__bit24 24 +#define R_SDRAM_CONFIG__bank_sel1__bit25 25 +#define R_SDRAM_CONFIG__bank_sel1__bit26 26 +#define R_SDRAM_CONFIG__bank_sel1__bit27 27 +#define R_SDRAM_CONFIG__bank_sel1__bit28 28 +#define R_SDRAM_CONFIG__bank_sel1__bit29 29 +#define R_SDRAM_CONFIG__ca0__BITNR 5 +#define R_SDRAM_CONFIG__ca0__WIDTH 3 +#define R_SDRAM_CONFIG__bank_sel0__BITNR 0 +#define R_SDRAM_CONFIG__bank_sel0__WIDTH 5 +#define R_SDRAM_CONFIG__bank_sel0__bit9 9 +#define R_SDRAM_CONFIG__bank_sel0__bit10 10 +#define R_SDRAM_CONFIG__bank_sel0__bit11 11 +#define R_SDRAM_CONFIG__bank_sel0__bit12 12 +#define R_SDRAM_CONFIG__bank_sel0__bit13 13 +#define R_SDRAM_CONFIG__bank_sel0__bit14 14 +#define R_SDRAM_CONFIG__bank_sel0__bit15 15 +#define R_SDRAM_CONFIG__bank_sel0__bit16 16 +#define R_SDRAM_CONFIG__bank_sel0__bit17 17 +#define R_SDRAM_CONFIG__bank_sel0__bit18 18 +#define R_SDRAM_CONFIG__bank_sel0__bit19 19 +#define R_SDRAM_CONFIG__bank_sel0__bit20 20 +#define R_SDRAM_CONFIG__bank_sel0__bit21 21 +#define R_SDRAM_CONFIG__bank_sel0__bit22 22 +#define R_SDRAM_CONFIG__bank_sel0__bit23 23 +#define R_SDRAM_CONFIG__bank_sel0__bit24 24 +#define R_SDRAM_CONFIG__bank_sel0__bit25 25 +#define R_SDRAM_CONFIG__bank_sel0__bit26 26 +#define R_SDRAM_CONFIG__bank_sel0__bit27 27 +#define R_SDRAM_CONFIG__bank_sel0__bit28 28 +#define R_SDRAM_CONFIG__bank_sel0__bit29 29 + +/* +!* External DMA registers +!*/ + +#define R_EXT_DMA_0_CMD (IO_TYPECAST_UDWORD 0xb0000010) +#define R_EXT_DMA_0_CMD__cnt__BITNR 23 +#define R_EXT_DMA_0_CMD__cnt__WIDTH 1 +#define R_EXT_DMA_0_CMD__cnt__enable 1 +#define R_EXT_DMA_0_CMD__cnt__disable 0 +#define R_EXT_DMA_0_CMD__rqpol__BITNR 22 +#define R_EXT_DMA_0_CMD__rqpol__WIDTH 1 +#define R_EXT_DMA_0_CMD__rqpol__ahigh 0 +#define R_EXT_DMA_0_CMD__rqpol__alow 1 +#define R_EXT_DMA_0_CMD__apol__BITNR 21 +#define R_EXT_DMA_0_CMD__apol__WIDTH 1 +#define R_EXT_DMA_0_CMD__apol__ahigh 0 +#define R_EXT_DMA_0_CMD__apol__alow 1 +#define R_EXT_DMA_0_CMD__rq_ack__BITNR 20 +#define R_EXT_DMA_0_CMD__rq_ack__WIDTH 1 +#define R_EXT_DMA_0_CMD__rq_ack__burst 0 +#define R_EXT_DMA_0_CMD__rq_ack__handsh 1 +#define R_EXT_DMA_0_CMD__wid__BITNR 18 +#define R_EXT_DMA_0_CMD__wid__WIDTH 2 +#define R_EXT_DMA_0_CMD__wid__byte 0 +#define R_EXT_DMA_0_CMD__wid__word 1 +#define R_EXT_DMA_0_CMD__wid__dword 2 +#define R_EXT_DMA_0_CMD__dir__BITNR 17 +#define R_EXT_DMA_0_CMD__dir__WIDTH 1 +#define R_EXT_DMA_0_CMD__dir__input 0 +#define R_EXT_DMA_0_CMD__dir__output 1 +#define R_EXT_DMA_0_CMD__run__BITNR 16 +#define R_EXT_DMA_0_CMD__run__WIDTH 1 +#define R_EXT_DMA_0_CMD__run__start 1 +#define R_EXT_DMA_0_CMD__run__stop 0 +#define R_EXT_DMA_0_CMD__trf_count__BITNR 0 +#define R_EXT_DMA_0_CMD__trf_count__WIDTH 16 + +#define R_EXT_DMA_0_STAT (IO_TYPECAST_RO_UDWORD 0xb0000010) +#define R_EXT_DMA_0_STAT__run__BITNR 16 +#define R_EXT_DMA_0_STAT__run__WIDTH 1 +#define R_EXT_DMA_0_STAT__run__start 1 +#define R_EXT_DMA_0_STAT__run__stop 0 +#define R_EXT_DMA_0_STAT__trf_count__BITNR 0 +#define R_EXT_DMA_0_STAT__trf_count__WIDTH 16 + +#define R_EXT_DMA_0_ADDR (IO_TYPECAST_UDWORD 0xb0000014) +#define R_EXT_DMA_0_ADDR__ext0_addr__BITNR 2 +#define R_EXT_DMA_0_ADDR__ext0_addr__WIDTH 28 + +#define R_EXT_DMA_1_CMD (IO_TYPECAST_UDWORD 0xb0000018) +#define R_EXT_DMA_1_CMD__cnt__BITNR 23 +#define R_EXT_DMA_1_CMD__cnt__WIDTH 1 +#define R_EXT_DMA_1_CMD__cnt__enable 1 +#define R_EXT_DMA_1_CMD__cnt__disable 0 +#define R_EXT_DMA_1_CMD__rqpol__BITNR 22 +#define R_EXT_DMA_1_CMD__rqpol__WIDTH 1 +#define R_EXT_DMA_1_CMD__rqpol__ahigh 0 +#define R_EXT_DMA_1_CMD__rqpol__alow 1 +#define R_EXT_DMA_1_CMD__apol__BITNR 21 +#define R_EXT_DMA_1_CMD__apol__WIDTH 1 +#define R_EXT_DMA_1_CMD__apol__ahigh 0 +#define R_EXT_DMA_1_CMD__apol__alow 1 +#define R_EXT_DMA_1_CMD__rq_ack__BITNR 20 +#define R_EXT_DMA_1_CMD__rq_ack__WIDTH 1 +#define R_EXT_DMA_1_CMD__rq_ack__burst 0 +#define R_EXT_DMA_1_CMD__rq_ack__handsh 1 +#define R_EXT_DMA_1_CMD__wid__BITNR 18 +#define R_EXT_DMA_1_CMD__wid__WIDTH 2 +#define R_EXT_DMA_1_CMD__wid__byte 0 +#define R_EXT_DMA_1_CMD__wid__word 1 +#define R_EXT_DMA_1_CMD__wid__dword 2 +#define R_EXT_DMA_1_CMD__dir__BITNR 17 +#define R_EXT_DMA_1_CMD__dir__WIDTH 1 +#define R_EXT_DMA_1_CMD__dir__input 0 +#define R_EXT_DMA_1_CMD__dir__output 1 +#define R_EXT_DMA_1_CMD__run__BITNR 16 +#define R_EXT_DMA_1_CMD__run__WIDTH 1 +#define R_EXT_DMA_1_CMD__run__start 1 +#define R_EXT_DMA_1_CMD__run__stop 0 +#define R_EXT_DMA_1_CMD__trf_count__BITNR 0 +#define R_EXT_DMA_1_CMD__trf_count__WIDTH 16 + +#define R_EXT_DMA_1_STAT (IO_TYPECAST_RO_UDWORD 0xb0000018) +#define R_EXT_DMA_1_STAT__run__BITNR 16 +#define R_EXT_DMA_1_STAT__run__WIDTH 1 +#define R_EXT_DMA_1_STAT__run__start 1 +#define R_EXT_DMA_1_STAT__run__stop 0 +#define R_EXT_DMA_1_STAT__trf_count__BITNR 0 +#define R_EXT_DMA_1_STAT__trf_count__WIDTH 16 + +#define R_EXT_DMA_1_ADDR (IO_TYPECAST_UDWORD 0xb000001c) +#define R_EXT_DMA_1_ADDR__ext0_addr__BITNR 2 +#define R_EXT_DMA_1_ADDR__ext0_addr__WIDTH 28 + +/* +!* Timer registers +!*/ + +#define R_TIMER_CTRL (IO_TYPECAST_UDWORD 0xb0000020) +#define R_TIMER_CTRL__timerdiv1__BITNR 24 +#define R_TIMER_CTRL__timerdiv1__WIDTH 8 +#define R_TIMER_CTRL__timerdiv0__BITNR 16 +#define R_TIMER_CTRL__timerdiv0__WIDTH 8 +#define R_TIMER_CTRL__presc_timer1__BITNR 15 +#define R_TIMER_CTRL__presc_timer1__WIDTH 1 +#define R_TIMER_CTRL__presc_timer1__normal 0 +#define R_TIMER_CTRL__presc_timer1__prescale 1 +#define R_TIMER_CTRL__i1__BITNR 14 +#define R_TIMER_CTRL__i1__WIDTH 1 +#define R_TIMER_CTRL__i1__clr 1 +#define R_TIMER_CTRL__i1__nop 0 +#define R_TIMER_CTRL__tm1__BITNR 12 +#define R_TIMER_CTRL__tm1__WIDTH 2 +#define R_TIMER_CTRL__tm1__stop_ld 0 +#define R_TIMER_CTRL__tm1__freeze 1 +#define R_TIMER_CTRL__tm1__run 2 +#define R_TIMER_CTRL__tm1__reserved 3 +#define R_TIMER_CTRL__clksel1__BITNR 8 +#define R_TIMER_CTRL__clksel1__WIDTH 4 +#define R_TIMER_CTRL__clksel1__c300Hz 0 +#define R_TIMER_CTRL__clksel1__c600Hz 1 +#define R_TIMER_CTRL__clksel1__c1200Hz 2 +#define R_TIMER_CTRL__clksel1__c2400Hz 3 +#define R_TIMER_CTRL__clksel1__c4800Hz 4 +#define R_TIMER_CTRL__clksel1__c9600Hz 5 +#define R_TIMER_CTRL__clksel1__c19k2Hz 6 +#define R_TIMER_CTRL__clksel1__c38k4Hz 7 +#define R_TIMER_CTRL__clksel1__c57k6Hz 8 +#define R_TIMER_CTRL__clksel1__c115k2Hz 9 +#define R_TIMER_CTRL__clksel1__c230k4Hz 10 +#define R_TIMER_CTRL__clksel1__c460k8Hz 11 +#define R_TIMER_CTRL__clksel1__c921k6Hz 12 +#define R_TIMER_CTRL__clksel1__c1843k2Hz 13 +#define R_TIMER_CTRL__clksel1__c6250kHz 14 +#define R_TIMER_CTRL__clksel1__cascade0 15 +#define R_TIMER_CTRL__presc_ext__BITNR 7 +#define R_TIMER_CTRL__presc_ext__WIDTH 1 +#define R_TIMER_CTRL__presc_ext__prescale 0 +#define R_TIMER_CTRL__presc_ext__external 1 +#define R_TIMER_CTRL__i0__BITNR 6 +#define R_TIMER_CTRL__i0__WIDTH 1 +#define R_TIMER_CTRL__i0__clr 1 +#define R_TIMER_CTRL__i0__nop 0 +#define R_TIMER_CTRL__tm0__BITNR 4 +#define R_TIMER_CTRL__tm0__WIDTH 2 +#define R_TIMER_CTRL__tm0__stop_ld 0 +#define R_TIMER_CTRL__tm0__freeze 1 +#define R_TIMER_CTRL__tm0__run 2 +#define R_TIMER_CTRL__tm0__reserved 3 +#define R_TIMER_CTRL__clksel0__BITNR 0 +#define R_TIMER_CTRL__clksel0__WIDTH 4 +#define R_TIMER_CTRL__clksel0__c300Hz 0 +#define R_TIMER_CTRL__clksel0__c600Hz 1 +#define R_TIMER_CTRL__clksel0__c1200Hz 2 +#define R_TIMER_CTRL__clksel0__c2400Hz 3 +#define R_TIMER_CTRL__clksel0__c4800Hz 4 +#define R_TIMER_CTRL__clksel0__c9600Hz 5 +#define R_TIMER_CTRL__clksel0__c19k2Hz 6 +#define R_TIMER_CTRL__clksel0__c38k4Hz 7 +#define R_TIMER_CTRL__clksel0__c57k6Hz 8 +#define R_TIMER_CTRL__clksel0__c115k2Hz 9 +#define R_TIMER_CTRL__clksel0__c230k4Hz 10 +#define R_TIMER_CTRL__clksel0__c460k8Hz 11 +#define R_TIMER_CTRL__clksel0__c921k6Hz 12 +#define R_TIMER_CTRL__clksel0__c1843k2Hz 13 +#define R_TIMER_CTRL__clksel0__c6250kHz 14 +#define R_TIMER_CTRL__clksel0__flexible 15 + +#define R_TIMER_DATA (IO_TYPECAST_RO_UDWORD 0xb0000020) +#define R_TIMER_DATA__timer1__BITNR 24 +#define R_TIMER_DATA__timer1__WIDTH 8 +#define R_TIMER_DATA__timer0__BITNR 16 +#define R_TIMER_DATA__timer0__WIDTH 8 +#define R_TIMER_DATA__clkdiv_high__BITNR 8 +#define R_TIMER_DATA__clkdiv_high__WIDTH 8 +#define R_TIMER_DATA__clkdiv_low__BITNR 0 +#define R_TIMER_DATA__clkdiv_low__WIDTH 8 + +#define R_TIMER01_DATA (IO_TYPECAST_RO_UWORD 0xb0000022) +#define R_TIMER01_DATA__count__BITNR 0 +#define R_TIMER01_DATA__count__WIDTH 16 + +#define R_TIMER0_DATA (IO_TYPECAST_RO_BYTE 0xb0000022) +#define R_TIMER0_DATA__count__BITNR 0 +#define R_TIMER0_DATA__count__WIDTH 8 + +#define R_TIMER1_DATA (IO_TYPECAST_RO_BYTE 0xb0000023) +#define R_TIMER1_DATA__count__BITNR 0 +#define R_TIMER1_DATA__count__WIDTH 8 + +#define R_WATCHDOG (IO_TYPECAST_UDWORD 0xb0000024) +#define R_WATCHDOG__key__BITNR 1 +#define R_WATCHDOG__key__WIDTH 3 +#define R_WATCHDOG__enable__BITNR 0 +#define R_WATCHDOG__enable__WIDTH 1 +#define R_WATCHDOG__enable__stop 0 +#define R_WATCHDOG__enable__start 1 + +#define R_CLOCK_PRESCALE (IO_TYPECAST_UDWORD 0xb00000f0) +#define R_CLOCK_PRESCALE__ser_presc__BITNR 16 +#define R_CLOCK_PRESCALE__ser_presc__WIDTH 16 +#define R_CLOCK_PRESCALE__tim_presc__BITNR 0 +#define R_CLOCK_PRESCALE__tim_presc__WIDTH 16 + +#define R_SERIAL_PRESCALE (IO_TYPECAST_UWORD 0xb00000f2) +#define R_SERIAL_PRESCALE__ser_presc__BITNR 0 +#define R_SERIAL_PRESCALE__ser_presc__WIDTH 16 + +#define R_TIMER_PRESCALE (IO_TYPECAST_UWORD 0xb00000f0) +#define R_TIMER_PRESCALE__tim_presc__BITNR 0 +#define R_TIMER_PRESCALE__tim_presc__WIDTH 16 + +#define R_PRESCALE_STATUS (IO_TYPECAST_RO_UDWORD 0xb00000f0) +#define R_PRESCALE_STATUS__ser_status__BITNR 16 +#define R_PRESCALE_STATUS__ser_status__WIDTH 16 +#define R_PRESCALE_STATUS__tim_status__BITNR 0 +#define R_PRESCALE_STATUS__tim_status__WIDTH 16 + +#define R_SER_PRESC_STATUS (IO_TYPECAST_RO_UWORD 0xb00000f2) +#define R_SER_PRESC_STATUS__ser_status__BITNR 0 +#define R_SER_PRESC_STATUS__ser_status__WIDTH 16 + +#define R_TIM_PRESC_STATUS (IO_TYPECAST_RO_UWORD 0xb00000f0) +#define R_TIM_PRESC_STATUS__tim_status__BITNR 0 +#define R_TIM_PRESC_STATUS__tim_status__WIDTH 16 + +#define R_SYNC_SERIAL_PRESCALE (IO_TYPECAST_UDWORD 0xb00000f4) +#define R_SYNC_SERIAL_PRESCALE__clk_sel_u3__BITNR 23 +#define R_SYNC_SERIAL_PRESCALE__clk_sel_u3__WIDTH 1 +#define R_SYNC_SERIAL_PRESCALE__clk_sel_u3__codec 0 +#define R_SYNC_SERIAL_PRESCALE__clk_sel_u3__baudrate 1 +#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u3__BITNR 22 +#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u3__WIDTH 1 +#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u3__external 0 +#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u3__internal 1 +#define R_SYNC_SERIAL_PRESCALE__clk_sel_u1__BITNR 21 +#define R_SYNC_SERIAL_PRESCALE__clk_sel_u1__WIDTH 1 +#define R_SYNC_SERIAL_PRESCALE__clk_sel_u1__codec 0 +#define R_SYNC_SERIAL_PRESCALE__clk_sel_u1__baudrate 1 +#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u1__BITNR 20 +#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u1__WIDTH 1 +#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u1__external 0 +#define R_SYNC_SERIAL_PRESCALE__word_stb_sel_u1__internal 1 +#define R_SYNC_SERIAL_PRESCALE__prescaler__BITNR 16 +#define R_SYNC_SERIAL_PRESCALE__prescaler__WIDTH 3 +#define R_SYNC_SERIAL_PRESCALE__prescaler__div1 0 +#define R_SYNC_SERIAL_PRESCALE__prescaler__div2 1 +#define R_SYNC_SERIAL_PRESCALE__prescaler__div4 2 +#define R_SYNC_SERIAL_PRESCALE__prescaler__div8 3 +#define R_SYNC_SERIAL_PRESCALE__prescaler__div16 4 +#define R_SYNC_SERIAL_PRESCALE__prescaler__div32 5 +#define R_SYNC_SERIAL_PRESCALE__prescaler__div64 6 +#define R_SYNC_SERIAL_PRESCALE__prescaler__div128 7 +#define R_SYNC_SERIAL_PRESCALE__warp_mode__BITNR 15 +#define R_SYNC_SERIAL_PRESCALE__warp_mode__WIDTH 1 +#define R_SYNC_SERIAL_PRESCALE__warp_mode__normal 0 +#define R_SYNC_SERIAL_PRESCALE__warp_mode__enabled 1 +#define R_SYNC_SERIAL_PRESCALE__frame_rate__BITNR 11 +#define R_SYNC_SERIAL_PRESCALE__frame_rate__WIDTH 4 +#define R_SYNC_SERIAL_PRESCALE__word_rate__BITNR 0 +#define R_SYNC_SERIAL_PRESCALE__word_rate__WIDTH 10 + +/* +!* Shared RAM interface registers +!*/ + +#define R_SHARED_RAM_CONFIG (IO_TYPECAST_UDWORD 0xb0000040) +#define R_SHARED_RAM_CONFIG__width__BITNR 3 +#define R_SHARED_RAM_CONFIG__width__WIDTH 1 +#define R_SHARED_RAM_CONFIG__width__byte 0 +#define R_SHARED_RAM_CONFIG__width__word 1 +#define R_SHARED_RAM_CONFIG__enable__BITNR 2 +#define R_SHARED_RAM_CONFIG__enable__WIDTH 1 +#define R_SHARED_RAM_CONFIG__enable__yes 1 +#define R_SHARED_RAM_CONFIG__enable__no 0 +#define R_SHARED_RAM_CONFIG__pint__BITNR 1 +#define R_SHARED_RAM_CONFIG__pint__WIDTH 1 +#define R_SHARED_RAM_CONFIG__pint__int 1 +#define R_SHARED_RAM_CONFIG__pint__nop 0 +#define R_SHARED_RAM_CONFIG__clri__BITNR 0 +#define R_SHARED_RAM_CONFIG__clri__WIDTH 1 +#define R_SHARED_RAM_CONFIG__clri__clr 1 +#define R_SHARED_RAM_CONFIG__clri__nop 0 + +#define R_SHARED_RAM_ADDR (IO_TYPECAST_UDWORD 0xb0000044) +#define R_SHARED_RAM_ADDR__base_addr__BITNR 8 +#define R_SHARED_RAM_ADDR__base_addr__WIDTH 22 + +/* +!* General config registers +!*/ + +#define R_GEN_CONFIG (IO_TYPECAST_UDWORD 0xb000002c) +#define R_GEN_CONFIG__par_w__BITNR 31 +#define R_GEN_CONFIG__par_w__WIDTH 1 +#define R_GEN_CONFIG__par_w__select 1 +#define R_GEN_CONFIG__par_w__disable 0 +#define R_GEN_CONFIG__usb2__BITNR 30 +#define R_GEN_CONFIG__usb2__WIDTH 1 +#define R_GEN_CONFIG__usb2__select 1 +#define R_GEN_CONFIG__usb2__disable 0 +#define R_GEN_CONFIG__usb1__BITNR 29 +#define R_GEN_CONFIG__usb1__WIDTH 1 +#define R_GEN_CONFIG__usb1__select 1 +#define R_GEN_CONFIG__usb1__disable 0 +#define R_GEN_CONFIG__g24dir__BITNR 27 +#define R_GEN_CONFIG__g24dir__WIDTH 1 +#define R_GEN_CONFIG__g24dir__in 0 +#define R_GEN_CONFIG__g24dir__out 1 +#define R_GEN_CONFIG__g16_23dir__BITNR 26 +#define R_GEN_CONFIG__g16_23dir__WIDTH 1 +#define R_GEN_CONFIG__g16_23dir__in 0 +#define R_GEN_CONFIG__g16_23dir__out 1 +#define R_GEN_CONFIG__g8_15dir__BITNR 25 +#define R_GEN_CONFIG__g8_15dir__WIDTH 1 +#define R_GEN_CONFIG__g8_15dir__in 0 +#define R_GEN_CONFIG__g8_15dir__out 1 +#define R_GEN_CONFIG__g0dir__BITNR 24 +#define R_GEN_CONFIG__g0dir__WIDTH 1 +#define R_GEN_CONFIG__g0dir__in 0 +#define R_GEN_CONFIG__g0dir__out 1 +#define R_GEN_CONFIG__dma9__BITNR 23 +#define R_GEN_CONFIG__dma9__WIDTH 1 +#define R_GEN_CONFIG__dma9__usb 0 +#define R_GEN_CONFIG__dma9__serial1 1 +#define R_GEN_CONFIG__dma8__BITNR 22 +#define R_GEN_CONFIG__dma8__WIDTH 1 +#define R_GEN_CONFIG__dma8__usb 0 +#define R_GEN_CONFIG__dma8__serial1 1 +#define R_GEN_CONFIG__dma7__BITNR 20 +#define R_GEN_CONFIG__dma7__WIDTH 2 +#define R_GEN_CONFIG__dma7__unused 0 +#define R_GEN_CONFIG__dma7__serial0 1 +#define R_GEN_CONFIG__dma7__extdma1 2 +#define R_GEN_CONFIG__dma7__intdma6 3 +#define R_GEN_CONFIG__dma6__BITNR 18 +#define R_GEN_CONFIG__dma6__WIDTH 2 +#define R_GEN_CONFIG__dma6__unused 0 +#define R_GEN_CONFIG__dma6__serial0 1 +#define R_GEN_CONFIG__dma6__extdma1 2 +#define R_GEN_CONFIG__dma6__intdma7 3 +#define R_GEN_CONFIG__dma5__BITNR 16 +#define R_GEN_CONFIG__dma5__WIDTH 2 +#define R_GEN_CONFIG__dma5__par1 0 +#define R_GEN_CONFIG__dma5__scsi1 1 +#define R_GEN_CONFIG__dma5__serial3 2 +#define R_GEN_CONFIG__dma5__extdma0 3 +#define R_GEN_CONFIG__dma4__BITNR 14 +#define R_GEN_CONFIG__dma4__WIDTH 2 +#define R_GEN_CONFIG__dma4__par1 0 +#define R_GEN_CONFIG__dma4__scsi1 1 +#define R_GEN_CONFIG__dma4__serial3 2 +#define R_GEN_CONFIG__dma4__extdma0 3 +#define R_GEN_CONFIG__dma3__BITNR 12 +#define R_GEN_CONFIG__dma3__WIDTH 2 +#define R_GEN_CONFIG__dma3__par0 0 +#define R_GEN_CONFIG__dma3__scsi0 1 +#define R_GEN_CONFIG__dma3__serial2 2 +#define R_GEN_CONFIG__dma3__ata 3 +#define R_GEN_CONFIG__dma2__BITNR 10 +#define R_GEN_CONFIG__dma2__WIDTH 2 +#define R_GEN_CONFIG__dma2__par0 0 +#define R_GEN_CONFIG__dma2__scsi0 1 +#define R_GEN_CONFIG__dma2__serial2 2 +#define R_GEN_CONFIG__dma2__ata 3 +#define R_GEN_CONFIG__mio_w__BITNR 9 +#define R_GEN_CONFIG__mio_w__WIDTH 1 +#define R_GEN_CONFIG__mio_w__select 1 +#define R_GEN_CONFIG__mio_w__disable 0 +#define R_GEN_CONFIG__ser3__BITNR 8 +#define R_GEN_CONFIG__ser3__WIDTH 1 +#define R_GEN_CONFIG__ser3__select 1 +#define R_GEN_CONFIG__ser3__disable 0 +#define R_GEN_CONFIG__par1__BITNR 7 +#define R_GEN_CONFIG__par1__WIDTH 1 +#define R_GEN_CONFIG__par1__select 1 +#define R_GEN_CONFIG__par1__disable 0 +#define R_GEN_CONFIG__scsi0w__BITNR 6 +#define R_GEN_CONFIG__scsi0w__WIDTH 1 +#define R_GEN_CONFIG__scsi0w__select 1 +#define R_GEN_CONFIG__scsi0w__disable 0 +#define R_GEN_CONFIG__scsi1__BITNR 5 +#define R_GEN_CONFIG__scsi1__WIDTH 1 +#define R_GEN_CONFIG__scsi1__select 1 +#define R_GEN_CONFIG__scsi1__disable 0 +#define R_GEN_CONFIG__mio__BITNR 4 +#define R_GEN_CONFIG__mio__WIDTH 1 +#define R_GEN_CONFIG__mio__select 1 +#define R_GEN_CONFIG__mio__disable 0 +#define R_GEN_CONFIG__ser2__BITNR 3 +#define R_GEN_CONFIG__ser2__WIDTH 1 +#define R_GEN_CONFIG__ser2__select 1 +#define R_GEN_CONFIG__ser2__disable 0 +#define R_GEN_CONFIG__par0__BITNR 2 +#define R_GEN_CONFIG__par0__WIDTH 1 +#define R_GEN_CONFIG__par0__select 1 +#define R_GEN_CONFIG__par0__disable 0 +#define R_GEN_CONFIG__ata__BITNR 1 +#define R_GEN_CONFIG__ata__WIDTH 1 +#define R_GEN_CONFIG__ata__select 1 +#define R_GEN_CONFIG__ata__disable 0 +#define R_GEN_CONFIG__scsi0__BITNR 0 +#define R_GEN_CONFIG__scsi0__WIDTH 1 +#define R_GEN_CONFIG__scsi0__select 1 +#define R_GEN_CONFIG__scsi0__disable 0 + +#define R_GEN_CONFIG_II (IO_TYPECAST_UDWORD 0xb0000034) +#define R_GEN_CONFIG_II__sermode3__BITNR 6 +#define R_GEN_CONFIG_II__sermode3__WIDTH 1 +#define R_GEN_CONFIG_II__sermode3__async 0 +#define R_GEN_CONFIG_II__sermode3__sync 1 +#define R_GEN_CONFIG_II__sermode1__BITNR 4 +#define R_GEN_CONFIG_II__sermode1__WIDTH 1 +#define R_GEN_CONFIG_II__sermode1__async 0 +#define R_GEN_CONFIG_II__sermode1__sync 1 +#define R_GEN_CONFIG_II__ext_clk__BITNR 2 +#define R_GEN_CONFIG_II__ext_clk__WIDTH 1 +#define R_GEN_CONFIG_II__ext_clk__select 1 +#define R_GEN_CONFIG_II__ext_clk__disable 0 +#define R_GEN_CONFIG_II__ser2__BITNR 1 +#define R_GEN_CONFIG_II__ser2__WIDTH 1 +#define R_GEN_CONFIG_II__ser2__select 1 +#define R_GEN_CONFIG_II__ser2__disable 0 +#define R_GEN_CONFIG_II__ser3__BITNR 0 +#define R_GEN_CONFIG_II__ser3__WIDTH 1 +#define R_GEN_CONFIG_II__ser3__select 1 +#define R_GEN_CONFIG_II__ser3__disable 0 + +#define R_PORT_G_DATA (IO_TYPECAST_UDWORD 0xb0000028) +#define R_PORT_G_DATA__data__BITNR 0 +#define R_PORT_G_DATA__data__WIDTH 32 + +/* +!* General port configuration registers +!*/ + +#define R_PORT_PA_SET (IO_TYPECAST_UDWORD 0xb0000030) +#define R_PORT_PA_SET__dir7__BITNR 15 +#define R_PORT_PA_SET__dir7__WIDTH 1 +#define R_PORT_PA_SET__dir7__input 0 +#define R_PORT_PA_SET__dir7__output 1 +#define R_PORT_PA_SET__dir6__BITNR 14 +#define R_PORT_PA_SET__dir6__WIDTH 1 +#define R_PORT_PA_SET__dir6__input 0 +#define R_PORT_PA_SET__dir6__output 1 +#define R_PORT_PA_SET__dir5__BITNR 13 +#define R_PORT_PA_SET__dir5__WIDTH 1 +#define R_PORT_PA_SET__dir5__input 0 +#define R_PORT_PA_SET__dir5__output 1 +#define R_PORT_PA_SET__dir4__BITNR 12 +#define R_PORT_PA_SET__dir4__WIDTH 1 +#define R_PORT_PA_SET__dir4__input 0 +#define R_PORT_PA_SET__dir4__output 1 +#define R_PORT_PA_SET__dir3__BITNR 11 +#define R_PORT_PA_SET__dir3__WIDTH 1 +#define R_PORT_PA_SET__dir3__input 0 +#define R_PORT_PA_SET__dir3__output 1 +#define R_PORT_PA_SET__dir2__BITNR 10 +#define R_PORT_PA_SET__dir2__WIDTH 1 +#define R_PORT_PA_SET__dir2__input 0 +#define R_PORT_PA_SET__dir2__output 1 +#define R_PORT_PA_SET__dir1__BITNR 9 +#define R_PORT_PA_SET__dir1__WIDTH 1 +#define R_PORT_PA_SET__dir1__input 0 +#define R_PORT_PA_SET__dir1__output 1 +#define R_PORT_PA_SET__dir0__BITNR 8 +#define R_PORT_PA_SET__dir0__WIDTH 1 +#define R_PORT_PA_SET__dir0__input 0 +#define R_PORT_PA_SET__dir0__output 1 +#define R_PORT_PA_SET__data_out__BITNR 0 +#define R_PORT_PA_SET__data_out__WIDTH 8 + +#define R_PORT_PA_DATA (IO_TYPECAST_BYTE 0xb0000030) +#define R_PORT_PA_DATA__data_out__BITNR 0 +#define R_PORT_PA_DATA__data_out__WIDTH 8 + +#define R_PORT_PA_DIR (IO_TYPECAST_BYTE 0xb0000031) +#define R_PORT_PA_DIR__dir7__BITNR 7 +#define R_PORT_PA_DIR__dir7__WIDTH 1 +#define R_PORT_PA_DIR__dir7__input 0 +#define R_PORT_PA_DIR__dir7__output 1 +#define R_PORT_PA_DIR__dir6__BITNR 6 +#define R_PORT_PA_DIR__dir6__WIDTH 1 +#define R_PORT_PA_DIR__dir6__input 0 +#define R_PORT_PA_DIR__dir6__output 1 +#define R_PORT_PA_DIR__dir5__BITNR 5 +#define R_PORT_PA_DIR__dir5__WIDTH 1 +#define R_PORT_PA_DIR__dir5__input 0 +#define R_PORT_PA_DIR__dir5__output 1 +#define R_PORT_PA_DIR__dir4__BITNR 4 +#define R_PORT_PA_DIR__dir4__WIDTH 1 +#define R_PORT_PA_DIR__dir4__input 0 +#define R_PORT_PA_DIR__dir4__output 1 +#define R_PORT_PA_DIR__dir3__BITNR 3 +#define R_PORT_PA_DIR__dir3__WIDTH 1 +#define R_PORT_PA_DIR__dir3__input 0 +#define R_PORT_PA_DIR__dir3__output 1 +#define R_PORT_PA_DIR__dir2__BITNR 2 +#define R_PORT_PA_DIR__dir2__WIDTH 1 +#define R_PORT_PA_DIR__dir2__input 0 +#define R_PORT_PA_DIR__dir2__output 1 +#define R_PORT_PA_DIR__dir1__BITNR 1 +#define R_PORT_PA_DIR__dir1__WIDTH 1 +#define R_PORT_PA_DIR__dir1__input 0 +#define R_PORT_PA_DIR__dir1__output 1 +#define R_PORT_PA_DIR__dir0__BITNR 0 +#define R_PORT_PA_DIR__dir0__WIDTH 1 +#define R_PORT_PA_DIR__dir0__input 0 +#define R_PORT_PA_DIR__dir0__output 1 + +#define R_PORT_PA_READ (IO_TYPECAST_RO_UDWORD 0xb0000030) +#define R_PORT_PA_READ__data_in__BITNR 0 +#define R_PORT_PA_READ__data_in__WIDTH 8 + +#define R_PORT_PB_SET (IO_TYPECAST_UDWORD 0xb0000038) +#define R_PORT_PB_SET__syncser3__BITNR 29 +#define R_PORT_PB_SET__syncser3__WIDTH 1 +#define R_PORT_PB_SET__syncser3__port_cs 0 +#define R_PORT_PB_SET__syncser3__ss3extra 1 +#define R_PORT_PB_SET__syncser1__BITNR 28 +#define R_PORT_PB_SET__syncser1__WIDTH 1 +#define R_PORT_PB_SET__syncser1__port_cs 0 +#define R_PORT_PB_SET__syncser1__ss1extra 1 +#define R_PORT_PB_SET__i2c_en__BITNR 27 +#define R_PORT_PB_SET__i2c_en__WIDTH 1 +#define R_PORT_PB_SET__i2c_en__off 0 +#define R_PORT_PB_SET__i2c_en__on 1 +#define R_PORT_PB_SET__i2c_d__BITNR 26 +#define R_PORT_PB_SET__i2c_d__WIDTH 1 +#define R_PORT_PB_SET__i2c_clk__BITNR 25 +#define R_PORT_PB_SET__i2c_clk__WIDTH 1 +#define R_PORT_PB_SET__i2c_oe___BITNR 24 +#define R_PORT_PB_SET__i2c_oe___WIDTH 1 +#define R_PORT_PB_SET__i2c_oe___enable 0 +#define R_PORT_PB_SET__i2c_oe___disable 1 +#define R_PORT_PB_SET__cs7__BITNR 23 +#define R_PORT_PB_SET__cs7__WIDTH 1 +#define R_PORT_PB_SET__cs7__port 0 +#define R_PORT_PB_SET__cs7__cs 1 +#define R_PORT_PB_SET__cs6__BITNR 22 +#define R_PORT_PB_SET__cs6__WIDTH 1 +#define R_PORT_PB_SET__cs6__port 0 +#define R_PORT_PB_SET__cs6__cs 1 +#define R_PORT_PB_SET__cs5__BITNR 21 +#define R_PORT_PB_SET__cs5__WIDTH 1 +#define R_PORT_PB_SET__cs5__port 0 +#define R_PORT_PB_SET__cs5__cs 1 +#define R_PORT_PB_SET__cs4__BITNR 20 +#define R_PORT_PB_SET__cs4__WIDTH 1 +#define R_PORT_PB_SET__cs4__port 0 +#define R_PORT_PB_SET__cs4__cs 1 +#define R_PORT_PB_SET__cs3__BITNR 19 +#define R_PORT_PB_SET__cs3__WIDTH 1 +#define R_PORT_PB_SET__cs3__port 0 +#define R_PORT_PB_SET__cs3__cs 1 +#define R_PORT_PB_SET__cs2__BITNR 18 +#define R_PORT_PB_SET__cs2__WIDTH 1 +#define R_PORT_PB_SET__cs2__port 0 +#define R_PORT_PB_SET__cs2__cs 1 +#define R_PORT_PB_SET__scsi1__BITNR 17 +#define R_PORT_PB_SET__scsi1__WIDTH 1 +#define R_PORT_PB_SET__scsi1__port_cs 0 +#define R_PORT_PB_SET__scsi1__enph 1 +#define R_PORT_PB_SET__scsi0__BITNR 16 +#define R_PORT_PB_SET__scsi0__WIDTH 1 +#define R_PORT_PB_SET__scsi0__port_cs 0 +#define R_PORT_PB_SET__scsi0__enph 1 +#define R_PORT_PB_SET__dir7__BITNR 15 +#define R_PORT_PB_SET__dir7__WIDTH 1 +#define R_PORT_PB_SET__dir7__input 0 +#define R_PORT_PB_SET__dir7__output 1 +#define R_PORT_PB_SET__dir6__BITNR 14 +#define R_PORT_PB_SET__dir6__WIDTH 1 +#define R_PORT_PB_SET__dir6__input 0 +#define R_PORT_PB_SET__dir6__output 1 +#define R_PORT_PB_SET__dir5__BITNR 13 +#define R_PORT_PB_SET__dir5__WIDTH 1 +#define R_PORT_PB_SET__dir5__input 0 +#define R_PORT_PB_SET__dir5__output 1 +#define R_PORT_PB_SET__dir4__BITNR 12 +#define R_PORT_PB_SET__dir4__WIDTH 1 +#define R_PORT_PB_SET__dir4__input 0 +#define R_PORT_PB_SET__dir4__output 1 +#define R_PORT_PB_SET__dir3__BITNR 11 +#define R_PORT_PB_SET__dir3__WIDTH 1 +#define R_PORT_PB_SET__dir3__input 0 +#define R_PORT_PB_SET__dir3__output 1 +#define R_PORT_PB_SET__dir2__BITNR 10 +#define R_PORT_PB_SET__dir2__WIDTH 1 +#define R_PORT_PB_SET__dir2__input 0 +#define R_PORT_PB_SET__dir2__output 1 +#define R_PORT_PB_SET__dir1__BITNR 9 +#define R_PORT_PB_SET__dir1__WIDTH 1 +#define R_PORT_PB_SET__dir1__input 0 +#define R_PORT_PB_SET__dir1__output 1 +#define R_PORT_PB_SET__dir0__BITNR 8 +#define R_PORT_PB_SET__dir0__WIDTH 1 +#define R_PORT_PB_SET__dir0__input 0 +#define R_PORT_PB_SET__dir0__output 1 +#define R_PORT_PB_SET__data_out__BITNR 0 +#define R_PORT_PB_SET__data_out__WIDTH 8 + +#define R_PORT_PB_DATA (IO_TYPECAST_BYTE 0xb0000038) +#define R_PORT_PB_DATA__data_out__BITNR 0 +#define R_PORT_PB_DATA__data_out__WIDTH 8 + +#define R_PORT_PB_DIR (IO_TYPECAST_BYTE 0xb0000039) +#define R_PORT_PB_DIR__dir7__BITNR 7 +#define R_PORT_PB_DIR__dir7__WIDTH 1 +#define R_PORT_PB_DIR__dir7__input 0 +#define R_PORT_PB_DIR__dir7__output 1 +#define R_PORT_PB_DIR__dir6__BITNR 6 +#define R_PORT_PB_DIR__dir6__WIDTH 1 +#define R_PORT_PB_DIR__dir6__input 0 +#define R_PORT_PB_DIR__dir6__output 1 +#define R_PORT_PB_DIR__dir5__BITNR 5 +#define R_PORT_PB_DIR__dir5__WIDTH 1 +#define R_PORT_PB_DIR__dir5__input 0 +#define R_PORT_PB_DIR__dir5__output 1 +#define R_PORT_PB_DIR__dir4__BITNR 4 +#define R_PORT_PB_DIR__dir4__WIDTH 1 +#define R_PORT_PB_DIR__dir4__input 0 +#define R_PORT_PB_DIR__dir4__output 1 +#define R_PORT_PB_DIR__dir3__BITNR 3 +#define R_PORT_PB_DIR__dir3__WIDTH 1 +#define R_PORT_PB_DIR__dir3__input 0 +#define R_PORT_PB_DIR__dir3__output 1 +#define R_PORT_PB_DIR__dir2__BITNR 2 +#define R_PORT_PB_DIR__dir2__WIDTH 1 +#define R_PORT_PB_DIR__dir2__input 0 +#define R_PORT_PB_DIR__dir2__output 1 +#define R_PORT_PB_DIR__dir1__BITNR 1 +#define R_PORT_PB_DIR__dir1__WIDTH 1 +#define R_PORT_PB_DIR__dir1__input 0 +#define R_PORT_PB_DIR__dir1__output 1 +#define R_PORT_PB_DIR__dir0__BITNR 0 +#define R_PORT_PB_DIR__dir0__WIDTH 1 +#define R_PORT_PB_DIR__dir0__input 0 +#define R_PORT_PB_DIR__dir0__output 1 + +#define R_PORT_PB_CONFIG (IO_TYPECAST_BYTE 0xb000003a) +#define R_PORT_PB_CONFIG__cs7__BITNR 7 +#define R_PORT_PB_CONFIG__cs7__WIDTH 1 +#define R_PORT_PB_CONFIG__cs7__port 0 +#define R_PORT_PB_CONFIG__cs7__cs 1 +#define R_PORT_PB_CONFIG__cs6__BITNR 6 +#define R_PORT_PB_CONFIG__cs6__WIDTH 1 +#define R_PORT_PB_CONFIG__cs6__port 0 +#define R_PORT_PB_CONFIG__cs6__cs 1 +#define R_PORT_PB_CONFIG__cs5__BITNR 5 +#define R_PORT_PB_CONFIG__cs5__WIDTH 1 +#define R_PORT_PB_CONFIG__cs5__port 0 +#define R_PORT_PB_CONFIG__cs5__cs 1 +#define R_PORT_PB_CONFIG__cs4__BITNR 4 +#define R_PORT_PB_CONFIG__cs4__WIDTH 1 +#define R_PORT_PB_CONFIG__cs4__port 0 +#define R_PORT_PB_CONFIG__cs4__cs 1 +#define R_PORT_PB_CONFIG__cs3__BITNR 3 +#define R_PORT_PB_CONFIG__cs3__WIDTH 1 +#define R_PORT_PB_CONFIG__cs3__port 0 +#define R_PORT_PB_CONFIG__cs3__cs 1 +#define R_PORT_PB_CONFIG__cs2__BITNR 2 +#define R_PORT_PB_CONFIG__cs2__WIDTH 1 +#define R_PORT_PB_CONFIG__cs2__port 0 +#define R_PORT_PB_CONFIG__cs2__cs 1 +#define R_PORT_PB_CONFIG__scsi1__BITNR 1 +#define R_PORT_PB_CONFIG__scsi1__WIDTH 1 +#define R_PORT_PB_CONFIG__scsi1__port_cs 0 +#define R_PORT_PB_CONFIG__scsi1__enph 1 +#define R_PORT_PB_CONFIG__scsi0__BITNR 0 +#define R_PORT_PB_CONFIG__scsi0__WIDTH 1 +#define R_PORT_PB_CONFIG__scsi0__port_cs 0 +#define R_PORT_PB_CONFIG__scsi0__enph 1 + +#define R_PORT_PB_I2C (IO_TYPECAST_BYTE 0xb000003b) +#define R_PORT_PB_I2C__syncser3__BITNR 5 +#define R_PORT_PB_I2C__syncser3__WIDTH 1 +#define R_PORT_PB_I2C__syncser3__port_cs 0 +#define R_PORT_PB_I2C__syncser3__ss3extra 1 +#define R_PORT_PB_I2C__syncser1__BITNR 4 +#define R_PORT_PB_I2C__syncser1__WIDTH 1 +#define R_PORT_PB_I2C__syncser1__port_cs 0 +#define R_PORT_PB_I2C__syncser1__ss1extra 1 +#define R_PORT_PB_I2C__i2c_en__BITNR 3 +#define R_PORT_PB_I2C__i2c_en__WIDTH 1 +#define R_PORT_PB_I2C__i2c_en__off 0 +#define R_PORT_PB_I2C__i2c_en__on 1 +#define R_PORT_PB_I2C__i2c_d__BITNR 2 +#define R_PORT_PB_I2C__i2c_d__WIDTH 1 +#define R_PORT_PB_I2C__i2c_clk__BITNR 1 +#define R_PORT_PB_I2C__i2c_clk__WIDTH 1 +#define R_PORT_PB_I2C__i2c_oe___BITNR 0 +#define R_PORT_PB_I2C__i2c_oe___WIDTH 1 +#define R_PORT_PB_I2C__i2c_oe___enable 0 +#define R_PORT_PB_I2C__i2c_oe___disable 1 + +#define R_PORT_PB_READ (IO_TYPECAST_RO_UDWORD 0xb0000038) +#define R_PORT_PB_READ__data_in__BITNR 0 +#define R_PORT_PB_READ__data_in__WIDTH 8 + +/* +!* Serial port registers +!*/ + +#define R_SERIAL0_CTRL (IO_TYPECAST_UDWORD 0xb0000060) +#define R_SERIAL0_CTRL__tr_baud__BITNR 28 +#define R_SERIAL0_CTRL__tr_baud__WIDTH 4 +#define R_SERIAL0_CTRL__tr_baud__c300Hz 0 +#define R_SERIAL0_CTRL__tr_baud__c600Hz 1 +#define R_SERIAL0_CTRL__tr_baud__c1200Hz 2 +#define R_SERIAL0_CTRL__tr_baud__c2400Hz 3 +#define R_SERIAL0_CTRL__tr_baud__c4800Hz 4 +#define R_SERIAL0_CTRL__tr_baud__c9600Hz 5 +#define R_SERIAL0_CTRL__tr_baud__c19k2Hz 6 +#define R_SERIAL0_CTRL__tr_baud__c38k4Hz 7 +#define R_SERIAL0_CTRL__tr_baud__c57k6Hz 8 +#define R_SERIAL0_CTRL__tr_baud__c115k2Hz 9 +#define R_SERIAL0_CTRL__tr_baud__c230k4Hz 10 +#define R_SERIAL0_CTRL__tr_baud__c460k8Hz 11 +#define R_SERIAL0_CTRL__tr_baud__c921k6Hz 12 +#define R_SERIAL0_CTRL__tr_baud__c1843k2Hz 13 +#define R_SERIAL0_CTRL__tr_baud__c6250kHz 14 +#define R_SERIAL0_CTRL__tr_baud__reserved 15 +#define R_SERIAL0_CTRL__rec_baud__BITNR 24 +#define R_SERIAL0_CTRL__rec_baud__WIDTH 4 +#define R_SERIAL0_CTRL__rec_baud__c300Hz 0 +#define R_SERIAL0_CTRL__rec_baud__c600Hz 1 +#define R_SERIAL0_CTRL__rec_baud__c1200Hz 2 +#define R_SERIAL0_CTRL__rec_baud__c2400Hz 3 +#define R_SERIAL0_CTRL__rec_baud__c4800Hz 4 +#define R_SERIAL0_CTRL__rec_baud__c9600Hz 5 +#define R_SERIAL0_CTRL__rec_baud__c19k2Hz 6 +#define R_SERIAL0_CTRL__rec_baud__c38k4Hz 7 +#define R_SERIAL0_CTRL__rec_baud__c57k6Hz 8 +#define R_SERIAL0_CTRL__rec_baud__c115k2Hz 9 +#define R_SERIAL0_CTRL__rec_baud__c230k4Hz 10 +#define R_SERIAL0_CTRL__rec_baud__c460k8Hz 11 +#define R_SERIAL0_CTRL__rec_baud__c921k6Hz 12 +#define R_SERIAL0_CTRL__rec_baud__c1843k2Hz 13 +#define R_SERIAL0_CTRL__rec_baud__c6250kHz 14 +#define R_SERIAL0_CTRL__rec_baud__reserved 15 +#define R_SERIAL0_CTRL__dma_err__BITNR 23 +#define R_SERIAL0_CTRL__dma_err__WIDTH 1 +#define R_SERIAL0_CTRL__dma_err__stop 0 +#define R_SERIAL0_CTRL__dma_err__ignore 1 +#define R_SERIAL0_CTRL__rec_enable__BITNR 22 +#define R_SERIAL0_CTRL__rec_enable__WIDTH 1 +#define R_SERIAL0_CTRL__rec_enable__disable 0 +#define R_SERIAL0_CTRL__rec_enable__enable 1 +#define R_SERIAL0_CTRL__rts___BITNR 21 +#define R_SERIAL0_CTRL__rts___WIDTH 1 +#define R_SERIAL0_CTRL__rts___active 0 +#define R_SERIAL0_CTRL__rts___inactive 1 +#define R_SERIAL0_CTRL__sampling__BITNR 20 +#define R_SERIAL0_CTRL__sampling__WIDTH 1 +#define R_SERIAL0_CTRL__sampling__middle 0 +#define R_SERIAL0_CTRL__sampling__majority 1 +#define R_SERIAL0_CTRL__rec_stick_par__BITNR 19 +#define R_SERIAL0_CTRL__rec_stick_par__WIDTH 1 +#define R_SERIAL0_CTRL__rec_stick_par__normal 0 +#define R_SERIAL0_CTRL__rec_stick_par__stick 1 +#define R_SERIAL0_CTRL__rec_par__BITNR 18 +#define R_SERIAL0_CTRL__rec_par__WIDTH 1 +#define R_SERIAL0_CTRL__rec_par__even 0 +#define R_SERIAL0_CTRL__rec_par__odd 1 +#define R_SERIAL0_CTRL__rec_par_en__BITNR 17 +#define R_SERIAL0_CTRL__rec_par_en__WIDTH 1 +#define R_SERIAL0_CTRL__rec_par_en__disable 0 +#define R_SERIAL0_CTRL__rec_par_en__enable 1 +#define R_SERIAL0_CTRL__rec_bitnr__BITNR 16 +#define R_SERIAL0_CTRL__rec_bitnr__WIDTH 1 +#define R_SERIAL0_CTRL__rec_bitnr__rec_8bit 0 +#define R_SERIAL0_CTRL__rec_bitnr__rec_7bit 1 +#define R_SERIAL0_CTRL__txd__BITNR 15 +#define R_SERIAL0_CTRL__txd__WIDTH 1 +#define R_SERIAL0_CTRL__tr_enable__BITNR 14 +#define R_SERIAL0_CTRL__tr_enable__WIDTH 1 +#define R_SERIAL0_CTRL__tr_enable__disable 0 +#define R_SERIAL0_CTRL__tr_enable__enable 1 +#define R_SERIAL0_CTRL__auto_cts__BITNR 13 +#define R_SERIAL0_CTRL__auto_cts__WIDTH 1 +#define R_SERIAL0_CTRL__auto_cts__disabled 0 +#define R_SERIAL0_CTRL__auto_cts__active 1 +#define R_SERIAL0_CTRL__stop_bits__BITNR 12 +#define R_SERIAL0_CTRL__stop_bits__WIDTH 1 +#define R_SERIAL0_CTRL__stop_bits__one_bit 0 +#define R_SERIAL0_CTRL__stop_bits__two_bits 1 +#define R_SERIAL0_CTRL__tr_stick_par__BITNR 11 +#define R_SERIAL0_CTRL__tr_stick_par__WIDTH 1 +#define R_SERIAL0_CTRL__tr_stick_par__normal 0 +#define R_SERIAL0_CTRL__tr_stick_par__stick 1 +#define R_SERIAL0_CTRL__tr_par__BITNR 10 +#define R_SERIAL0_CTRL__tr_par__WIDTH 1 +#define R_SERIAL0_CTRL__tr_par__even 0 +#define R_SERIAL0_CTRL__tr_par__odd 1 +#define R_SERIAL0_CTRL__tr_par_en__BITNR 9 +#define R_SERIAL0_CTRL__tr_par_en__WIDTH 1 +#define R_SERIAL0_CTRL__tr_par_en__disable 0 +#define R_SERIAL0_CTRL__tr_par_en__enable 1 +#define R_SERIAL0_CTRL__tr_bitnr__BITNR 8 +#define R_SERIAL0_CTRL__tr_bitnr__WIDTH 1 +#define R_SERIAL0_CTRL__tr_bitnr__tr_8bit 0 +#define R_SERIAL0_CTRL__tr_bitnr__tr_7bit 1 +#define R_SERIAL0_CTRL__data_out__BITNR 0 +#define R_SERIAL0_CTRL__data_out__WIDTH 8 + +#define R_SERIAL0_BAUD (IO_TYPECAST_BYTE 0xb0000063) +#define R_SERIAL0_BAUD__tr_baud__BITNR 4 +#define R_SERIAL0_BAUD__tr_baud__WIDTH 4 +#define R_SERIAL0_BAUD__tr_baud__c300Hz 0 +#define R_SERIAL0_BAUD__tr_baud__c600Hz 1 +#define R_SERIAL0_BAUD__tr_baud__c1200Hz 2 +#define R_SERIAL0_BAUD__tr_baud__c2400Hz 3 +#define R_SERIAL0_BAUD__tr_baud__c4800Hz 4 +#define R_SERIAL0_BAUD__tr_baud__c9600Hz 5 +#define R_SERIAL0_BAUD__tr_baud__c19k2Hz 6 +#define R_SERIAL0_BAUD__tr_baud__c38k4Hz 7 +#define R_SERIAL0_BAUD__tr_baud__c57k6Hz 8 +#define R_SERIAL0_BAUD__tr_baud__c115k2Hz 9 +#define R_SERIAL0_BAUD__tr_baud__c230k4Hz 10 +#define R_SERIAL0_BAUD__tr_baud__c460k8Hz 11 +#define R_SERIAL0_BAUD__tr_baud__c921k6Hz 12 +#define R_SERIAL0_BAUD__tr_baud__c1843k2Hz 13 +#define R_SERIAL0_BAUD__tr_baud__c6250kHz 14 +#define R_SERIAL0_BAUD__tr_baud__reserved 15 +#define R_SERIAL0_BAUD__rec_baud__BITNR 0 +#define R_SERIAL0_BAUD__rec_baud__WIDTH 4 +#define R_SERIAL0_BAUD__rec_baud__c300Hz 0 +#define R_SERIAL0_BAUD__rec_baud__c600Hz 1 +#define R_SERIAL0_BAUD__rec_baud__c1200Hz 2 +#define R_SERIAL0_BAUD__rec_baud__c2400Hz 3 +#define R_SERIAL0_BAUD__rec_baud__c4800Hz 4 +#define R_SERIAL0_BAUD__rec_baud__c9600Hz 5 +#define R_SERIAL0_BAUD__rec_baud__c19k2Hz 6 +#define R_SERIAL0_BAUD__rec_baud__c38k4Hz 7 +#define R_SERIAL0_BAUD__rec_baud__c57k6Hz 8 +#define R_SERIAL0_BAUD__rec_baud__c115k2Hz 9 +#define R_SERIAL0_BAUD__rec_baud__c230k4Hz 10 +#define R_SERIAL0_BAUD__rec_baud__c460k8Hz 11 +#define R_SERIAL0_BAUD__rec_baud__c921k6Hz 12 +#define R_SERIAL0_BAUD__rec_baud__c1843k2Hz 13 +#define R_SERIAL0_BAUD__rec_baud__c6250kHz 14 +#define R_SERIAL0_BAUD__rec_baud__reserved 15 + +#define R_SERIAL0_REC_CTRL (IO_TYPECAST_BYTE 0xb0000062) +#define R_SERIAL0_REC_CTRL__dma_err__BITNR 7 +#define R_SERIAL0_REC_CTRL__dma_err__WIDTH 1 +#define R_SERIAL0_REC_CTRL__dma_err__stop 0 +#define R_SERIAL0_REC_CTRL__dma_err__ignore 1 +#define R_SERIAL0_REC_CTRL__rec_enable__BITNR 6 +#define R_SERIAL0_REC_CTRL__rec_enable__WIDTH 1 +#define R_SERIAL0_REC_CTRL__rec_enable__disable 0 +#define R_SERIAL0_REC_CTRL__rec_enable__enable 1 +#define R_SERIAL0_REC_CTRL__rts___BITNR 5 +#define R_SERIAL0_REC_CTRL__rts___WIDTH 1 +#define R_SERIAL0_REC_CTRL__rts___active 0 +#define R_SERIAL0_REC_CTRL__rts___inactive 1 +#define R_SERIAL0_REC_CTRL__sampling__BITNR 4 +#define R_SERIAL0_REC_CTRL__sampling__WIDTH 1 +#define R_SERIAL0_REC_CTRL__sampling__middle 0 +#define R_SERIAL0_REC_CTRL__sampling__majority 1 +#define R_SERIAL0_REC_CTRL__rec_stick_par__BITNR 3 +#define R_SERIAL0_REC_CTRL__rec_stick_par__WIDTH 1 +#define R_SERIAL0_REC_CTRL__rec_stick_par__normal 0 +#define R_SERIAL0_REC_CTRL__rec_stick_par__stick 1 +#define R_SERIAL0_REC_CTRL__rec_par__BITNR 2 +#define R_SERIAL0_REC_CTRL__rec_par__WIDTH 1 +#define R_SERIAL0_REC_CTRL__rec_par__even 0 +#define R_SERIAL0_REC_CTRL__rec_par__odd 1 +#define R_SERIAL0_REC_CTRL__rec_par_en__BITNR 1 +#define R_SERIAL0_REC_CTRL__rec_par_en__WIDTH 1 +#define R_SERIAL0_REC_CTRL__rec_par_en__disable 0 +#define R_SERIAL0_REC_CTRL__rec_par_en__enable 1 +#define R_SERIAL0_REC_CTRL__rec_bitnr__BITNR 0 +#define R_SERIAL0_REC_CTRL__rec_bitnr__WIDTH 1 +#define R_SERIAL0_REC_CTRL__rec_bitnr__rec_8bit 0 +#define R_SERIAL0_REC_CTRL__rec_bitnr__rec_7bit 1 + +#define R_SERIAL0_TR_CTRL (IO_TYPECAST_BYTE 0xb0000061) +#define R_SERIAL0_TR_CTRL__txd__BITNR 7 +#define R_SERIAL0_TR_CTRL__txd__WIDTH 1 +#define R_SERIAL0_TR_CTRL__tr_enable__BITNR 6 +#define R_SERIAL0_TR_CTRL__tr_enable__WIDTH 1 +#define R_SERIAL0_TR_CTRL__tr_enable__disable 0 +#define R_SERIAL0_TR_CTRL__tr_enable__enable 1 +#define R_SERIAL0_TR_CTRL__auto_cts__BITNR 5 +#define R_SERIAL0_TR_CTRL__auto_cts__WIDTH 1 +#define R_SERIAL0_TR_CTRL__auto_cts__disabled 0 +#define R_SERIAL0_TR_CTRL__auto_cts__active 1 +#define R_SERIAL0_TR_CTRL__stop_bits__BITNR 4 +#define R_SERIAL0_TR_CTRL__stop_bits__WIDTH 1 +#define R_SERIAL0_TR_CTRL__stop_bits__one_bit 0 +#define R_SERIAL0_TR_CTRL__stop_bits__two_bits 1 +#define R_SERIAL0_TR_CTRL__tr_stick_par__BITNR 3 +#define R_SERIAL0_TR_CTRL__tr_stick_par__WIDTH 1 +#define R_SERIAL0_TR_CTRL__tr_stick_par__normal 0 +#define R_SERIAL0_TR_CTRL__tr_stick_par__stick 1 +#define R_SERIAL0_TR_CTRL__tr_par__BITNR 2 +#define R_SERIAL0_TR_CTRL__tr_par__WIDTH 1 +#define R_SERIAL0_TR_CTRL__tr_par__even 0 +#define R_SERIAL0_TR_CTRL__tr_par__odd 1 +#define R_SERIAL0_TR_CTRL__tr_par_en__BITNR 1 +#define R_SERIAL0_TR_CTRL__tr_par_en__WIDTH 1 +#define R_SERIAL0_TR_CTRL__tr_par_en__disable 0 +#define R_SERIAL0_TR_CTRL__tr_par_en__enable 1 +#define R_SERIAL0_TR_CTRL__tr_bitnr__BITNR 0 +#define R_SERIAL0_TR_CTRL__tr_bitnr__WIDTH 1 +#define R_SERIAL0_TR_CTRL__tr_bitnr__tr_8bit 0 +#define R_SERIAL0_TR_CTRL__tr_bitnr__tr_7bit 1 + +#define R_SERIAL0_TR_DATA (IO_TYPECAST_BYTE 0xb0000060) +#define R_SERIAL0_TR_DATA__data_out__BITNR 0 +#define R_SERIAL0_TR_DATA__data_out__WIDTH 8 + +#define R_SERIAL0_READ (IO_TYPECAST_RO_UDWORD 0xb0000060) +#define R_SERIAL0_READ__xoff_detect__BITNR 15 +#define R_SERIAL0_READ__xoff_detect__WIDTH 1 +#define R_SERIAL0_READ__xoff_detect__no_xoff 0 +#define R_SERIAL0_READ__xoff_detect__xoff 1 +#define R_SERIAL0_READ__cts___BITNR 14 +#define R_SERIAL0_READ__cts___WIDTH 1 +#define R_SERIAL0_READ__cts___active 0 +#define R_SERIAL0_READ__cts___inactive 1 +#define R_SERIAL0_READ__tr_ready__BITNR 13 +#define R_SERIAL0_READ__tr_ready__WIDTH 1 +#define R_SERIAL0_READ__tr_ready__full 0 +#define R_SERIAL0_READ__tr_ready__ready 1 +#define R_SERIAL0_READ__rxd__BITNR 12 +#define R_SERIAL0_READ__rxd__WIDTH 1 +#define R_SERIAL0_READ__overrun__BITNR 11 +#define R_SERIAL0_READ__overrun__WIDTH 1 +#define R_SERIAL0_READ__overrun__no 0 +#define R_SERIAL0_READ__overrun__yes 1 +#define R_SERIAL0_READ__par_err__BITNR 10 +#define R_SERIAL0_READ__par_err__WIDTH 1 +#define R_SERIAL0_READ__par_err__no 0 +#define R_SERIAL0_READ__par_err__yes 1 +#define R_SERIAL0_READ__framing_err__BITNR 9 +#define R_SERIAL0_READ__framing_err__WIDTH 1 +#define R_SERIAL0_READ__framing_err__no 0 +#define R_SERIAL0_READ__framing_err__yes 1 +#define R_SERIAL0_READ__data_avail__BITNR 8 +#define R_SERIAL0_READ__data_avail__WIDTH 1 +#define R_SERIAL0_READ__data_avail__no 0 +#define R_SERIAL0_READ__data_avail__yes 1 +#define R_SERIAL0_READ__data_in__BITNR 0 +#define R_SERIAL0_READ__data_in__WIDTH 8 + +#define R_SERIAL0_STATUS (IO_TYPECAST_RO_BYTE 0xb0000061) +#define R_SERIAL0_STATUS__xoff_detect__BITNR 7 +#define R_SERIAL0_STATUS__xoff_detect__WIDTH 1 +#define R_SERIAL0_STATUS__xoff_detect__no_xoff 0 +#define R_SERIAL0_STATUS__xoff_detect__xoff 1 +#define R_SERIAL0_STATUS__cts___BITNR 6 +#define R_SERIAL0_STATUS__cts___WIDTH 1 +#define R_SERIAL0_STATUS__cts___active 0 +#define R_SERIAL0_STATUS__cts___inactive 1 +#define R_SERIAL0_STATUS__tr_ready__BITNR 5 +#define R_SERIAL0_STATUS__tr_ready__WIDTH 1 +#define R_SERIAL0_STATUS__tr_ready__full 0 +#define R_SERIAL0_STATUS__tr_ready__ready 1 +#define R_SERIAL0_STATUS__rxd__BITNR 4 +#define R_SERIAL0_STATUS__rxd__WIDTH 1 +#define R_SERIAL0_STATUS__overrun__BITNR 3 +#define R_SERIAL0_STATUS__overrun__WIDTH 1 +#define R_SERIAL0_STATUS__overrun__no 0 +#define R_SERIAL0_STATUS__overrun__yes 1 +#define R_SERIAL0_STATUS__par_err__BITNR 2 +#define R_SERIAL0_STATUS__par_err__WIDTH 1 +#define R_SERIAL0_STATUS__par_err__no 0 +#define R_SERIAL0_STATUS__par_err__yes 1 +#define R_SERIAL0_STATUS__framing_err__BITNR 1 +#define R_SERIAL0_STATUS__framing_err__WIDTH 1 +#define R_SERIAL0_STATUS__framing_err__no 0 +#define R_SERIAL0_STATUS__framing_err__yes 1 +#define R_SERIAL0_STATUS__data_avail__BITNR 0 +#define R_SERIAL0_STATUS__data_avail__WIDTH 1 +#define R_SERIAL0_STATUS__data_avail__no 0 +#define R_SERIAL0_STATUS__data_avail__yes 1 + +#define R_SERIAL0_REC_DATA (IO_TYPECAST_RO_BYTE 0xb0000060) +#define R_SERIAL0_REC_DATA__data_in__BITNR 0 +#define R_SERIAL0_REC_DATA__data_in__WIDTH 8 + +#define R_SERIAL0_XOFF (IO_TYPECAST_UDWORD 0xb0000064) +#define R_SERIAL0_XOFF__tx_stop__BITNR 9 +#define R_SERIAL0_XOFF__tx_stop__WIDTH 1 +#define R_SERIAL0_XOFF__tx_stop__enable 0 +#define R_SERIAL0_XOFF__tx_stop__stop 1 +#define R_SERIAL0_XOFF__auto_xoff__BITNR 8 +#define R_SERIAL0_XOFF__auto_xoff__WIDTH 1 +#define R_SERIAL0_XOFF__auto_xoff__disable 0 +#define R_SERIAL0_XOFF__auto_xoff__enable 1 +#define R_SERIAL0_XOFF__xoff_char__BITNR 0 +#define R_SERIAL0_XOFF__xoff_char__WIDTH 8 + +#define R_SERIAL1_CTRL (IO_TYPECAST_UDWORD 0xb0000068) +#define R_SERIAL1_CTRL__tr_baud__BITNR 28 +#define R_SERIAL1_CTRL__tr_baud__WIDTH 4 +#define R_SERIAL1_CTRL__tr_baud__c300Hz 0 +#define R_SERIAL1_CTRL__tr_baud__c600Hz 1 +#define R_SERIAL1_CTRL__tr_baud__c1200Hz 2 +#define R_SERIAL1_CTRL__tr_baud__c2400Hz 3 +#define R_SERIAL1_CTRL__tr_baud__c4800Hz 4 +#define R_SERIAL1_CTRL__tr_baud__c9600Hz 5 +#define R_SERIAL1_CTRL__tr_baud__c19k2Hz 6 +#define R_SERIAL1_CTRL__tr_baud__c38k4Hz 7 +#define R_SERIAL1_CTRL__tr_baud__c57k6Hz 8 +#define R_SERIAL1_CTRL__tr_baud__c115k2Hz 9 +#define R_SERIAL1_CTRL__tr_baud__c230k4Hz 10 +#define R_SERIAL1_CTRL__tr_baud__c460k8Hz 11 +#define R_SERIAL1_CTRL__tr_baud__c921k6Hz 12 +#define R_SERIAL1_CTRL__tr_baud__c1843k2Hz 13 +#define R_SERIAL1_CTRL__tr_baud__c6250kHz 14 +#define R_SERIAL1_CTRL__tr_baud__reserved 15 +#define R_SERIAL1_CTRL__rec_baud__BITNR 24 +#define R_SERIAL1_CTRL__rec_baud__WIDTH 4 +#define R_SERIAL1_CTRL__rec_baud__c300Hz 0 +#define R_SERIAL1_CTRL__rec_baud__c600Hz 1 +#define R_SERIAL1_CTRL__rec_baud__c1200Hz 2 +#define R_SERIAL1_CTRL__rec_baud__c2400Hz 3 +#define R_SERIAL1_CTRL__rec_baud__c4800Hz 4 +#define R_SERIAL1_CTRL__rec_baud__c9600Hz 5 +#define R_SERIAL1_CTRL__rec_baud__c19k2Hz 6 +#define R_SERIAL1_CTRL__rec_baud__c38k4Hz 7 +#define R_SERIAL1_CTRL__rec_baud__c57k6Hz 8 +#define R_SERIAL1_CTRL__rec_baud__c115k2Hz 9 +#define R_SERIAL1_CTRL__rec_baud__c230k4Hz 10 +#define R_SERIAL1_CTRL__rec_baud__c460k8Hz 11 +#define R_SERIAL1_CTRL__rec_baud__c921k6Hz 12 +#define R_SERIAL1_CTRL__rec_baud__c1843k2Hz 13 +#define R_SERIAL1_CTRL__rec_baud__c6250kHz 14 +#define R_SERIAL1_CTRL__rec_baud__reserved 15 +#define R_SERIAL1_CTRL__dma_err__BITNR 23 +#define R_SERIAL1_CTRL__dma_err__WIDTH 1 +#define R_SERIAL1_CTRL__dma_err__stop 0 +#define R_SERIAL1_CTRL__dma_err__ignore 1 +#define R_SERIAL1_CTRL__rec_enable__BITNR 22 +#define R_SERIAL1_CTRL__rec_enable__WIDTH 1 +#define R_SERIAL1_CTRL__rec_enable__disable 0 +#define R_SERIAL1_CTRL__rec_enable__enable 1 +#define R_SERIAL1_CTRL__rts___BITNR 21 +#define R_SERIAL1_CTRL__rts___WIDTH 1 +#define R_SERIAL1_CTRL__rts___active 0 +#define R_SERIAL1_CTRL__rts___inactive 1 +#define R_SERIAL1_CTRL__sampling__BITNR 20 +#define R_SERIAL1_CTRL__sampling__WIDTH 1 +#define R_SERIAL1_CTRL__sampling__middle 0 +#define R_SERIAL1_CTRL__sampling__majority 1 +#define R_SERIAL1_CTRL__rec_stick_par__BITNR 19 +#define R_SERIAL1_CTRL__rec_stick_par__WIDTH 1 +#define R_SERIAL1_CTRL__rec_stick_par__normal 0 +#define R_SERIAL1_CTRL__rec_stick_par__stick 1 +#define R_SERIAL1_CTRL__rec_par__BITNR 18 +#define R_SERIAL1_CTRL__rec_par__WIDTH 1 +#define R_SERIAL1_CTRL__rec_par__even 0 +#define R_SERIAL1_CTRL__rec_par__odd 1 +#define R_SERIAL1_CTRL__rec_par_en__BITNR 17 +#define R_SERIAL1_CTRL__rec_par_en__WIDTH 1 +#define R_SERIAL1_CTRL__rec_par_en__disable 0 +#define R_SERIAL1_CTRL__rec_par_en__enable 1 +#define R_SERIAL1_CTRL__rec_bitnr__BITNR 16 +#define R_SERIAL1_CTRL__rec_bitnr__WIDTH 1 +#define R_SERIAL1_CTRL__rec_bitnr__rec_8bit 0 +#define R_SERIAL1_CTRL__rec_bitnr__rec_7bit 1 +#define R_SERIAL1_CTRL__txd__BITNR 15 +#define R_SERIAL1_CTRL__txd__WIDTH 1 +#define R_SERIAL1_CTRL__tr_enable__BITNR 14 +#define R_SERIAL1_CTRL__tr_enable__WIDTH 1 +#define R_SERIAL1_CTRL__tr_enable__disable 0 +#define R_SERIAL1_CTRL__tr_enable__enable 1 +#define R_SERIAL1_CTRL__auto_cts__BITNR 13 +#define R_SERIAL1_CTRL__auto_cts__WIDTH 1 +#define R_SERIAL1_CTRL__auto_cts__disabled 0 +#define R_SERIAL1_CTRL__auto_cts__active 1 +#define R_SERIAL1_CTRL__stop_bits__BITNR 12 +#define R_SERIAL1_CTRL__stop_bits__WIDTH 1 +#define R_SERIAL1_CTRL__stop_bits__one_bit 0 +#define R_SERIAL1_CTRL__stop_bits__two_bits 1 +#define R_SERIAL1_CTRL__tr_stick_par__BITNR 11 +#define R_SERIAL1_CTRL__tr_stick_par__WIDTH 1 +#define R_SERIAL1_CTRL__tr_stick_par__normal 0 +#define R_SERIAL1_CTRL__tr_stick_par__stick 1 +#define R_SERIAL1_CTRL__tr_par__BITNR 10 +#define R_SERIAL1_CTRL__tr_par__WIDTH 1 +#define R_SERIAL1_CTRL__tr_par__even 0 +#define R_SERIAL1_CTRL__tr_par__odd 1 +#define R_SERIAL1_CTRL__tr_par_en__BITNR 9 +#define R_SERIAL1_CTRL__tr_par_en__WIDTH 1 +#define R_SERIAL1_CTRL__tr_par_en__disable 0 +#define R_SERIAL1_CTRL__tr_par_en__enable 1 +#define R_SERIAL1_CTRL__tr_bitnr__BITNR 8 +#define R_SERIAL1_CTRL__tr_bitnr__WIDTH 1 +#define R_SERIAL1_CTRL__tr_bitnr__tr_8bit 0 +#define R_SERIAL1_CTRL__tr_bitnr__tr_7bit 1 +#define R_SERIAL1_CTRL__data_out__BITNR 0 +#define R_SERIAL1_CTRL__data_out__WIDTH 8 + +#define R_SERIAL1_BAUD (IO_TYPECAST_BYTE 0xb000006b) +#define R_SERIAL1_BAUD__tr_baud__BITNR 4 +#define R_SERIAL1_BAUD__tr_baud__WIDTH 4 +#define R_SERIAL1_BAUD__tr_baud__c300Hz 0 +#define R_SERIAL1_BAUD__tr_baud__c600Hz 1 +#define R_SERIAL1_BAUD__tr_baud__c1200Hz 2 +#define R_SERIAL1_BAUD__tr_baud__c2400Hz 3 +#define R_SERIAL1_BAUD__tr_baud__c4800Hz 4 +#define R_SERIAL1_BAUD__tr_baud__c9600Hz 5 +#define R_SERIAL1_BAUD__tr_baud__c19k2Hz 6 +#define R_SERIAL1_BAUD__tr_baud__c38k4Hz 7 +#define R_SERIAL1_BAUD__tr_baud__c57k6Hz 8 +#define R_SERIAL1_BAUD__tr_baud__c115k2Hz 9 +#define R_SERIAL1_BAUD__tr_baud__c230k4Hz 10 +#define R_SERIAL1_BAUD__tr_baud__c460k8Hz 11 +#define R_SERIAL1_BAUD__tr_baud__c921k6Hz 12 +#define R_SERIAL1_BAUD__tr_baud__c1843k2Hz 13 +#define R_SERIAL1_BAUD__tr_baud__c6250kHz 14 +#define R_SERIAL1_BAUD__tr_baud__reserved 15 +#define R_SERIAL1_BAUD__rec_baud__BITNR 0 +#define R_SERIAL1_BAUD__rec_baud__WIDTH 4 +#define R_SERIAL1_BAUD__rec_baud__c300Hz 0 +#define R_SERIAL1_BAUD__rec_baud__c600Hz 1 +#define R_SERIAL1_BAUD__rec_baud__c1200Hz 2 +#define R_SERIAL1_BAUD__rec_baud__c2400Hz 3 +#define R_SERIAL1_BAUD__rec_baud__c4800Hz 4 +#define R_SERIAL1_BAUD__rec_baud__c9600Hz 5 +#define R_SERIAL1_BAUD__rec_baud__c19k2Hz 6 +#define R_SERIAL1_BAUD__rec_baud__c38k4Hz 7 +#define R_SERIAL1_BAUD__rec_baud__c57k6Hz 8 +#define R_SERIAL1_BAUD__rec_baud__c115k2Hz 9 +#define R_SERIAL1_BAUD__rec_baud__c230k4Hz 10 +#define R_SERIAL1_BAUD__rec_baud__c460k8Hz 11 +#define R_SERIAL1_BAUD__rec_baud__c921k6Hz 12 +#define R_SERIAL1_BAUD__rec_baud__c1843k2Hz 13 +#define R_SERIAL1_BAUD__rec_baud__c6250kHz 14 +#define R_SERIAL1_BAUD__rec_baud__reserved 15 + +#define R_SERIAL1_REC_CTRL (IO_TYPECAST_BYTE 0xb000006a) +#define R_SERIAL1_REC_CTRL__dma_err__BITNR 7 +#define R_SERIAL1_REC_CTRL__dma_err__WIDTH 1 +#define R_SERIAL1_REC_CTRL__dma_err__stop 0 +#define R_SERIAL1_REC_CTRL__dma_err__ignore 1 +#define R_SERIAL1_REC_CTRL__rec_enable__BITNR 6 +#define R_SERIAL1_REC_CTRL__rec_enable__WIDTH 1 +#define R_SERIAL1_REC_CTRL__rec_enable__disable 0 +#define R_SERIAL1_REC_CTRL__rec_enable__enable 1 +#define R_SERIAL1_REC_CTRL__rts___BITNR 5 +#define R_SERIAL1_REC_CTRL__rts___WIDTH 1 +#define R_SERIAL1_REC_CTRL__rts___active 0 +#define R_SERIAL1_REC_CTRL__rts___inactive 1 +#define R_SERIAL1_REC_CTRL__sampling__BITNR 4 +#define R_SERIAL1_REC_CTRL__sampling__WIDTH 1 +#define R_SERIAL1_REC_CTRL__sampling__middle 0 +#define R_SERIAL1_REC_CTRL__sampling__majority 1 +#define R_SERIAL1_REC_CTRL__rec_stick_par__BITNR 3 +#define R_SERIAL1_REC_CTRL__rec_stick_par__WIDTH 1 +#define R_SERIAL1_REC_CTRL__rec_stick_par__normal 0 +#define R_SERIAL1_REC_CTRL__rec_stick_par__stick 1 +#define R_SERIAL1_REC_CTRL__rec_par__BITNR 2 +#define R_SERIAL1_REC_CTRL__rec_par__WIDTH 1 +#define R_SERIAL1_REC_CTRL__rec_par__even 0 +#define R_SERIAL1_REC_CTRL__rec_par__odd 1 +#define R_SERIAL1_REC_CTRL__rec_par_en__BITNR 1 +#define R_SERIAL1_REC_CTRL__rec_par_en__WIDTH 1 +#define R_SERIAL1_REC_CTRL__rec_par_en__disable 0 +#define R_SERIAL1_REC_CTRL__rec_par_en__enable 1 +#define R_SERIAL1_REC_CTRL__rec_bitnr__BITNR 0 +#define R_SERIAL1_REC_CTRL__rec_bitnr__WIDTH 1 +#define R_SERIAL1_REC_CTRL__rec_bitnr__rec_8bit 0 +#define R_SERIAL1_REC_CTRL__rec_bitnr__rec_7bit 1 + +#define R_SERIAL1_TR_CTRL (IO_TYPECAST_BYTE 0xb0000069) +#define R_SERIAL1_TR_CTRL__txd__BITNR 7 +#define R_SERIAL1_TR_CTRL__txd__WIDTH 1 +#define R_SERIAL1_TR_CTRL__tr_enable__BITNR 6 +#define R_SERIAL1_TR_CTRL__tr_enable__WIDTH 1 +#define R_SERIAL1_TR_CTRL__tr_enable__disable 0 +#define R_SERIAL1_TR_CTRL__tr_enable__enable 1 +#define R_SERIAL1_TR_CTRL__auto_cts__BITNR 5 +#define R_SERIAL1_TR_CTRL__auto_cts__WIDTH 1 +#define R_SERIAL1_TR_CTRL__auto_cts__disabled 0 +#define R_SERIAL1_TR_CTRL__auto_cts__active 1 +#define R_SERIAL1_TR_CTRL__stop_bits__BITNR 4 +#define R_SERIAL1_TR_CTRL__stop_bits__WIDTH 1 +#define R_SERIAL1_TR_CTRL__stop_bits__one_bit 0 +#define R_SERIAL1_TR_CTRL__stop_bits__two_bits 1 +#define R_SERIAL1_TR_CTRL__tr_stick_par__BITNR 3 +#define R_SERIAL1_TR_CTRL__tr_stick_par__WIDTH 1 +#define R_SERIAL1_TR_CTRL__tr_stick_par__normal 0 +#define R_SERIAL1_TR_CTRL__tr_stick_par__stick 1 +#define R_SERIAL1_TR_CTRL__tr_par__BITNR 2 +#define R_SERIAL1_TR_CTRL__tr_par__WIDTH 1 +#define R_SERIAL1_TR_CTRL__tr_par__even 0 +#define R_SERIAL1_TR_CTRL__tr_par__odd 1 +#define R_SERIAL1_TR_CTRL__tr_par_en__BITNR 1 +#define R_SERIAL1_TR_CTRL__tr_par_en__WIDTH 1 +#define R_SERIAL1_TR_CTRL__tr_par_en__disable 0 +#define R_SERIAL1_TR_CTRL__tr_par_en__enable 1 +#define R_SERIAL1_TR_CTRL__tr_bitnr__BITNR 0 +#define R_SERIAL1_TR_CTRL__tr_bitnr__WIDTH 1 +#define R_SERIAL1_TR_CTRL__tr_bitnr__tr_8bit 0 +#define R_SERIAL1_TR_CTRL__tr_bitnr__tr_7bit 1 + +#define R_SERIAL1_TR_DATA (IO_TYPECAST_BYTE 0xb0000068) +#define R_SERIAL1_TR_DATA__data_out__BITNR 0 +#define R_SERIAL1_TR_DATA__data_out__WIDTH 8 + +#define R_SERIAL1_READ (IO_TYPECAST_RO_UDWORD 0xb0000068) +#define R_SERIAL1_READ__xoff_detect__BITNR 15 +#define R_SERIAL1_READ__xoff_detect__WIDTH 1 +#define R_SERIAL1_READ__xoff_detect__no_xoff 0 +#define R_SERIAL1_READ__xoff_detect__xoff 1 +#define R_SERIAL1_READ__cts___BITNR 14 +#define R_SERIAL1_READ__cts___WIDTH 1 +#define R_SERIAL1_READ__cts___active 0 +#define R_SERIAL1_READ__cts___inactive 1 +#define R_SERIAL1_READ__tr_ready__BITNR 13 +#define R_SERIAL1_READ__tr_ready__WIDTH 1 +#define R_SERIAL1_READ__tr_ready__full 0 +#define R_SERIAL1_READ__tr_ready__ready 1 +#define R_SERIAL1_READ__rxd__BITNR 12 +#define R_SERIAL1_READ__rxd__WIDTH 1 +#define R_SERIAL1_READ__overrun__BITNR 11 +#define R_SERIAL1_READ__overrun__WIDTH 1 +#define R_SERIAL1_READ__overrun__no 0 +#define R_SERIAL1_READ__overrun__yes 1 +#define R_SERIAL1_READ__par_err__BITNR 10 +#define R_SERIAL1_READ__par_err__WIDTH 1 +#define R_SERIAL1_READ__par_err__no 0 +#define R_SERIAL1_READ__par_err__yes 1 +#define R_SERIAL1_READ__framing_err__BITNR 9 +#define R_SERIAL1_READ__framing_err__WIDTH 1 +#define R_SERIAL1_READ__framing_err__no 0 +#define R_SERIAL1_READ__framing_err__yes 1 +#define R_SERIAL1_READ__data_avail__BITNR 8 +#define R_SERIAL1_READ__data_avail__WIDTH 1 +#define R_SERIAL1_READ__data_avail__no 0 +#define R_SERIAL1_READ__data_avail__yes 1 +#define R_SERIAL1_READ__data_in__BITNR 0 +#define R_SERIAL1_READ__data_in__WIDTH 8 + +#define R_SERIAL1_STATUS (IO_TYPECAST_RO_BYTE 0xb0000069) +#define R_SERIAL1_STATUS__xoff_detect__BITNR 7 +#define R_SERIAL1_STATUS__xoff_detect__WIDTH 1 +#define R_SERIAL1_STATUS__xoff_detect__no_xoff 0 +#define R_SERIAL1_STATUS__xoff_detect__xoff 1 +#define R_SERIAL1_STATUS__cts___BITNR 6 +#define R_SERIAL1_STATUS__cts___WIDTH 1 +#define R_SERIAL1_STATUS__cts___active 0 +#define R_SERIAL1_STATUS__cts___inactive 1 +#define R_SERIAL1_STATUS__tr_ready__BITNR 5 +#define R_SERIAL1_STATUS__tr_ready__WIDTH 1 +#define R_SERIAL1_STATUS__tr_ready__full 0 +#define R_SERIAL1_STATUS__tr_ready__ready 1 +#define R_SERIAL1_STATUS__rxd__BITNR 4 +#define R_SERIAL1_STATUS__rxd__WIDTH 1 +#define R_SERIAL1_STATUS__overrun__BITNR 3 +#define R_SERIAL1_STATUS__overrun__WIDTH 1 +#define R_SERIAL1_STATUS__overrun__no 0 +#define R_SERIAL1_STATUS__overrun__yes 1 +#define R_SERIAL1_STATUS__par_err__BITNR 2 +#define R_SERIAL1_STATUS__par_err__WIDTH 1 +#define R_SERIAL1_STATUS__par_err__no 0 +#define R_SERIAL1_STATUS__par_err__yes 1 +#define R_SERIAL1_STATUS__framing_err__BITNR 1 +#define R_SERIAL1_STATUS__framing_err__WIDTH 1 +#define R_SERIAL1_STATUS__framing_err__no 0 +#define R_SERIAL1_STATUS__framing_err__yes 1 +#define R_SERIAL1_STATUS__data_avail__BITNR 0 +#define R_SERIAL1_STATUS__data_avail__WIDTH 1 +#define R_SERIAL1_STATUS__data_avail__no 0 +#define R_SERIAL1_STATUS__data_avail__yes 1 + +#define R_SERIAL1_REC_DATA (IO_TYPECAST_RO_BYTE 0xb0000068) +#define R_SERIAL1_REC_DATA__data_in__BITNR 0 +#define R_SERIAL1_REC_DATA__data_in__WIDTH 8 + +#define R_SERIAL1_XOFF (IO_TYPECAST_UDWORD 0xb000006c) +#define R_SERIAL1_XOFF__tx_stop__BITNR 9 +#define R_SERIAL1_XOFF__tx_stop__WIDTH 1 +#define R_SERIAL1_XOFF__tx_stop__enable 0 +#define R_SERIAL1_XOFF__tx_stop__stop 1 +#define R_SERIAL1_XOFF__auto_xoff__BITNR 8 +#define R_SERIAL1_XOFF__auto_xoff__WIDTH 1 +#define R_SERIAL1_XOFF__auto_xoff__disable 0 +#define R_SERIAL1_XOFF__auto_xoff__enable 1 +#define R_SERIAL1_XOFF__xoff_char__BITNR 0 +#define R_SERIAL1_XOFF__xoff_char__WIDTH 8 + +#define R_SERIAL2_CTRL (IO_TYPECAST_UDWORD 0xb0000070) +#define R_SERIAL2_CTRL__tr_baud__BITNR 28 +#define R_SERIAL2_CTRL__tr_baud__WIDTH 4 +#define R_SERIAL2_CTRL__tr_baud__c300Hz 0 +#define R_SERIAL2_CTRL__tr_baud__c600Hz 1 +#define R_SERIAL2_CTRL__tr_baud__c1200Hz 2 +#define R_SERIAL2_CTRL__tr_baud__c2400Hz 3 +#define R_SERIAL2_CTRL__tr_baud__c4800Hz 4 +#define R_SERIAL2_CTRL__tr_baud__c9600Hz 5 +#define R_SERIAL2_CTRL__tr_baud__c19k2Hz 6 +#define R_SERIAL2_CTRL__tr_baud__c38k4Hz 7 +#define R_SERIAL2_CTRL__tr_baud__c57k6Hz 8 +#define R_SERIAL2_CTRL__tr_baud__c115k2Hz 9 +#define R_SERIAL2_CTRL__tr_baud__c230k4Hz 10 +#define R_SERIAL2_CTRL__tr_baud__c460k8Hz 11 +#define R_SERIAL2_CTRL__tr_baud__c921k6Hz 12 +#define R_SERIAL2_CTRL__tr_baud__c1843k2Hz 13 +#define R_SERIAL2_CTRL__tr_baud__c6250kHz 14 +#define R_SERIAL2_CTRL__tr_baud__reserved 15 +#define R_SERIAL2_CTRL__rec_baud__BITNR 24 +#define R_SERIAL2_CTRL__rec_baud__WIDTH 4 +#define R_SERIAL2_CTRL__rec_baud__c300Hz 0 +#define R_SERIAL2_CTRL__rec_baud__c600Hz 1 +#define R_SERIAL2_CTRL__rec_baud__c1200Hz 2 +#define R_SERIAL2_CTRL__rec_baud__c2400Hz 3 +#define R_SERIAL2_CTRL__rec_baud__c4800Hz 4 +#define R_SERIAL2_CTRL__rec_baud__c9600Hz 5 +#define R_SERIAL2_CTRL__rec_baud__c19k2Hz 6 +#define R_SERIAL2_CTRL__rec_baud__c38k4Hz 7 +#define R_SERIAL2_CTRL__rec_baud__c57k6Hz 8 +#define R_SERIAL2_CTRL__rec_baud__c115k2Hz 9 +#define R_SERIAL2_CTRL__rec_baud__c230k4Hz 10 +#define R_SERIAL2_CTRL__rec_baud__c460k8Hz 11 +#define R_SERIAL2_CTRL__rec_baud__c921k6Hz 12 +#define R_SERIAL2_CTRL__rec_baud__c1843k2Hz 13 +#define R_SERIAL2_CTRL__rec_baud__c6250kHz 14 +#define R_SERIAL2_CTRL__rec_baud__reserved 15 +#define R_SERIAL2_CTRL__dma_err__BITNR 23 +#define R_SERIAL2_CTRL__dma_err__WIDTH 1 +#define R_SERIAL2_CTRL__dma_err__stop 0 +#define R_SERIAL2_CTRL__dma_err__ignore 1 +#define R_SERIAL2_CTRL__rec_enable__BITNR 22 +#define R_SERIAL2_CTRL__rec_enable__WIDTH 1 +#define R_SERIAL2_CTRL__rec_enable__disable 0 +#define R_SERIAL2_CTRL__rec_enable__enable 1 +#define R_SERIAL2_CTRL__rts___BITNR 21 +#define R_SERIAL2_CTRL__rts___WIDTH 1 +#define R_SERIAL2_CTRL__rts___active 0 +#define R_SERIAL2_CTRL__rts___inactive 1 +#define R_SERIAL2_CTRL__sampling__BITNR 20 +#define R_SERIAL2_CTRL__sampling__WIDTH 1 +#define R_SERIAL2_CTRL__sampling__middle 0 +#define R_SERIAL2_CTRL__sampling__majority 1 +#define R_SERIAL2_CTRL__rec_stick_par__BITNR 19 +#define R_SERIAL2_CTRL__rec_stick_par__WIDTH 1 +#define R_SERIAL2_CTRL__rec_stick_par__normal 0 +#define R_SERIAL2_CTRL__rec_stick_par__stick 1 +#define R_SERIAL2_CTRL__rec_par__BITNR 18 +#define R_SERIAL2_CTRL__rec_par__WIDTH 1 +#define R_SERIAL2_CTRL__rec_par__even 0 +#define R_SERIAL2_CTRL__rec_par__odd 1 +#define R_SERIAL2_CTRL__rec_par_en__BITNR 17 +#define R_SERIAL2_CTRL__rec_par_en__WIDTH 1 +#define R_SERIAL2_CTRL__rec_par_en__disable 0 +#define R_SERIAL2_CTRL__rec_par_en__enable 1 +#define R_SERIAL2_CTRL__rec_bitnr__BITNR 16 +#define R_SERIAL2_CTRL__rec_bitnr__WIDTH 1 +#define R_SERIAL2_CTRL__rec_bitnr__rec_8bit 0 +#define R_SERIAL2_CTRL__rec_bitnr__rec_7bit 1 +#define R_SERIAL2_CTRL__txd__BITNR 15 +#define R_SERIAL2_CTRL__txd__WIDTH 1 +#define R_SERIAL2_CTRL__tr_enable__BITNR 14 +#define R_SERIAL2_CTRL__tr_enable__WIDTH 1 +#define R_SERIAL2_CTRL__tr_enable__disable 0 +#define R_SERIAL2_CTRL__tr_enable__enable 1 +#define R_SERIAL2_CTRL__auto_cts__BITNR 13 +#define R_SERIAL2_CTRL__auto_cts__WIDTH 1 +#define R_SERIAL2_CTRL__auto_cts__disabled 0 +#define R_SERIAL2_CTRL__auto_cts__active 1 +#define R_SERIAL2_CTRL__stop_bits__BITNR 12 +#define R_SERIAL2_CTRL__stop_bits__WIDTH 1 +#define R_SERIAL2_CTRL__stop_bits__one_bit 0 +#define R_SERIAL2_CTRL__stop_bits__two_bits 1 +#define R_SERIAL2_CTRL__tr_stick_par__BITNR 11 +#define R_SERIAL2_CTRL__tr_stick_par__WIDTH 1 +#define R_SERIAL2_CTRL__tr_stick_par__normal 0 +#define R_SERIAL2_CTRL__tr_stick_par__stick 1 +#define R_SERIAL2_CTRL__tr_par__BITNR 10 +#define R_SERIAL2_CTRL__tr_par__WIDTH 1 +#define R_SERIAL2_CTRL__tr_par__even 0 +#define R_SERIAL2_CTRL__tr_par__odd 1 +#define R_SERIAL2_CTRL__tr_par_en__BITNR 9 +#define R_SERIAL2_CTRL__tr_par_en__WIDTH 1 +#define R_SERIAL2_CTRL__tr_par_en__disable 0 +#define R_SERIAL2_CTRL__tr_par_en__enable 1 +#define R_SERIAL2_CTRL__tr_bitnr__BITNR 8 +#define R_SERIAL2_CTRL__tr_bitnr__WIDTH 1 +#define R_SERIAL2_CTRL__tr_bitnr__tr_8bit 0 +#define R_SERIAL2_CTRL__tr_bitnr__tr_7bit 1 +#define R_SERIAL2_CTRL__data_out__BITNR 0 +#define R_SERIAL2_CTRL__data_out__WIDTH 8 + +#define R_SERIAL2_BAUD (IO_TYPECAST_BYTE 0xb0000073) +#define R_SERIAL2_BAUD__tr_baud__BITNR 4 +#define R_SERIAL2_BAUD__tr_baud__WIDTH 4 +#define R_SERIAL2_BAUD__tr_baud__c300Hz 0 +#define R_SERIAL2_BAUD__tr_baud__c600Hz 1 +#define R_SERIAL2_BAUD__tr_baud__c1200Hz 2 +#define R_SERIAL2_BAUD__tr_baud__c2400Hz 3 +#define R_SERIAL2_BAUD__tr_baud__c4800Hz 4 +#define R_SERIAL2_BAUD__tr_baud__c9600Hz 5 +#define R_SERIAL2_BAUD__tr_baud__c19k2Hz 6 +#define R_SERIAL2_BAUD__tr_baud__c38k4Hz 7 +#define R_SERIAL2_BAUD__tr_baud__c57k6Hz 8 +#define R_SERIAL2_BAUD__tr_baud__c115k2Hz 9 +#define R_SERIAL2_BAUD__tr_baud__c230k4Hz 10 +#define R_SERIAL2_BAUD__tr_baud__c460k8Hz 11 +#define R_SERIAL2_BAUD__tr_baud__c921k6Hz 12 +#define R_SERIAL2_BAUD__tr_baud__c1843k2Hz 13 +#define R_SERIAL2_BAUD__tr_baud__c6250kHz 14 +#define R_SERIAL2_BAUD__tr_baud__reserved 15 +#define R_SERIAL2_BAUD__rec_baud__BITNR 0 +#define R_SERIAL2_BAUD__rec_baud__WIDTH 4 +#define R_SERIAL2_BAUD__rec_baud__c300Hz 0 +#define R_SERIAL2_BAUD__rec_baud__c600Hz 1 +#define R_SERIAL2_BAUD__rec_baud__c1200Hz 2 +#define R_SERIAL2_BAUD__rec_baud__c2400Hz 3 +#define R_SERIAL2_BAUD__rec_baud__c4800Hz 4 +#define R_SERIAL2_BAUD__rec_baud__c9600Hz 5 +#define R_SERIAL2_BAUD__rec_baud__c19k2Hz 6 +#define R_SERIAL2_BAUD__rec_baud__c38k4Hz 7 +#define R_SERIAL2_BAUD__rec_baud__c57k6Hz 8 +#define R_SERIAL2_BAUD__rec_baud__c115k2Hz 9 +#define R_SERIAL2_BAUD__rec_baud__c230k4Hz 10 +#define R_SERIAL2_BAUD__rec_baud__c460k8Hz 11 +#define R_SERIAL2_BAUD__rec_baud__c921k6Hz 12 +#define R_SERIAL2_BAUD__rec_baud__c1843k2Hz 13 +#define R_SERIAL2_BAUD__rec_baud__c6250kHz 14 +#define R_SERIAL2_BAUD__rec_baud__reserved 15 + +#define R_SERIAL2_REC_CTRL (IO_TYPECAST_BYTE 0xb0000072) +#define R_SERIAL2_REC_CTRL__dma_err__BITNR 7 +#define R_SERIAL2_REC_CTRL__dma_err__WIDTH 1 +#define R_SERIAL2_REC_CTRL__dma_err__stop 0 +#define R_SERIAL2_REC_CTRL__dma_err__ignore 1 +#define R_SERIAL2_REC_CTRL__rec_enable__BITNR 6 +#define R_SERIAL2_REC_CTRL__rec_enable__WIDTH 1 +#define R_SERIAL2_REC_CTRL__rec_enable__disable 0 +#define R_SERIAL2_REC_CTRL__rec_enable__enable 1 +#define R_SERIAL2_REC_CTRL__rts___BITNR 5 +#define R_SERIAL2_REC_CTRL__rts___WIDTH 1 +#define R_SERIAL2_REC_CTRL__rts___active 0 +#define R_SERIAL2_REC_CTRL__rts___inactive 1 +#define R_SERIAL2_REC_CTRL__sampling__BITNR 4 +#define R_SERIAL2_REC_CTRL__sampling__WIDTH 1 +#define R_SERIAL2_REC_CTRL__sampling__middle 0 +#define R_SERIAL2_REC_CTRL__sampling__majority 1 +#define R_SERIAL2_REC_CTRL__rec_stick_par__BITNR 3 +#define R_SERIAL2_REC_CTRL__rec_stick_par__WIDTH 1 +#define R_SERIAL2_REC_CTRL__rec_stick_par__normal 0 +#define R_SERIAL2_REC_CTRL__rec_stick_par__stick 1 +#define R_SERIAL2_REC_CTRL__rec_par__BITNR 2 +#define R_SERIAL2_REC_CTRL__rec_par__WIDTH 1 +#define R_SERIAL2_REC_CTRL__rec_par__even 0 +#define R_SERIAL2_REC_CTRL__rec_par__odd 1 +#define R_SERIAL2_REC_CTRL__rec_par_en__BITNR 1 +#define R_SERIAL2_REC_CTRL__rec_par_en__WIDTH 1 +#define R_SERIAL2_REC_CTRL__rec_par_en__disable 0 +#define R_SERIAL2_REC_CTRL__rec_par_en__enable 1 +#define R_SERIAL2_REC_CTRL__rec_bitnr__BITNR 0 +#define R_SERIAL2_REC_CTRL__rec_bitnr__WIDTH 1 +#define R_SERIAL2_REC_CTRL__rec_bitnr__rec_8bit 0 +#define R_SERIAL2_REC_CTRL__rec_bitnr__rec_7bit 1 + +#define R_SERIAL2_TR_CTRL (IO_TYPECAST_BYTE 0xb0000071) +#define R_SERIAL2_TR_CTRL__txd__BITNR 7 +#define R_SERIAL2_TR_CTRL__txd__WIDTH 1 +#define R_SERIAL2_TR_CTRL__tr_enable__BITNR 6 +#define R_SERIAL2_TR_CTRL__tr_enable__WIDTH 1 +#define R_SERIAL2_TR_CTRL__tr_enable__disable 0 +#define R_SERIAL2_TR_CTRL__tr_enable__enable 1 +#define R_SERIAL2_TR_CTRL__auto_cts__BITNR 5 +#define R_SERIAL2_TR_CTRL__auto_cts__WIDTH 1 +#define R_SERIAL2_TR_CTRL__auto_cts__disabled 0 +#define R_SERIAL2_TR_CTRL__auto_cts__active 1 +#define R_SERIAL2_TR_CTRL__stop_bits__BITNR 4 +#define R_SERIAL2_TR_CTRL__stop_bits__WIDTH 1 +#define R_SERIAL2_TR_CTRL__stop_bits__one_bit 0 +#define R_SERIAL2_TR_CTRL__stop_bits__two_bits 1 +#define R_SERIAL2_TR_CTRL__tr_stick_par__BITNR 3 +#define R_SERIAL2_TR_CTRL__tr_stick_par__WIDTH 1 +#define R_SERIAL2_TR_CTRL__tr_stick_par__normal 0 +#define R_SERIAL2_TR_CTRL__tr_stick_par__stick 1 +#define R_SERIAL2_TR_CTRL__tr_par__BITNR 2 +#define R_SERIAL2_TR_CTRL__tr_par__WIDTH 1 +#define R_SERIAL2_TR_CTRL__tr_par__even 0 +#define R_SERIAL2_TR_CTRL__tr_par__odd 1 +#define R_SERIAL2_TR_CTRL__tr_par_en__BITNR 1 +#define R_SERIAL2_TR_CTRL__tr_par_en__WIDTH 1 +#define R_SERIAL2_TR_CTRL__tr_par_en__disable 0 +#define R_SERIAL2_TR_CTRL__tr_par_en__enable 1 +#define R_SERIAL2_TR_CTRL__tr_bitnr__BITNR 0 +#define R_SERIAL2_TR_CTRL__tr_bitnr__WIDTH 1 +#define R_SERIAL2_TR_CTRL__tr_bitnr__tr_8bit 0 +#define R_SERIAL2_TR_CTRL__tr_bitnr__tr_7bit 1 + +#define R_SERIAL2_TR_DATA (IO_TYPECAST_BYTE 0xb0000070) +#define R_SERIAL2_TR_DATA__data_out__BITNR 0 +#define R_SERIAL2_TR_DATA__data_out__WIDTH 8 + +#define R_SERIAL2_READ (IO_TYPECAST_RO_UDWORD 0xb0000070) +#define R_SERIAL2_READ__xoff_detect__BITNR 15 +#define R_SERIAL2_READ__xoff_detect__WIDTH 1 +#define R_SERIAL2_READ__xoff_detect__no_xoff 0 +#define R_SERIAL2_READ__xoff_detect__xoff 1 +#define R_SERIAL2_READ__cts___BITNR 14 +#define R_SERIAL2_READ__cts___WIDTH 1 +#define R_SERIAL2_READ__cts___active 0 +#define R_SERIAL2_READ__cts___inactive 1 +#define R_SERIAL2_READ__tr_ready__BITNR 13 +#define R_SERIAL2_READ__tr_ready__WIDTH 1 +#define R_SERIAL2_READ__tr_ready__full 0 +#define R_SERIAL2_READ__tr_ready__ready 1 +#define R_SERIAL2_READ__rxd__BITNR 12 +#define R_SERIAL2_READ__rxd__WIDTH 1 +#define R_SERIAL2_READ__overrun__BITNR 11 +#define R_SERIAL2_READ__overrun__WIDTH 1 +#define R_SERIAL2_READ__overrun__no 0 +#define R_SERIAL2_READ__overrun__yes 1 +#define R_SERIAL2_READ__par_err__BITNR 10 +#define R_SERIAL2_READ__par_err__WIDTH 1 +#define R_SERIAL2_READ__par_err__no 0 +#define R_SERIAL2_READ__par_err__yes 1 +#define R_SERIAL2_READ__framing_err__BITNR 9 +#define R_SERIAL2_READ__framing_err__WIDTH 1 +#define R_SERIAL2_READ__framing_err__no 0 +#define R_SERIAL2_READ__framing_err__yes 1 +#define R_SERIAL2_READ__data_avail__BITNR 8 +#define R_SERIAL2_READ__data_avail__WIDTH 1 +#define R_SERIAL2_READ__data_avail__no 0 +#define R_SERIAL2_READ__data_avail__yes 1 +#define R_SERIAL2_READ__data_in__BITNR 0 +#define R_SERIAL2_READ__data_in__WIDTH 8 + +#define R_SERIAL2_STATUS (IO_TYPECAST_RO_BYTE 0xb0000071) +#define R_SERIAL2_STATUS__xoff_detect__BITNR 7 +#define R_SERIAL2_STATUS__xoff_detect__WIDTH 1 +#define R_SERIAL2_STATUS__xoff_detect__no_xoff 0 +#define R_SERIAL2_STATUS__xoff_detect__xoff 1 +#define R_SERIAL2_STATUS__cts___BITNR 6 +#define R_SERIAL2_STATUS__cts___WIDTH 1 +#define R_SERIAL2_STATUS__cts___active 0 +#define R_SERIAL2_STATUS__cts___inactive 1 +#define R_SERIAL2_STATUS__tr_ready__BITNR 5 +#define R_SERIAL2_STATUS__tr_ready__WIDTH 1 +#define R_SERIAL2_STATUS__tr_ready__full 0 +#define R_SERIAL2_STATUS__tr_ready__ready 1 +#define R_SERIAL2_STATUS__rxd__BITNR 4 +#define R_SERIAL2_STATUS__rxd__WIDTH 1 +#define R_SERIAL2_STATUS__overrun__BITNR 3 +#define R_SERIAL2_STATUS__overrun__WIDTH 1 +#define R_SERIAL2_STATUS__overrun__no 0 +#define R_SERIAL2_STATUS__overrun__yes 1 +#define R_SERIAL2_STATUS__par_err__BITNR 2 +#define R_SERIAL2_STATUS__par_err__WIDTH 1 +#define R_SERIAL2_STATUS__par_err__no 0 +#define R_SERIAL2_STATUS__par_err__yes 1 +#define R_SERIAL2_STATUS__framing_err__BITNR 1 +#define R_SERIAL2_STATUS__framing_err__WIDTH 1 +#define R_SERIAL2_STATUS__framing_err__no 0 +#define R_SERIAL2_STATUS__framing_err__yes 1 +#define R_SERIAL2_STATUS__data_avail__BITNR 0 +#define R_SERIAL2_STATUS__data_avail__WIDTH 1 +#define R_SERIAL2_STATUS__data_avail__no 0 +#define R_SERIAL2_STATUS__data_avail__yes 1 + +#define R_SERIAL2_REC_DATA (IO_TYPECAST_RO_BYTE 0xb0000070) +#define R_SERIAL2_REC_DATA__data_in__BITNR 0 +#define R_SERIAL2_REC_DATA__data_in__WIDTH 8 + +#define R_SERIAL2_XOFF (IO_TYPECAST_UDWORD 0xb0000074) +#define R_SERIAL2_XOFF__tx_stop__BITNR 9 +#define R_SERIAL2_XOFF__tx_stop__WIDTH 1 +#define R_SERIAL2_XOFF__tx_stop__enable 0 +#define R_SERIAL2_XOFF__tx_stop__stop 1 +#define R_SERIAL2_XOFF__auto_xoff__BITNR 8 +#define R_SERIAL2_XOFF__auto_xoff__WIDTH 1 +#define R_SERIAL2_XOFF__auto_xoff__disable 0 +#define R_SERIAL2_XOFF__auto_xoff__enable 1 +#define R_SERIAL2_XOFF__xoff_char__BITNR 0 +#define R_SERIAL2_XOFF__xoff_char__WIDTH 8 + +#define R_SERIAL3_CTRL (IO_TYPECAST_UDWORD 0xb0000078) +#define R_SERIAL3_CTRL__tr_baud__BITNR 28 +#define R_SERIAL3_CTRL__tr_baud__WIDTH 4 +#define R_SERIAL3_CTRL__tr_baud__c300Hz 0 +#define R_SERIAL3_CTRL__tr_baud__c600Hz 1 +#define R_SERIAL3_CTRL__tr_baud__c1200Hz 2 +#define R_SERIAL3_CTRL__tr_baud__c2400Hz 3 +#define R_SERIAL3_CTRL__tr_baud__c4800Hz 4 +#define R_SERIAL3_CTRL__tr_baud__c9600Hz 5 +#define R_SERIAL3_CTRL__tr_baud__c19k2Hz 6 +#define R_SERIAL3_CTRL__tr_baud__c38k4Hz 7 +#define R_SERIAL3_CTRL__tr_baud__c57k6Hz 8 +#define R_SERIAL3_CTRL__tr_baud__c115k2Hz 9 +#define R_SERIAL3_CTRL__tr_baud__c230k4Hz 10 +#define R_SERIAL3_CTRL__tr_baud__c460k8Hz 11 +#define R_SERIAL3_CTRL__tr_baud__c921k6Hz 12 +#define R_SERIAL3_CTRL__tr_baud__c1843k2Hz 13 +#define R_SERIAL3_CTRL__tr_baud__c6250kHz 14 +#define R_SERIAL3_CTRL__tr_baud__reserved 15 +#define R_SERIAL3_CTRL__rec_baud__BITNR 24 +#define R_SERIAL3_CTRL__rec_baud__WIDTH 4 +#define R_SERIAL3_CTRL__rec_baud__c300Hz 0 +#define R_SERIAL3_CTRL__rec_baud__c600Hz 1 +#define R_SERIAL3_CTRL__rec_baud__c1200Hz 2 +#define R_SERIAL3_CTRL__rec_baud__c2400Hz 3 +#define R_SERIAL3_CTRL__rec_baud__c4800Hz 4 +#define R_SERIAL3_CTRL__rec_baud__c9600Hz 5 +#define R_SERIAL3_CTRL__rec_baud__c19k2Hz 6 +#define R_SERIAL3_CTRL__rec_baud__c38k4Hz 7 +#define R_SERIAL3_CTRL__rec_baud__c57k6Hz 8 +#define R_SERIAL3_CTRL__rec_baud__c115k2Hz 9 +#define R_SERIAL3_CTRL__rec_baud__c230k4Hz 10 +#define R_SERIAL3_CTRL__rec_baud__c460k8Hz 11 +#define R_SERIAL3_CTRL__rec_baud__c921k6Hz 12 +#define R_SERIAL3_CTRL__rec_baud__c1843k2Hz 13 +#define R_SERIAL3_CTRL__rec_baud__c6250kHz 14 +#define R_SERIAL3_CTRL__rec_baud__reserved 15 +#define R_SERIAL3_CTRL__dma_err__BITNR 23 +#define R_SERIAL3_CTRL__dma_err__WIDTH 1 +#define R_SERIAL3_CTRL__dma_err__stop 0 +#define R_SERIAL3_CTRL__dma_err__ignore 1 +#define R_SERIAL3_CTRL__rec_enable__BITNR 22 +#define R_SERIAL3_CTRL__rec_enable__WIDTH 1 +#define R_SERIAL3_CTRL__rec_enable__disable 0 +#define R_SERIAL3_CTRL__rec_enable__enable 1 +#define R_SERIAL3_CTRL__rts___BITNR 21 +#define R_SERIAL3_CTRL__rts___WIDTH 1 +#define R_SERIAL3_CTRL__rts___active 0 +#define R_SERIAL3_CTRL__rts___inactive 1 +#define R_SERIAL3_CTRL__sampling__BITNR 20 +#define R_SERIAL3_CTRL__sampling__WIDTH 1 +#define R_SERIAL3_CTRL__sampling__middle 0 +#define R_SERIAL3_CTRL__sampling__majority 1 +#define R_SERIAL3_CTRL__rec_stick_par__BITNR 19 +#define R_SERIAL3_CTRL__rec_stick_par__WIDTH 1 +#define R_SERIAL3_CTRL__rec_stick_par__normal 0 +#define R_SERIAL3_CTRL__rec_stick_par__stick 1 +#define R_SERIAL3_CTRL__rec_par__BITNR 18 +#define R_SERIAL3_CTRL__rec_par__WIDTH 1 +#define R_SERIAL3_CTRL__rec_par__even 0 +#define R_SERIAL3_CTRL__rec_par__odd 1 +#define R_SERIAL3_CTRL__rec_par_en__BITNR 17 +#define R_SERIAL3_CTRL__rec_par_en__WIDTH 1 +#define R_SERIAL3_CTRL__rec_par_en__disable 0 +#define R_SERIAL3_CTRL__rec_par_en__enable 1 +#define R_SERIAL3_CTRL__rec_bitnr__BITNR 16 +#define R_SERIAL3_CTRL__rec_bitnr__WIDTH 1 +#define R_SERIAL3_CTRL__rec_bitnr__rec_8bit 0 +#define R_SERIAL3_CTRL__rec_bitnr__rec_7bit 1 +#define R_SERIAL3_CTRL__txd__BITNR 15 +#define R_SERIAL3_CTRL__txd__WIDTH 1 +#define R_SERIAL3_CTRL__tr_enable__BITNR 14 +#define R_SERIAL3_CTRL__tr_enable__WIDTH 1 +#define R_SERIAL3_CTRL__tr_enable__disable 0 +#define R_SERIAL3_CTRL__tr_enable__enable 1 +#define R_SERIAL3_CTRL__auto_cts__BITNR 13 +#define R_SERIAL3_CTRL__auto_cts__WIDTH 1 +#define R_SERIAL3_CTRL__auto_cts__disabled 0 +#define R_SERIAL3_CTRL__auto_cts__active 1 +#define R_SERIAL3_CTRL__stop_bits__BITNR 12 +#define R_SERIAL3_CTRL__stop_bits__WIDTH 1 +#define R_SERIAL3_CTRL__stop_bits__one_bit 0 +#define R_SERIAL3_CTRL__stop_bits__two_bits 1 +#define R_SERIAL3_CTRL__tr_stick_par__BITNR 11 +#define R_SERIAL3_CTRL__tr_stick_par__WIDTH 1 +#define R_SERIAL3_CTRL__tr_stick_par__normal 0 +#define R_SERIAL3_CTRL__tr_stick_par__stick 1 +#define R_SERIAL3_CTRL__tr_par__BITNR 10 +#define R_SERIAL3_CTRL__tr_par__WIDTH 1 +#define R_SERIAL3_CTRL__tr_par__even 0 +#define R_SERIAL3_CTRL__tr_par__odd 1 +#define R_SERIAL3_CTRL__tr_par_en__BITNR 9 +#define R_SERIAL3_CTRL__tr_par_en__WIDTH 1 +#define R_SERIAL3_CTRL__tr_par_en__disable 0 +#define R_SERIAL3_CTRL__tr_par_en__enable 1 +#define R_SERIAL3_CTRL__tr_bitnr__BITNR 8 +#define R_SERIAL3_CTRL__tr_bitnr__WIDTH 1 +#define R_SERIAL3_CTRL__tr_bitnr__tr_8bit 0 +#define R_SERIAL3_CTRL__tr_bitnr__tr_7bit 1 +#define R_SERIAL3_CTRL__data_out__BITNR 0 +#define R_SERIAL3_CTRL__data_out__WIDTH 8 + +#define R_SERIAL3_BAUD (IO_TYPECAST_BYTE 0xb000007b) +#define R_SERIAL3_BAUD__tr_baud__BITNR 4 +#define R_SERIAL3_BAUD__tr_baud__WIDTH 4 +#define R_SERIAL3_BAUD__tr_baud__c300Hz 0 +#define R_SERIAL3_BAUD__tr_baud__c600Hz 1 +#define R_SERIAL3_BAUD__tr_baud__c1200Hz 2 +#define R_SERIAL3_BAUD__tr_baud__c2400Hz 3 +#define R_SERIAL3_BAUD__tr_baud__c4800Hz 4 +#define R_SERIAL3_BAUD__tr_baud__c9600Hz 5 +#define R_SERIAL3_BAUD__tr_baud__c19k2Hz 6 +#define R_SERIAL3_BAUD__tr_baud__c38k4Hz 7 +#define R_SERIAL3_BAUD__tr_baud__c57k6Hz 8 +#define R_SERIAL3_BAUD__tr_baud__c115k2Hz 9 +#define R_SERIAL3_BAUD__tr_baud__c230k4Hz 10 +#define R_SERIAL3_BAUD__tr_baud__c460k8Hz 11 +#define R_SERIAL3_BAUD__tr_baud__c921k6Hz 12 +#define R_SERIAL3_BAUD__tr_baud__c1843k2Hz 13 +#define R_SERIAL3_BAUD__tr_baud__c6250kHz 14 +#define R_SERIAL3_BAUD__tr_baud__reserved 15 +#define R_SERIAL3_BAUD__rec_baud__BITNR 0 +#define R_SERIAL3_BAUD__rec_baud__WIDTH 4 +#define R_SERIAL3_BAUD__rec_baud__c300Hz 0 +#define R_SERIAL3_BAUD__rec_baud__c600Hz 1 +#define R_SERIAL3_BAUD__rec_baud__c1200Hz 2 +#define R_SERIAL3_BAUD__rec_baud__c2400Hz 3 +#define R_SERIAL3_BAUD__rec_baud__c4800Hz 4 +#define R_SERIAL3_BAUD__rec_baud__c9600Hz 5 +#define R_SERIAL3_BAUD__rec_baud__c19k2Hz 6 +#define R_SERIAL3_BAUD__rec_baud__c38k4Hz 7 +#define R_SERIAL3_BAUD__rec_baud__c57k6Hz 8 +#define R_SERIAL3_BAUD__rec_baud__c115k2Hz 9 +#define R_SERIAL3_BAUD__rec_baud__c230k4Hz 10 +#define R_SERIAL3_BAUD__rec_baud__c460k8Hz 11 +#define R_SERIAL3_BAUD__rec_baud__c921k6Hz 12 +#define R_SERIAL3_BAUD__rec_baud__c1843k2Hz 13 +#define R_SERIAL3_BAUD__rec_baud__c6250kHz 14 +#define R_SERIAL3_BAUD__rec_baud__reserved 15 + +#define R_SERIAL3_REC_CTRL (IO_TYPECAST_BYTE 0xb000007a) +#define R_SERIAL3_REC_CTRL__dma_err__BITNR 7 +#define R_SERIAL3_REC_CTRL__dma_err__WIDTH 1 +#define R_SERIAL3_REC_CTRL__dma_err__stop 0 +#define R_SERIAL3_REC_CTRL__dma_err__ignore 1 +#define R_SERIAL3_REC_CTRL__rec_enable__BITNR 6 +#define R_SERIAL3_REC_CTRL__rec_enable__WIDTH 1 +#define R_SERIAL3_REC_CTRL__rec_enable__disable 0 +#define R_SERIAL3_REC_CTRL__rec_enable__enable 1 +#define R_SERIAL3_REC_CTRL__rts___BITNR 5 +#define R_SERIAL3_REC_CTRL__rts___WIDTH 1 +#define R_SERIAL3_REC_CTRL__rts___active 0 +#define R_SERIAL3_REC_CTRL__rts___inactive 1 +#define R_SERIAL3_REC_CTRL__sampling__BITNR 4 +#define R_SERIAL3_REC_CTRL__sampling__WIDTH 1 +#define R_SERIAL3_REC_CTRL__sampling__middle 0 +#define R_SERIAL3_REC_CTRL__sampling__majority 1 +#define R_SERIAL3_REC_CTRL__rec_stick_par__BITNR 3 +#define R_SERIAL3_REC_CTRL__rec_stick_par__WIDTH 1 +#define R_SERIAL3_REC_CTRL__rec_stick_par__normal 0 +#define R_SERIAL3_REC_CTRL__rec_stick_par__stick 1 +#define R_SERIAL3_REC_CTRL__rec_par__BITNR 2 +#define R_SERIAL3_REC_CTRL__rec_par__WIDTH 1 +#define R_SERIAL3_REC_CTRL__rec_par__even 0 +#define R_SERIAL3_REC_CTRL__rec_par__odd 1 +#define R_SERIAL3_REC_CTRL__rec_par_en__BITNR 1 +#define R_SERIAL3_REC_CTRL__rec_par_en__WIDTH 1 +#define R_SERIAL3_REC_CTRL__rec_par_en__disable 0 +#define R_SERIAL3_REC_CTRL__rec_par_en__enable 1 +#define R_SERIAL3_REC_CTRL__rec_bitnr__BITNR 0 +#define R_SERIAL3_REC_CTRL__rec_bitnr__WIDTH 1 +#define R_SERIAL3_REC_CTRL__rec_bitnr__rec_8bit 0 +#define R_SERIAL3_REC_CTRL__rec_bitnr__rec_7bit 1 + +#define R_SERIAL3_TR_CTRL (IO_TYPECAST_BYTE 0xb0000079) +#define R_SERIAL3_TR_CTRL__txd__BITNR 7 +#define R_SERIAL3_TR_CTRL__txd__WIDTH 1 +#define R_SERIAL3_TR_CTRL__tr_enable__BITNR 6 +#define R_SERIAL3_TR_CTRL__tr_enable__WIDTH 1 +#define R_SERIAL3_TR_CTRL__tr_enable__disable 0 +#define R_SERIAL3_TR_CTRL__tr_enable__enable 1 +#define R_SERIAL3_TR_CTRL__auto_cts__BITNR 5 +#define R_SERIAL3_TR_CTRL__auto_cts__WIDTH 1 +#define R_SERIAL3_TR_CTRL__auto_cts__disabled 0 +#define R_SERIAL3_TR_CTRL__auto_cts__active 1 +#define R_SERIAL3_TR_CTRL__stop_bits__BITNR 4 +#define R_SERIAL3_TR_CTRL__stop_bits__WIDTH 1 +#define R_SERIAL3_TR_CTRL__stop_bits__one_bit 0 +#define R_SERIAL3_TR_CTRL__stop_bits__two_bits 1 +#define R_SERIAL3_TR_CTRL__tr_stick_par__BITNR 3 +#define R_SERIAL3_TR_CTRL__tr_stick_par__WIDTH 1 +#define R_SERIAL3_TR_CTRL__tr_stick_par__normal 0 +#define R_SERIAL3_TR_CTRL__tr_stick_par__stick 1 +#define R_SERIAL3_TR_CTRL__tr_par__BITNR 2 +#define R_SERIAL3_TR_CTRL__tr_par__WIDTH 1 +#define R_SERIAL3_TR_CTRL__tr_par__even 0 +#define R_SERIAL3_TR_CTRL__tr_par__odd 1 +#define R_SERIAL3_TR_CTRL__tr_par_en__BITNR 1 +#define R_SERIAL3_TR_CTRL__tr_par_en__WIDTH 1 +#define R_SERIAL3_TR_CTRL__tr_par_en__disable 0 +#define R_SERIAL3_TR_CTRL__tr_par_en__enable 1 +#define R_SERIAL3_TR_CTRL__tr_bitnr__BITNR 0 +#define R_SERIAL3_TR_CTRL__tr_bitnr__WIDTH 1 +#define R_SERIAL3_TR_CTRL__tr_bitnr__tr_8bit 0 +#define R_SERIAL3_TR_CTRL__tr_bitnr__tr_7bit 1 + +#define R_SERIAL3_TR_DATA (IO_TYPECAST_BYTE 0xb0000078) +#define R_SERIAL3_TR_DATA__data_out__BITNR 0 +#define R_SERIAL3_TR_DATA__data_out__WIDTH 8 + +#define R_SERIAL3_READ (IO_TYPECAST_RO_UDWORD 0xb0000078) +#define R_SERIAL3_READ__xoff_detect__BITNR 15 +#define R_SERIAL3_READ__xoff_detect__WIDTH 1 +#define R_SERIAL3_READ__xoff_detect__no_xoff 0 +#define R_SERIAL3_READ__xoff_detect__xoff 1 +#define R_SERIAL3_READ__cts___BITNR 14 +#define R_SERIAL3_READ__cts___WIDTH 1 +#define R_SERIAL3_READ__cts___active 0 +#define R_SERIAL3_READ__cts___inactive 1 +#define R_SERIAL3_READ__tr_ready__BITNR 13 +#define R_SERIAL3_READ__tr_ready__WIDTH 1 +#define R_SERIAL3_READ__tr_ready__full 0 +#define R_SERIAL3_READ__tr_ready__ready 1 +#define R_SERIAL3_READ__rxd__BITNR 12 +#define R_SERIAL3_READ__rxd__WIDTH 1 +#define R_SERIAL3_READ__overrun__BITNR 11 +#define R_SERIAL3_READ__overrun__WIDTH 1 +#define R_SERIAL3_READ__overrun__no 0 +#define R_SERIAL3_READ__overrun__yes 1 +#define R_SERIAL3_READ__par_err__BITNR 10 +#define R_SERIAL3_READ__par_err__WIDTH 1 +#define R_SERIAL3_READ__par_err__no 0 +#define R_SERIAL3_READ__par_err__yes 1 +#define R_SERIAL3_READ__framing_err__BITNR 9 +#define R_SERIAL3_READ__framing_err__WIDTH 1 +#define R_SERIAL3_READ__framing_err__no 0 +#define R_SERIAL3_READ__framing_err__yes 1 +#define R_SERIAL3_READ__data_avail__BITNR 8 +#define R_SERIAL3_READ__data_avail__WIDTH 1 +#define R_SERIAL3_READ__data_avail__no 0 +#define R_SERIAL3_READ__data_avail__yes 1 +#define R_SERIAL3_READ__data_in__BITNR 0 +#define R_SERIAL3_READ__data_in__WIDTH 8 + +#define R_SERIAL3_STATUS (IO_TYPECAST_RO_BYTE 0xb0000079) +#define R_SERIAL3_STATUS__xoff_detect__BITNR 7 +#define R_SERIAL3_STATUS__xoff_detect__WIDTH 1 +#define R_SERIAL3_STATUS__xoff_detect__no_xoff 0 +#define R_SERIAL3_STATUS__xoff_detect__xoff 1 +#define R_SERIAL3_STATUS__cts___BITNR 6 +#define R_SERIAL3_STATUS__cts___WIDTH 1 +#define R_SERIAL3_STATUS__cts___active 0 +#define R_SERIAL3_STATUS__cts___inactive 1 +#define R_SERIAL3_STATUS__tr_ready__BITNR 5 +#define R_SERIAL3_STATUS__tr_ready__WIDTH 1 +#define R_SERIAL3_STATUS__tr_ready__full 0 +#define R_SERIAL3_STATUS__tr_ready__ready 1 +#define R_SERIAL3_STATUS__rxd__BITNR 4 +#define R_SERIAL3_STATUS__rxd__WIDTH 1 +#define R_SERIAL3_STATUS__overrun__BITNR 3 +#define R_SERIAL3_STATUS__overrun__WIDTH 1 +#define R_SERIAL3_STATUS__overrun__no 0 +#define R_SERIAL3_STATUS__overrun__yes 1 +#define R_SERIAL3_STATUS__par_err__BITNR 2 +#define R_SERIAL3_STATUS__par_err__WIDTH 1 +#define R_SERIAL3_STATUS__par_err__no 0 +#define R_SERIAL3_STATUS__par_err__yes 1 +#define R_SERIAL3_STATUS__framing_err__BITNR 1 +#define R_SERIAL3_STATUS__framing_err__WIDTH 1 +#define R_SERIAL3_STATUS__framing_err__no 0 +#define R_SERIAL3_STATUS__framing_err__yes 1 +#define R_SERIAL3_STATUS__data_avail__BITNR 0 +#define R_SERIAL3_STATUS__data_avail__WIDTH 1 +#define R_SERIAL3_STATUS__data_avail__no 0 +#define R_SERIAL3_STATUS__data_avail__yes 1 + +#define R_SERIAL3_REC_DATA (IO_TYPECAST_RO_BYTE 0xb0000078) +#define R_SERIAL3_REC_DATA__data_in__BITNR 0 +#define R_SERIAL3_REC_DATA__data_in__WIDTH 8 + +#define R_SERIAL3_XOFF (IO_TYPECAST_UDWORD 0xb000007c) +#define R_SERIAL3_XOFF__tx_stop__BITNR 9 +#define R_SERIAL3_XOFF__tx_stop__WIDTH 1 +#define R_SERIAL3_XOFF__tx_stop__enable 0 +#define R_SERIAL3_XOFF__tx_stop__stop 1 +#define R_SERIAL3_XOFF__auto_xoff__BITNR 8 +#define R_SERIAL3_XOFF__auto_xoff__WIDTH 1 +#define R_SERIAL3_XOFF__auto_xoff__disable 0 +#define R_SERIAL3_XOFF__auto_xoff__enable 1 +#define R_SERIAL3_XOFF__xoff_char__BITNR 0 +#define R_SERIAL3_XOFF__xoff_char__WIDTH 8 + +#define R_ALT_SER_BAUDRATE (IO_TYPECAST_UDWORD 0xb000005c) +#define R_ALT_SER_BAUDRATE__ser3_tr__BITNR 28 +#define R_ALT_SER_BAUDRATE__ser3_tr__WIDTH 2 +#define R_ALT_SER_BAUDRATE__ser3_tr__normal 0 +#define R_ALT_SER_BAUDRATE__ser3_tr__prescale 1 +#define R_ALT_SER_BAUDRATE__ser3_tr__extern 2 +#define R_ALT_SER_BAUDRATE__ser3_tr__timer 3 +#define R_ALT_SER_BAUDRATE__ser3_rec__BITNR 24 +#define R_ALT_SER_BAUDRATE__ser3_rec__WIDTH 2 +#define R_ALT_SER_BAUDRATE__ser3_rec__normal 0 +#define R_ALT_SER_BAUDRATE__ser3_rec__prescale 1 +#define R_ALT_SER_BAUDRATE__ser3_rec__extern 2 +#define R_ALT_SER_BAUDRATE__ser3_rec__timer 3 +#define R_ALT_SER_BAUDRATE__ser2_tr__BITNR 20 +#define R_ALT_SER_BAUDRATE__ser2_tr__WIDTH 2 +#define R_ALT_SER_BAUDRATE__ser2_tr__normal 0 +#define R_ALT_SER_BAUDRATE__ser2_tr__prescale 1 +#define R_ALT_SER_BAUDRATE__ser2_tr__extern 2 +#define R_ALT_SER_BAUDRATE__ser2_tr__timer 3 +#define R_ALT_SER_BAUDRATE__ser2_rec__BITNR 16 +#define R_ALT_SER_BAUDRATE__ser2_rec__WIDTH 2 +#define R_ALT_SER_BAUDRATE__ser2_rec__normal 0 +#define R_ALT_SER_BAUDRATE__ser2_rec__prescale 1 +#define R_ALT_SER_BAUDRATE__ser2_rec__extern 2 +#define R_ALT_SER_BAUDRATE__ser2_rec__timer 3 +#define R_ALT_SER_BAUDRATE__ser1_tr__BITNR 12 +#define R_ALT_SER_BAUDRATE__ser1_tr__WIDTH 2 +#define R_ALT_SER_BAUDRATE__ser1_tr__normal 0 +#define R_ALT_SER_BAUDRATE__ser1_tr__prescale 1 +#define R_ALT_SER_BAUDRATE__ser1_tr__extern 2 +#define R_ALT_SER_BAUDRATE__ser1_tr__timer 3 +#define R_ALT_SER_BAUDRATE__ser1_rec__BITNR 8 +#define R_ALT_SER_BAUDRATE__ser1_rec__WIDTH 2 +#define R_ALT_SER_BAUDRATE__ser1_rec__normal 0 +#define R_ALT_SER_BAUDRATE__ser1_rec__prescale 1 +#define R_ALT_SER_BAUDRATE__ser1_rec__extern 2 +#define R_ALT_SER_BAUDRATE__ser1_rec__timer 3 +#define R_ALT_SER_BAUDRATE__ser0_tr__BITNR 4 +#define R_ALT_SER_BAUDRATE__ser0_tr__WIDTH 2 +#define R_ALT_SER_BAUDRATE__ser0_tr__normal 0 +#define R_ALT_SER_BAUDRATE__ser0_tr__prescale 1 +#define R_ALT_SER_BAUDRATE__ser0_tr__extern 2 +#define R_ALT_SER_BAUDRATE__ser0_tr__timer 3 +#define R_ALT_SER_BAUDRATE__ser0_rec__BITNR 0 +#define R_ALT_SER_BAUDRATE__ser0_rec__WIDTH 2 +#define R_ALT_SER_BAUDRATE__ser0_rec__normal 0 +#define R_ALT_SER_BAUDRATE__ser0_rec__prescale 1 +#define R_ALT_SER_BAUDRATE__ser0_rec__extern 2 +#define R_ALT_SER_BAUDRATE__ser0_rec__timer 3 + +/* +!* Network interface registers +!*/ + +#define R_NETWORK_SA_0 (IO_TYPECAST_UDWORD 0xb0000080) +#define R_NETWORK_SA_0__ma0_low__BITNR 0 +#define R_NETWORK_SA_0__ma0_low__WIDTH 32 + +#define R_NETWORK_SA_1 (IO_TYPECAST_UDWORD 0xb0000084) +#define R_NETWORK_SA_1__ma1_low__BITNR 16 +#define R_NETWORK_SA_1__ma1_low__WIDTH 16 +#define R_NETWORK_SA_1__ma0_high__BITNR 0 +#define R_NETWORK_SA_1__ma0_high__WIDTH 16 + +#define R_NETWORK_SA_2 (IO_TYPECAST_UDWORD 0xb0000088) +#define R_NETWORK_SA_2__ma1_high__BITNR 0 +#define R_NETWORK_SA_2__ma1_high__WIDTH 32 + +#define R_NETWORK_GA_0 (IO_TYPECAST_UDWORD 0xb000008c) +#define R_NETWORK_GA_0__ga_low__BITNR 0 +#define R_NETWORK_GA_0__ga_low__WIDTH 32 + +#define R_NETWORK_GA_1 (IO_TYPECAST_UDWORD 0xb0000090) +#define R_NETWORK_GA_1__ga_high__BITNR 0 +#define R_NETWORK_GA_1__ga_high__WIDTH 32 + +#define R_NETWORK_REC_CONFIG (IO_TYPECAST_UDWORD 0xb0000094) +#define R_NETWORK_REC_CONFIG__max_size__BITNR 10 +#define R_NETWORK_REC_CONFIG__max_size__WIDTH 1 +#define R_NETWORK_REC_CONFIG__max_size__size1518 0 +#define R_NETWORK_REC_CONFIG__max_size__size1522 1 +#define R_NETWORK_REC_CONFIG__duplex__BITNR 9 +#define R_NETWORK_REC_CONFIG__duplex__WIDTH 1 +#define R_NETWORK_REC_CONFIG__duplex__full 1 +#define R_NETWORK_REC_CONFIG__duplex__half 0 +#define R_NETWORK_REC_CONFIG__bad_crc__BITNR 8 +#define R_NETWORK_REC_CONFIG__bad_crc__WIDTH 1 +#define R_NETWORK_REC_CONFIG__bad_crc__receive 1 +#define R_NETWORK_REC_CONFIG__bad_crc__discard 0 +#define R_NETWORK_REC_CONFIG__oversize__BITNR 7 +#define R_NETWORK_REC_CONFIG__oversize__WIDTH 1 +#define R_NETWORK_REC_CONFIG__oversize__receive 1 +#define R_NETWORK_REC_CONFIG__oversize__discard 0 +#define R_NETWORK_REC_CONFIG__undersize__BITNR 6 +#define R_NETWORK_REC_CONFIG__undersize__WIDTH 1 +#define R_NETWORK_REC_CONFIG__undersize__receive 1 +#define R_NETWORK_REC_CONFIG__undersize__discard 0 +#define R_NETWORK_REC_CONFIG__all_roots__BITNR 5 +#define R_NETWORK_REC_CONFIG__all_roots__WIDTH 1 +#define R_NETWORK_REC_CONFIG__all_roots__receive 1 +#define R_NETWORK_REC_CONFIG__all_roots__discard 0 +#define R_NETWORK_REC_CONFIG__tr_broadcast__BITNR 4 +#define R_NETWORK_REC_CONFIG__tr_broadcast__WIDTH 1 +#define R_NETWORK_REC_CONFIG__tr_broadcast__receive 1 +#define R_NETWORK_REC_CONFIG__tr_broadcast__discard 0 +#define R_NETWORK_REC_CONFIG__broadcast__BITNR 3 +#define R_NETWORK_REC_CONFIG__broadcast__WIDTH 1 +#define R_NETWORK_REC_CONFIG__broadcast__receive 1 +#define R_NETWORK_REC_CONFIG__broadcast__discard 0 +#define R_NETWORK_REC_CONFIG__individual__BITNR 2 +#define R_NETWORK_REC_CONFIG__individual__WIDTH 1 +#define R_NETWORK_REC_CONFIG__individual__receive 1 +#define R_NETWORK_REC_CONFIG__individual__discard 0 +#define R_NETWORK_REC_CONFIG__ma1__BITNR 1 +#define R_NETWORK_REC_CONFIG__ma1__WIDTH 1 +#define R_NETWORK_REC_CONFIG__ma1__enable 1 +#define R_NETWORK_REC_CONFIG__ma1__disable 0 +#define R_NETWORK_REC_CONFIG__ma0__BITNR 0 +#define R_NETWORK_REC_CONFIG__ma0__WIDTH 1 +#define R_NETWORK_REC_CONFIG__ma0__enable 1 +#define R_NETWORK_REC_CONFIG__ma0__disable 0 + +#define R_NETWORK_GEN_CONFIG (IO_TYPECAST_UDWORD 0xb0000098) +#define R_NETWORK_GEN_CONFIG__loopback__BITNR 5 +#define R_NETWORK_GEN_CONFIG__loopback__WIDTH 1 +#define R_NETWORK_GEN_CONFIG__loopback__on 1 +#define R_NETWORK_GEN_CONFIG__loopback__off 0 +#define R_NETWORK_GEN_CONFIG__frame__BITNR 4 +#define R_NETWORK_GEN_CONFIG__frame__WIDTH 1 +#define R_NETWORK_GEN_CONFIG__frame__tokenr 1 +#define R_NETWORK_GEN_CONFIG__frame__ether 0 +#define R_NETWORK_GEN_CONFIG__vg__BITNR 3 +#define R_NETWORK_GEN_CONFIG__vg__WIDTH 1 +#define R_NETWORK_GEN_CONFIG__vg__on 1 +#define R_NETWORK_GEN_CONFIG__vg__off 0 +#define R_NETWORK_GEN_CONFIG__phy__BITNR 1 +#define R_NETWORK_GEN_CONFIG__phy__WIDTH 2 +#define R_NETWORK_GEN_CONFIG__phy__sni 0 +#define R_NETWORK_GEN_CONFIG__phy__mii_clk 1 +#define R_NETWORK_GEN_CONFIG__phy__mii_err 2 +#define R_NETWORK_GEN_CONFIG__phy__mii_req 3 +#define R_NETWORK_GEN_CONFIG__enable__BITNR 0 +#define R_NETWORK_GEN_CONFIG__enable__WIDTH 1 +#define R_NETWORK_GEN_CONFIG__enable__on 1 +#define R_NETWORK_GEN_CONFIG__enable__off 0 + +#define R_NETWORK_TR_CTRL (IO_TYPECAST_UDWORD 0xb000009c) +#define R_NETWORK_TR_CTRL__clr_error__BITNR 8 +#define R_NETWORK_TR_CTRL__clr_error__WIDTH 1 +#define R_NETWORK_TR_CTRL__clr_error__clr 1 +#define R_NETWORK_TR_CTRL__clr_error__nop 0 +#define R_NETWORK_TR_CTRL__delay__BITNR 5 +#define R_NETWORK_TR_CTRL__delay__WIDTH 1 +#define R_NETWORK_TR_CTRL__delay__d2us 1 +#define R_NETWORK_TR_CTRL__delay__none 0 +#define R_NETWORK_TR_CTRL__cancel__BITNR 4 +#define R_NETWORK_TR_CTRL__cancel__WIDTH 1 +#define R_NETWORK_TR_CTRL__cancel__do 1 +#define R_NETWORK_TR_CTRL__cancel__dont 0 +#define R_NETWORK_TR_CTRL__cd__BITNR 3 +#define R_NETWORK_TR_CTRL__cd__WIDTH 1 +#define R_NETWORK_TR_CTRL__cd__enable 0 +#define R_NETWORK_TR_CTRL__cd__disable 1 +#define R_NETWORK_TR_CTRL__cd__ack_col 0 +#define R_NETWORK_TR_CTRL__cd__ack_crs 1 +#define R_NETWORK_TR_CTRL__retry__BITNR 2 +#define R_NETWORK_TR_CTRL__retry__WIDTH 1 +#define R_NETWORK_TR_CTRL__retry__enable 0 +#define R_NETWORK_TR_CTRL__retry__disable 1 +#define R_NETWORK_TR_CTRL__pad__BITNR 1 +#define R_NETWORK_TR_CTRL__pad__WIDTH 1 +#define R_NETWORK_TR_CTRL__pad__enable 1 +#define R_NETWORK_TR_CTRL__pad__disable 0 +#define R_NETWORK_TR_CTRL__crc__BITNR 0 +#define R_NETWORK_TR_CTRL__crc__WIDTH 1 +#define R_NETWORK_TR_CTRL__crc__enable 0 +#define R_NETWORK_TR_CTRL__crc__disable 1 + +#define R_NETWORK_MGM_CTRL (IO_TYPECAST_UDWORD 0xb00000a0) +#define R_NETWORK_MGM_CTRL__txd_pins__BITNR 4 +#define R_NETWORK_MGM_CTRL__txd_pins__WIDTH 4 +#define R_NETWORK_MGM_CTRL__txer_pin__BITNR 3 +#define R_NETWORK_MGM_CTRL__txer_pin__WIDTH 1 +#define R_NETWORK_MGM_CTRL__mdck__BITNR 2 +#define R_NETWORK_MGM_CTRL__mdck__WIDTH 1 +#define R_NETWORK_MGM_CTRL__mdoe__BITNR 1 +#define R_NETWORK_MGM_CTRL__mdoe__WIDTH 1 +#define R_NETWORK_MGM_CTRL__mdoe__enable 1 +#define R_NETWORK_MGM_CTRL__mdoe__disable 0 +#define R_NETWORK_MGM_CTRL__mdio__BITNR 0 +#define R_NETWORK_MGM_CTRL__mdio__WIDTH 1 + +#define R_NETWORK_STAT (IO_TYPECAST_RO_UDWORD 0xb00000a0) +#define R_NETWORK_STAT__rxd_pins__BITNR 4 +#define R_NETWORK_STAT__rxd_pins__WIDTH 4 +#define R_NETWORK_STAT__rxer__BITNR 3 +#define R_NETWORK_STAT__rxer__WIDTH 1 +#define R_NETWORK_STAT__underrun__BITNR 2 +#define R_NETWORK_STAT__underrun__WIDTH 1 +#define R_NETWORK_STAT__underrun__yes 1 +#define R_NETWORK_STAT__underrun__no 0 +#define R_NETWORK_STAT__exc_col__BITNR 1 +#define R_NETWORK_STAT__exc_col__WIDTH 1 +#define R_NETWORK_STAT__exc_col__yes 1 +#define R_NETWORK_STAT__exc_col__no 0 +#define R_NETWORK_STAT__mdio__BITNR 0 +#define R_NETWORK_STAT__mdio__WIDTH 1 + +#define R_REC_COUNTERS (IO_TYPECAST_RO_UDWORD 0xb00000a4) +#define R_REC_COUNTERS__congestion__BITNR 24 +#define R_REC_COUNTERS__congestion__WIDTH 8 +#define R_REC_COUNTERS__oversize__BITNR 16 +#define R_REC_COUNTERS__oversize__WIDTH 8 +#define R_REC_COUNTERS__alignment_error__BITNR 8 +#define R_REC_COUNTERS__alignment_error__WIDTH 8 +#define R_REC_COUNTERS__crc_error__BITNR 0 +#define R_REC_COUNTERS__crc_error__WIDTH 8 + +#define R_TR_COUNTERS (IO_TYPECAST_RO_UDWORD 0xb00000a8) +#define R_TR_COUNTERS__deferred__BITNR 24 +#define R_TR_COUNTERS__deferred__WIDTH 8 +#define R_TR_COUNTERS__late_col__BITNR 16 +#define R_TR_COUNTERS__late_col__WIDTH 8 +#define R_TR_COUNTERS__multiple_col__BITNR 8 +#define R_TR_COUNTERS__multiple_col__WIDTH 8 +#define R_TR_COUNTERS__single_col__BITNR 0 +#define R_TR_COUNTERS__single_col__WIDTH 8 + +#define R_PHY_COUNTERS (IO_TYPECAST_RO_UDWORD 0xb00000ac) +#define R_PHY_COUNTERS__sqe_test_error__BITNR 8 +#define R_PHY_COUNTERS__sqe_test_error__WIDTH 8 +#define R_PHY_COUNTERS__carrier_loss__BITNR 0 +#define R_PHY_COUNTERS__carrier_loss__WIDTH 8 + +/* +!* Parallel printer port registers +!*/ + +#define R_PAR0_CTRL_DATA (IO_TYPECAST_UDWORD 0xb0000040) +#define R_PAR0_CTRL_DATA__peri_int__BITNR 24 +#define R_PAR0_CTRL_DATA__peri_int__WIDTH 1 +#define R_PAR0_CTRL_DATA__peri_int__ack 1 +#define R_PAR0_CTRL_DATA__peri_int__nop 0 +#define R_PAR0_CTRL_DATA__oe__BITNR 20 +#define R_PAR0_CTRL_DATA__oe__WIDTH 1 +#define R_PAR0_CTRL_DATA__oe__enable 1 +#define R_PAR0_CTRL_DATA__oe__disable 0 +#define R_PAR0_CTRL_DATA__seli__BITNR 19 +#define R_PAR0_CTRL_DATA__seli__WIDTH 1 +#define R_PAR0_CTRL_DATA__seli__active 1 +#define R_PAR0_CTRL_DATA__seli__inactive 0 +#define R_PAR0_CTRL_DATA__autofd__BITNR 18 +#define R_PAR0_CTRL_DATA__autofd__WIDTH 1 +#define R_PAR0_CTRL_DATA__autofd__active 1 +#define R_PAR0_CTRL_DATA__autofd__inactive 0 +#define R_PAR0_CTRL_DATA__strb__BITNR 17 +#define R_PAR0_CTRL_DATA__strb__WIDTH 1 +#define R_PAR0_CTRL_DATA__strb__active 1 +#define R_PAR0_CTRL_DATA__strb__inactive 0 +#define R_PAR0_CTRL_DATA__init__BITNR 16 +#define R_PAR0_CTRL_DATA__init__WIDTH 1 +#define R_PAR0_CTRL_DATA__init__active 1 +#define R_PAR0_CTRL_DATA__init__inactive 0 +#define R_PAR0_CTRL_DATA__ecp_cmd__BITNR 8 +#define R_PAR0_CTRL_DATA__ecp_cmd__WIDTH 1 +#define R_PAR0_CTRL_DATA__ecp_cmd__command 1 +#define R_PAR0_CTRL_DATA__ecp_cmd__data 0 +#define R_PAR0_CTRL_DATA__data__BITNR 0 +#define R_PAR0_CTRL_DATA__data__WIDTH 8 + +#define R_PAR0_CTRL (IO_TYPECAST_BYTE 0xb0000042) +#define R_PAR0_CTRL__ctrl__BITNR 0 +#define R_PAR0_CTRL__ctrl__WIDTH 5 + +#define R_PAR0_STATUS_DATA (IO_TYPECAST_RO_UDWORD 0xb0000040) +#define R_PAR0_STATUS_DATA__mode__BITNR 29 +#define R_PAR0_STATUS_DATA__mode__WIDTH 3 +#define R_PAR0_STATUS_DATA__mode__manual 0 +#define R_PAR0_STATUS_DATA__mode__centronics 1 +#define R_PAR0_STATUS_DATA__mode__fastbyte 2 +#define R_PAR0_STATUS_DATA__mode__nibble 3 +#define R_PAR0_STATUS_DATA__mode__byte 4 +#define R_PAR0_STATUS_DATA__mode__ecp_fwd 5 +#define R_PAR0_STATUS_DATA__mode__ecp_rev 6 +#define R_PAR0_STATUS_DATA__mode__off 7 +#define R_PAR0_STATUS_DATA__mode__epp_wr1 5 +#define R_PAR0_STATUS_DATA__mode__epp_wr2 6 +#define R_PAR0_STATUS_DATA__mode__epp_wr3 7 +#define R_PAR0_STATUS_DATA__mode__epp_rd 0 +#define R_PAR0_STATUS_DATA__perr__BITNR 28 +#define R_PAR0_STATUS_DATA__perr__WIDTH 1 +#define R_PAR0_STATUS_DATA__perr__active 1 +#define R_PAR0_STATUS_DATA__perr__inactive 0 +#define R_PAR0_STATUS_DATA__ack__BITNR 27 +#define R_PAR0_STATUS_DATA__ack__WIDTH 1 +#define R_PAR0_STATUS_DATA__ack__active 0 +#define R_PAR0_STATUS_DATA__ack__inactive 1 +#define R_PAR0_STATUS_DATA__busy__BITNR 26 +#define R_PAR0_STATUS_DATA__busy__WIDTH 1 +#define R_PAR0_STATUS_DATA__busy__active 1 +#define R_PAR0_STATUS_DATA__busy__inactive 0 +#define R_PAR0_STATUS_DATA__fault__BITNR 25 +#define R_PAR0_STATUS_DATA__fault__WIDTH 1 +#define R_PAR0_STATUS_DATA__fault__active 0 +#define R_PAR0_STATUS_DATA__fault__inactive 1 +#define R_PAR0_STATUS_DATA__sel__BITNR 24 +#define R_PAR0_STATUS_DATA__sel__WIDTH 1 +#define R_PAR0_STATUS_DATA__sel__active 1 +#define R_PAR0_STATUS_DATA__sel__inactive 0 +#define R_PAR0_STATUS_DATA__ext_mode__BITNR 23 +#define R_PAR0_STATUS_DATA__ext_mode__WIDTH 1 +#define R_PAR0_STATUS_DATA__ext_mode__enable 1 +#define R_PAR0_STATUS_DATA__ext_mode__disable 0 +#define R_PAR0_STATUS_DATA__ecp_16__BITNR 22 +#define R_PAR0_STATUS_DATA__ecp_16__WIDTH 1 +#define R_PAR0_STATUS_DATA__ecp_16__active 1 +#define R_PAR0_STATUS_DATA__ecp_16__inactive 0 +#define R_PAR0_STATUS_DATA__tr_rdy__BITNR 17 +#define R_PAR0_STATUS_DATA__tr_rdy__WIDTH 1 +#define R_PAR0_STATUS_DATA__tr_rdy__ready 1 +#define R_PAR0_STATUS_DATA__tr_rdy__busy 0 +#define R_PAR0_STATUS_DATA__dav__BITNR 16 +#define R_PAR0_STATUS_DATA__dav__WIDTH 1 +#define R_PAR0_STATUS_DATA__dav__data 1 +#define R_PAR0_STATUS_DATA__dav__nodata 0 +#define R_PAR0_STATUS_DATA__ecp_cmd__BITNR 8 +#define R_PAR0_STATUS_DATA__ecp_cmd__WIDTH 1 +#define R_PAR0_STATUS_DATA__ecp_cmd__command 1 +#define R_PAR0_STATUS_DATA__ecp_cmd__data 0 +#define R_PAR0_STATUS_DATA__data__BITNR 0 +#define R_PAR0_STATUS_DATA__data__WIDTH 8 + +#define R_PAR0_STATUS (IO_TYPECAST_RO_UWORD 0xb0000042) +#define R_PAR0_STATUS__mode__BITNR 13 +#define R_PAR0_STATUS__mode__WIDTH 3 +#define R_PAR0_STATUS__mode__manual 0 +#define R_PAR0_STATUS__mode__centronics 1 +#define R_PAR0_STATUS__mode__fastbyte 2 +#define R_PAR0_STATUS__mode__nibble 3 +#define R_PAR0_STATUS__mode__byte 4 +#define R_PAR0_STATUS__mode__ecp_fwd 5 +#define R_PAR0_STATUS__mode__ecp_rev 6 +#define R_PAR0_STATUS__mode__off 7 +#define R_PAR0_STATUS__mode__epp_wr1 5 +#define R_PAR0_STATUS__mode__epp_wr2 6 +#define R_PAR0_STATUS__mode__epp_wr3 7 +#define R_PAR0_STATUS__mode__epp_rd 0 +#define R_PAR0_STATUS__perr__BITNR 12 +#define R_PAR0_STATUS__perr__WIDTH 1 +#define R_PAR0_STATUS__perr__active 1 +#define R_PAR0_STATUS__perr__inactive 0 +#define R_PAR0_STATUS__ack__BITNR 11 +#define R_PAR0_STATUS__ack__WIDTH 1 +#define R_PAR0_STATUS__ack__active 0 +#define R_PAR0_STATUS__ack__inactive 1 +#define R_PAR0_STATUS__busy__BITNR 10 +#define R_PAR0_STATUS__busy__WIDTH 1 +#define R_PAR0_STATUS__busy__active 1 +#define R_PAR0_STATUS__busy__inactive 0 +#define R_PAR0_STATUS__fault__BITNR 9 +#define R_PAR0_STATUS__fault__WIDTH 1 +#define R_PAR0_STATUS__fault__active 0 +#define R_PAR0_STATUS__fault__inactive 1 +#define R_PAR0_STATUS__sel__BITNR 8 +#define R_PAR0_STATUS__sel__WIDTH 1 +#define R_PAR0_STATUS__sel__active 1 +#define R_PAR0_STATUS__sel__inactive 0 +#define R_PAR0_STATUS__ext_mode__BITNR 7 +#define R_PAR0_STATUS__ext_mode__WIDTH 1 +#define R_PAR0_STATUS__ext_mode__enable 1 +#define R_PAR0_STATUS__ext_mode__disable 0 +#define R_PAR0_STATUS__ecp_16__BITNR 6 +#define R_PAR0_STATUS__ecp_16__WIDTH 1 +#define R_PAR0_STATUS__ecp_16__active 1 +#define R_PAR0_STATUS__ecp_16__inactive 0 +#define R_PAR0_STATUS__tr_rdy__BITNR 1 +#define R_PAR0_STATUS__tr_rdy__WIDTH 1 +#define R_PAR0_STATUS__tr_rdy__ready 1 +#define R_PAR0_STATUS__tr_rdy__busy 0 +#define R_PAR0_STATUS__dav__BITNR 0 +#define R_PAR0_STATUS__dav__WIDTH 1 +#define R_PAR0_STATUS__dav__data 1 +#define R_PAR0_STATUS__dav__nodata 0 + +#define R_PAR_ECP16_DATA (IO_TYPECAST_UWORD 0xb0000040) +#define R_PAR_ECP16_DATA__data__BITNR 0 +#define R_PAR_ECP16_DATA__data__WIDTH 16 + +#define R_PAR0_CONFIG (IO_TYPECAST_UDWORD 0xb0000044) +#define R_PAR0_CONFIG__ioe__BITNR 25 +#define R_PAR0_CONFIG__ioe__WIDTH 1 +#define R_PAR0_CONFIG__ioe__inv 1 +#define R_PAR0_CONFIG__ioe__noninv 0 +#define R_PAR0_CONFIG__iseli__BITNR 24 +#define R_PAR0_CONFIG__iseli__WIDTH 1 +#define R_PAR0_CONFIG__iseli__inv 1 +#define R_PAR0_CONFIG__iseli__noninv 0 +#define R_PAR0_CONFIG__iautofd__BITNR 23 +#define R_PAR0_CONFIG__iautofd__WIDTH 1 +#define R_PAR0_CONFIG__iautofd__inv 1 +#define R_PAR0_CONFIG__iautofd__noninv 0 +#define R_PAR0_CONFIG__istrb__BITNR 22 +#define R_PAR0_CONFIG__istrb__WIDTH 1 +#define R_PAR0_CONFIG__istrb__inv 1 +#define R_PAR0_CONFIG__istrb__noninv 0 +#define R_PAR0_CONFIG__iinit__BITNR 21 +#define R_PAR0_CONFIG__iinit__WIDTH 1 +#define R_PAR0_CONFIG__iinit__inv 1 +#define R_PAR0_CONFIG__iinit__noninv 0 +#define R_PAR0_CONFIG__iperr__BITNR 20 +#define R_PAR0_CONFIG__iperr__WIDTH 1 +#define R_PAR0_CONFIG__iperr__inv 1 +#define R_PAR0_CONFIG__iperr__noninv 0 +#define R_PAR0_CONFIG__iack__BITNR 19 +#define R_PAR0_CONFIG__iack__WIDTH 1 +#define R_PAR0_CONFIG__iack__inv 1 +#define R_PAR0_CONFIG__iack__noninv 0 +#define R_PAR0_CONFIG__ibusy__BITNR 18 +#define R_PAR0_CONFIG__ibusy__WIDTH 1 +#define R_PAR0_CONFIG__ibusy__inv 1 +#define R_PAR0_CONFIG__ibusy__noninv 0 +#define R_PAR0_CONFIG__ifault__BITNR 17 +#define R_PAR0_CONFIG__ifault__WIDTH 1 +#define R_PAR0_CONFIG__ifault__inv 1 +#define R_PAR0_CONFIG__ifault__noninv 0 +#define R_PAR0_CONFIG__isel__BITNR 16 +#define R_PAR0_CONFIG__isel__WIDTH 1 +#define R_PAR0_CONFIG__isel__inv 1 +#define R_PAR0_CONFIG__isel__noninv 0 +#define R_PAR0_CONFIG__ext_mode__BITNR 11 +#define R_PAR0_CONFIG__ext_mode__WIDTH 1 +#define R_PAR0_CONFIG__ext_mode__enable 1 +#define R_PAR0_CONFIG__ext_mode__disable 0 +#define R_PAR0_CONFIG__wide__BITNR 10 +#define R_PAR0_CONFIG__wide__WIDTH 1 +#define R_PAR0_CONFIG__wide__enable 1 +#define R_PAR0_CONFIG__wide__disable 0 +#define R_PAR0_CONFIG__dma__BITNR 9 +#define R_PAR0_CONFIG__dma__WIDTH 1 +#define R_PAR0_CONFIG__dma__enable 1 +#define R_PAR0_CONFIG__dma__disable 0 +#define R_PAR0_CONFIG__rle_in__BITNR 8 +#define R_PAR0_CONFIG__rle_in__WIDTH 1 +#define R_PAR0_CONFIG__rle_in__enable 1 +#define R_PAR0_CONFIG__rle_in__disable 0 +#define R_PAR0_CONFIG__rle_out__BITNR 7 +#define R_PAR0_CONFIG__rle_out__WIDTH 1 +#define R_PAR0_CONFIG__rle_out__enable 1 +#define R_PAR0_CONFIG__rle_out__disable 0 +#define R_PAR0_CONFIG__enable__BITNR 6 +#define R_PAR0_CONFIG__enable__WIDTH 1 +#define R_PAR0_CONFIG__enable__on 1 +#define R_PAR0_CONFIG__enable__reset 0 +#define R_PAR0_CONFIG__force__BITNR 5 +#define R_PAR0_CONFIG__force__WIDTH 1 +#define R_PAR0_CONFIG__force__on 1 +#define R_PAR0_CONFIG__force__off 0 +#define R_PAR0_CONFIG__ign_ack__BITNR 4 +#define R_PAR0_CONFIG__ign_ack__WIDTH 1 +#define R_PAR0_CONFIG__ign_ack__ignore 1 +#define R_PAR0_CONFIG__ign_ack__wait 0 +#define R_PAR0_CONFIG__oe_ack__BITNR 3 +#define R_PAR0_CONFIG__oe_ack__WIDTH 1 +#define R_PAR0_CONFIG__oe_ack__wait_oe 1 +#define R_PAR0_CONFIG__oe_ack__dont_wait 0 +#define R_PAR0_CONFIG__oe_ack__epp_addr 1 +#define R_PAR0_CONFIG__oe_ack__epp_data 0 +#define R_PAR0_CONFIG__epp_addr_data__BITNR 3 +#define R_PAR0_CONFIG__epp_addr_data__WIDTH 1 +#define R_PAR0_CONFIG__epp_addr_data__wait_oe 1 +#define R_PAR0_CONFIG__epp_addr_data__dont_wait 0 +#define R_PAR0_CONFIG__epp_addr_data__epp_addr 1 +#define R_PAR0_CONFIG__epp_addr_data__epp_data 0 +#define R_PAR0_CONFIG__mode__BITNR 0 +#define R_PAR0_CONFIG__mode__WIDTH 3 +#define R_PAR0_CONFIG__mode__manual 0 +#define R_PAR0_CONFIG__mode__centronics 1 +#define R_PAR0_CONFIG__mode__fastbyte 2 +#define R_PAR0_CONFIG__mode__nibble 3 +#define R_PAR0_CONFIG__mode__byte 4 +#define R_PAR0_CONFIG__mode__ecp_fwd 5 +#define R_PAR0_CONFIG__mode__ecp_rev 6 +#define R_PAR0_CONFIG__mode__off 7 +#define R_PAR0_CONFIG__mode__epp_wr1 5 +#define R_PAR0_CONFIG__mode__epp_wr2 6 +#define R_PAR0_CONFIG__mode__epp_wr3 7 +#define R_PAR0_CONFIG__mode__epp_rd 0 + +#define R_PAR0_DELAY (IO_TYPECAST_UDWORD 0xb0000048) +#define R_PAR0_DELAY__fine_hold__BITNR 21 +#define R_PAR0_DELAY__fine_hold__WIDTH 3 +#define R_PAR0_DELAY__hold__BITNR 16 +#define R_PAR0_DELAY__hold__WIDTH 5 +#define R_PAR0_DELAY__fine_strb__BITNR 13 +#define R_PAR0_DELAY__fine_strb__WIDTH 3 +#define R_PAR0_DELAY__strobe__BITNR 8 +#define R_PAR0_DELAY__strobe__WIDTH 5 +#define R_PAR0_DELAY__fine_setup__BITNR 5 +#define R_PAR0_DELAY__fine_setup__WIDTH 3 +#define R_PAR0_DELAY__setup__BITNR 0 +#define R_PAR0_DELAY__setup__WIDTH 5 + +#define R_PAR1_CTRL_DATA (IO_TYPECAST_UDWORD 0xb0000050) +#define R_PAR1_CTRL_DATA__peri_int__BITNR 24 +#define R_PAR1_CTRL_DATA__peri_int__WIDTH 1 +#define R_PAR1_CTRL_DATA__peri_int__ack 1 +#define R_PAR1_CTRL_DATA__peri_int__nop 0 +#define R_PAR1_CTRL_DATA__oe__BITNR 20 +#define R_PAR1_CTRL_DATA__oe__WIDTH 1 +#define R_PAR1_CTRL_DATA__oe__enable 1 +#define R_PAR1_CTRL_DATA__oe__disable 0 +#define R_PAR1_CTRL_DATA__seli__BITNR 19 +#define R_PAR1_CTRL_DATA__seli__WIDTH 1 +#define R_PAR1_CTRL_DATA__seli__active 1 +#define R_PAR1_CTRL_DATA__seli__inactive 0 +#define R_PAR1_CTRL_DATA__autofd__BITNR 18 +#define R_PAR1_CTRL_DATA__autofd__WIDTH 1 +#define R_PAR1_CTRL_DATA__autofd__active 1 +#define R_PAR1_CTRL_DATA__autofd__inactive 0 +#define R_PAR1_CTRL_DATA__strb__BITNR 17 +#define R_PAR1_CTRL_DATA__strb__WIDTH 1 +#define R_PAR1_CTRL_DATA__strb__active 1 +#define R_PAR1_CTRL_DATA__strb__inactive 0 +#define R_PAR1_CTRL_DATA__init__BITNR 16 +#define R_PAR1_CTRL_DATA__init__WIDTH 1 +#define R_PAR1_CTRL_DATA__init__active 1 +#define R_PAR1_CTRL_DATA__init__inactive 0 +#define R_PAR1_CTRL_DATA__ecp_cmd__BITNR 8 +#define R_PAR1_CTRL_DATA__ecp_cmd__WIDTH 1 +#define R_PAR1_CTRL_DATA__ecp_cmd__command 1 +#define R_PAR1_CTRL_DATA__ecp_cmd__data 0 +#define R_PAR1_CTRL_DATA__data__BITNR 0 +#define R_PAR1_CTRL_DATA__data__WIDTH 8 + +#define R_PAR1_CTRL (IO_TYPECAST_BYTE 0xb0000052) +#define R_PAR1_CTRL__ctrl__BITNR 0 +#define R_PAR1_CTRL__ctrl__WIDTH 5 + +#define R_PAR1_STATUS_DATA (IO_TYPECAST_RO_UDWORD 0xb0000050) +#define R_PAR1_STATUS_DATA__mode__BITNR 29 +#define R_PAR1_STATUS_DATA__mode__WIDTH 3 +#define R_PAR1_STATUS_DATA__mode__manual 0 +#define R_PAR1_STATUS_DATA__mode__centronics 1 +#define R_PAR1_STATUS_DATA__mode__fastbyte 2 +#define R_PAR1_STATUS_DATA__mode__nibble 3 +#define R_PAR1_STATUS_DATA__mode__byte 4 +#define R_PAR1_STATUS_DATA__mode__ecp_fwd 5 +#define R_PAR1_STATUS_DATA__mode__ecp_rev 6 +#define R_PAR1_STATUS_DATA__mode__off 7 +#define R_PAR1_STATUS_DATA__mode__epp_wr1 5 +#define R_PAR1_STATUS_DATA__mode__epp_wr2 6 +#define R_PAR1_STATUS_DATA__mode__epp_wr3 7 +#define R_PAR1_STATUS_DATA__mode__epp_rd 0 +#define R_PAR1_STATUS_DATA__perr__BITNR 28 +#define R_PAR1_STATUS_DATA__perr__WIDTH 1 +#define R_PAR1_STATUS_DATA__perr__active 1 +#define R_PAR1_STATUS_DATA__perr__inactive 0 +#define R_PAR1_STATUS_DATA__ack__BITNR 27 +#define R_PAR1_STATUS_DATA__ack__WIDTH 1 +#define R_PAR1_STATUS_DATA__ack__active 0 +#define R_PAR1_STATUS_DATA__ack__inactive 1 +#define R_PAR1_STATUS_DATA__busy__BITNR 26 +#define R_PAR1_STATUS_DATA__busy__WIDTH 1 +#define R_PAR1_STATUS_DATA__busy__active 1 +#define R_PAR1_STATUS_DATA__busy__inactive 0 +#define R_PAR1_STATUS_DATA__fault__BITNR 25 +#define R_PAR1_STATUS_DATA__fault__WIDTH 1 +#define R_PAR1_STATUS_DATA__fault__active 0 +#define R_PAR1_STATUS_DATA__fault__inactive 1 +#define R_PAR1_STATUS_DATA__sel__BITNR 24 +#define R_PAR1_STATUS_DATA__sel__WIDTH 1 +#define R_PAR1_STATUS_DATA__sel__active 1 +#define R_PAR1_STATUS_DATA__sel__inactive 0 +#define R_PAR1_STATUS_DATA__ext_mode__BITNR 23 +#define R_PAR1_STATUS_DATA__ext_mode__WIDTH 1 +#define R_PAR1_STATUS_DATA__ext_mode__enable 1 +#define R_PAR1_STATUS_DATA__ext_mode__disable 0 +#define R_PAR1_STATUS_DATA__tr_rdy__BITNR 17 +#define R_PAR1_STATUS_DATA__tr_rdy__WIDTH 1 +#define R_PAR1_STATUS_DATA__tr_rdy__ready 1 +#define R_PAR1_STATUS_DATA__tr_rdy__busy 0 +#define R_PAR1_STATUS_DATA__dav__BITNR 16 +#define R_PAR1_STATUS_DATA__dav__WIDTH 1 +#define R_PAR1_STATUS_DATA__dav__data 1 +#define R_PAR1_STATUS_DATA__dav__nodata 0 +#define R_PAR1_STATUS_DATA__ecp_cmd__BITNR 8 +#define R_PAR1_STATUS_DATA__ecp_cmd__WIDTH 1 +#define R_PAR1_STATUS_DATA__ecp_cmd__command 1 +#define R_PAR1_STATUS_DATA__ecp_cmd__data 0 +#define R_PAR1_STATUS_DATA__data__BITNR 0 +#define R_PAR1_STATUS_DATA__data__WIDTH 8 + +#define R_PAR1_STATUS (IO_TYPECAST_RO_UWORD 0xb0000052) +#define R_PAR1_STATUS__mode__BITNR 13 +#define R_PAR1_STATUS__mode__WIDTH 3 +#define R_PAR1_STATUS__mode__manual 0 +#define R_PAR1_STATUS__mode__centronics 1 +#define R_PAR1_STATUS__mode__fastbyte 2 +#define R_PAR1_STATUS__mode__nibble 3 +#define R_PAR1_STATUS__mode__byte 4 +#define R_PAR1_STATUS__mode__ecp_fwd 5 +#define R_PAR1_STATUS__mode__ecp_rev 6 +#define R_PAR1_STATUS__mode__off 7 +#define R_PAR1_STATUS__mode__epp_wr1 5 +#define R_PAR1_STATUS__mode__epp_wr2 6 +#define R_PAR1_STATUS__mode__epp_wr3 7 +#define R_PAR1_STATUS__mode__epp_rd 0 +#define R_PAR1_STATUS__perr__BITNR 12 +#define R_PAR1_STATUS__perr__WIDTH 1 +#define R_PAR1_STATUS__perr__active 1 +#define R_PAR1_STATUS__perr__inactive 0 +#define R_PAR1_STATUS__ack__BITNR 11 +#define R_PAR1_STATUS__ack__WIDTH 1 +#define R_PAR1_STATUS__ack__active 0 +#define R_PAR1_STATUS__ack__inactive 1 +#define R_PAR1_STATUS__busy__BITNR 10 +#define R_PAR1_STATUS__busy__WIDTH 1 +#define R_PAR1_STATUS__busy__active 1 +#define R_PAR1_STATUS__busy__inactive 0 +#define R_PAR1_STATUS__fault__BITNR 9 +#define R_PAR1_STATUS__fault__WIDTH 1 +#define R_PAR1_STATUS__fault__active 0 +#define R_PAR1_STATUS__fault__inactive 1 +#define R_PAR1_STATUS__sel__BITNR 8 +#define R_PAR1_STATUS__sel__WIDTH 1 +#define R_PAR1_STATUS__sel__active 1 +#define R_PAR1_STATUS__sel__inactive 0 +#define R_PAR1_STATUS__ext_mode__BITNR 7 +#define R_PAR1_STATUS__ext_mode__WIDTH 1 +#define R_PAR1_STATUS__ext_mode__enable 1 +#define R_PAR1_STATUS__ext_mode__disable 0 +#define R_PAR1_STATUS__tr_rdy__BITNR 1 +#define R_PAR1_STATUS__tr_rdy__WIDTH 1 +#define R_PAR1_STATUS__tr_rdy__ready 1 +#define R_PAR1_STATUS__tr_rdy__busy 0 +#define R_PAR1_STATUS__dav__BITNR 0 +#define R_PAR1_STATUS__dav__WIDTH 1 +#define R_PAR1_STATUS__dav__data 1 +#define R_PAR1_STATUS__dav__nodata 0 + +#define R_PAR1_CONFIG (IO_TYPECAST_UDWORD 0xb0000054) +#define R_PAR1_CONFIG__ioe__BITNR 25 +#define R_PAR1_CONFIG__ioe__WIDTH 1 +#define R_PAR1_CONFIG__ioe__inv 1 +#define R_PAR1_CONFIG__ioe__noninv 0 +#define R_PAR1_CONFIG__iseli__BITNR 24 +#define R_PAR1_CONFIG__iseli__WIDTH 1 +#define R_PAR1_CONFIG__iseli__inv 1 +#define R_PAR1_CONFIG__iseli__noninv 0 +#define R_PAR1_CONFIG__iautofd__BITNR 23 +#define R_PAR1_CONFIG__iautofd__WIDTH 1 +#define R_PAR1_CONFIG__iautofd__inv 1 +#define R_PAR1_CONFIG__iautofd__noninv 0 +#define R_PAR1_CONFIG__istrb__BITNR 22 +#define R_PAR1_CONFIG__istrb__WIDTH 1 +#define R_PAR1_CONFIG__istrb__inv 1 +#define R_PAR1_CONFIG__istrb__noninv 0 +#define R_PAR1_CONFIG__iinit__BITNR 21 +#define R_PAR1_CONFIG__iinit__WIDTH 1 +#define R_PAR1_CONFIG__iinit__inv 1 +#define R_PAR1_CONFIG__iinit__noninv 0 +#define R_PAR1_CONFIG__iperr__BITNR 20 +#define R_PAR1_CONFIG__iperr__WIDTH 1 +#define R_PAR1_CONFIG__iperr__inv 1 +#define R_PAR1_CONFIG__iperr__noninv 0 +#define R_PAR1_CONFIG__iack__BITNR 19 +#define R_PAR1_CONFIG__iack__WIDTH 1 +#define R_PAR1_CONFIG__iack__inv 1 +#define R_PAR1_CONFIG__iack__noninv 0 +#define R_PAR1_CONFIG__ibusy__BITNR 18 +#define R_PAR1_CONFIG__ibusy__WIDTH 1 +#define R_PAR1_CONFIG__ibusy__inv 1 +#define R_PAR1_CONFIG__ibusy__noninv 0 +#define R_PAR1_CONFIG__ifault__BITNR 17 +#define R_PAR1_CONFIG__ifault__WIDTH 1 +#define R_PAR1_CONFIG__ifault__inv 1 +#define R_PAR1_CONFIG__ifault__noninv 0 +#define R_PAR1_CONFIG__isel__BITNR 16 +#define R_PAR1_CONFIG__isel__WIDTH 1 +#define R_PAR1_CONFIG__isel__inv 1 +#define R_PAR1_CONFIG__isel__noninv 0 +#define R_PAR1_CONFIG__ext_mode__BITNR 11 +#define R_PAR1_CONFIG__ext_mode__WIDTH 1 +#define R_PAR1_CONFIG__ext_mode__enable 1 +#define R_PAR1_CONFIG__ext_mode__disable 0 +#define R_PAR1_CONFIG__dma__BITNR 9 +#define R_PAR1_CONFIG__dma__WIDTH 1 +#define R_PAR1_CONFIG__dma__enable 1 +#define R_PAR1_CONFIG__dma__disable 0 +#define R_PAR1_CONFIG__rle_in__BITNR 8 +#define R_PAR1_CONFIG__rle_in__WIDTH 1 +#define R_PAR1_CONFIG__rle_in__enable 1 +#define R_PAR1_CONFIG__rle_in__disable 0 +#define R_PAR1_CONFIG__rle_out__BITNR 7 +#define R_PAR1_CONFIG__rle_out__WIDTH 1 +#define R_PAR1_CONFIG__rle_out__enable 1 +#define R_PAR1_CONFIG__rle_out__disable 0 +#define R_PAR1_CONFIG__enable__BITNR 6 +#define R_PAR1_CONFIG__enable__WIDTH 1 +#define R_PAR1_CONFIG__enable__on 1 +#define R_PAR1_CONFIG__enable__reset 0 +#define R_PAR1_CONFIG__force__BITNR 5 +#define R_PAR1_CONFIG__force__WIDTH 1 +#define R_PAR1_CONFIG__force__on 1 +#define R_PAR1_CONFIG__force__off 0 +#define R_PAR1_CONFIG__ign_ack__BITNR 4 +#define R_PAR1_CONFIG__ign_ack__WIDTH 1 +#define R_PAR1_CONFIG__ign_ack__ignore 1 +#define R_PAR1_CONFIG__ign_ack__wait 0 +#define R_PAR1_CONFIG__oe_ack__BITNR 3 +#define R_PAR1_CONFIG__oe_ack__WIDTH 1 +#define R_PAR1_CONFIG__oe_ack__wait_oe 1 +#define R_PAR1_CONFIG__oe_ack__dont_wait 0 +#define R_PAR1_CONFIG__oe_ack__epp_addr 1 +#define R_PAR1_CONFIG__oe_ack__epp_data 0 +#define R_PAR1_CONFIG__epp_addr_data__BITNR 3 +#define R_PAR1_CONFIG__epp_addr_data__WIDTH 1 +#define R_PAR1_CONFIG__epp_addr_data__wait_oe 1 +#define R_PAR1_CONFIG__epp_addr_data__dont_wait 0 +#define R_PAR1_CONFIG__epp_addr_data__epp_addr 1 +#define R_PAR1_CONFIG__epp_addr_data__epp_data 0 +#define R_PAR1_CONFIG__mode__BITNR 0 +#define R_PAR1_CONFIG__mode__WIDTH 3 +#define R_PAR1_CONFIG__mode__manual 0 +#define R_PAR1_CONFIG__mode__centronics 1 +#define R_PAR1_CONFIG__mode__fastbyte 2 +#define R_PAR1_CONFIG__mode__nibble 3 +#define R_PAR1_CONFIG__mode__byte 4 +#define R_PAR1_CONFIG__mode__ecp_fwd 5 +#define R_PAR1_CONFIG__mode__ecp_rev 6 +#define R_PAR1_CONFIG__mode__off 7 +#define R_PAR1_CONFIG__mode__epp_wr1 5 +#define R_PAR1_CONFIG__mode__epp_wr2 6 +#define R_PAR1_CONFIG__mode__epp_wr3 7 +#define R_PAR1_CONFIG__mode__epp_rd 0 + +#define R_PAR1_DELAY (IO_TYPECAST_UDWORD 0xb0000058) +#define R_PAR1_DELAY__fine_hold__BITNR 21 +#define R_PAR1_DELAY__fine_hold__WIDTH 3 +#define R_PAR1_DELAY__hold__BITNR 16 +#define R_PAR1_DELAY__hold__WIDTH 5 +#define R_PAR1_DELAY__fine_strb__BITNR 13 +#define R_PAR1_DELAY__fine_strb__WIDTH 3 +#define R_PAR1_DELAY__strobe__BITNR 8 +#define R_PAR1_DELAY__strobe__WIDTH 5 +#define R_PAR1_DELAY__fine_setup__BITNR 5 +#define R_PAR1_DELAY__fine_setup__WIDTH 3 +#define R_PAR1_DELAY__setup__BITNR 0 +#define R_PAR1_DELAY__setup__WIDTH 5 + +/* +!* ATA interface registers +!*/ + +#define R_ATA_CTRL_DATA (IO_TYPECAST_UDWORD 0xb0000040) +#define R_ATA_CTRL_DATA__sel__BITNR 30 +#define R_ATA_CTRL_DATA__sel__WIDTH 2 +#define R_ATA_CTRL_DATA__cs1__BITNR 29 +#define R_ATA_CTRL_DATA__cs1__WIDTH 1 +#define R_ATA_CTRL_DATA__cs1__active 1 +#define R_ATA_CTRL_DATA__cs1__inactive 0 +#define R_ATA_CTRL_DATA__cs0__BITNR 28 +#define R_ATA_CTRL_DATA__cs0__WIDTH 1 +#define R_ATA_CTRL_DATA__cs0__active 1 +#define R_ATA_CTRL_DATA__cs0__inactive 0 +#define R_ATA_CTRL_DATA__addr__BITNR 25 +#define R_ATA_CTRL_DATA__addr__WIDTH 3 +#define R_ATA_CTRL_DATA__rw__BITNR 24 +#define R_ATA_CTRL_DATA__rw__WIDTH 1 +#define R_ATA_CTRL_DATA__rw__read 1 +#define R_ATA_CTRL_DATA__rw__write 0 +#define R_ATA_CTRL_DATA__src_dst__BITNR 23 +#define R_ATA_CTRL_DATA__src_dst__WIDTH 1 +#define R_ATA_CTRL_DATA__src_dst__dma 1 +#define R_ATA_CTRL_DATA__src_dst__register 0 +#define R_ATA_CTRL_DATA__handsh__BITNR 22 +#define R_ATA_CTRL_DATA__handsh__WIDTH 1 +#define R_ATA_CTRL_DATA__handsh__dma 1 +#define R_ATA_CTRL_DATA__handsh__pio 0 +#define R_ATA_CTRL_DATA__multi__BITNR 21 +#define R_ATA_CTRL_DATA__multi__WIDTH 1 +#define R_ATA_CTRL_DATA__multi__on 1 +#define R_ATA_CTRL_DATA__multi__off 0 +#define R_ATA_CTRL_DATA__dma_size__BITNR 20 +#define R_ATA_CTRL_DATA__dma_size__WIDTH 1 +#define R_ATA_CTRL_DATA__dma_size__byte 1 +#define R_ATA_CTRL_DATA__dma_size__word 0 +#define R_ATA_CTRL_DATA__data__BITNR 0 +#define R_ATA_CTRL_DATA__data__WIDTH 16 + +#define R_ATA_STATUS_DATA (IO_TYPECAST_RO_UDWORD 0xb0000040) +#define R_ATA_STATUS_DATA__busy__BITNR 18 +#define R_ATA_STATUS_DATA__busy__WIDTH 1 +#define R_ATA_STATUS_DATA__busy__yes 1 +#define R_ATA_STATUS_DATA__busy__no 0 +#define R_ATA_STATUS_DATA__tr_rdy__BITNR 17 +#define R_ATA_STATUS_DATA__tr_rdy__WIDTH 1 +#define R_ATA_STATUS_DATA__tr_rdy__ready 1 +#define R_ATA_STATUS_DATA__tr_rdy__busy 0 +#define R_ATA_STATUS_DATA__dav__BITNR 16 +#define R_ATA_STATUS_DATA__dav__WIDTH 1 +#define R_ATA_STATUS_DATA__dav__data 1 +#define R_ATA_STATUS_DATA__dav__nodata 0 +#define R_ATA_STATUS_DATA__data__BITNR 0 +#define R_ATA_STATUS_DATA__data__WIDTH 16 + +#define R_ATA_CONFIG (IO_TYPECAST_UDWORD 0xb0000044) +#define R_ATA_CONFIG__enable__BITNR 25 +#define R_ATA_CONFIG__enable__WIDTH 1 +#define R_ATA_CONFIG__enable__on 1 +#define R_ATA_CONFIG__enable__off 0 +#define R_ATA_CONFIG__dma_strobe__BITNR 20 +#define R_ATA_CONFIG__dma_strobe__WIDTH 5 +#define R_ATA_CONFIG__dma_hold__BITNR 15 +#define R_ATA_CONFIG__dma_hold__WIDTH 5 +#define R_ATA_CONFIG__pio_setup__BITNR 10 +#define R_ATA_CONFIG__pio_setup__WIDTH 5 +#define R_ATA_CONFIG__pio_strobe__BITNR 5 +#define R_ATA_CONFIG__pio_strobe__WIDTH 5 +#define R_ATA_CONFIG__pio_hold__BITNR 0 +#define R_ATA_CONFIG__pio_hold__WIDTH 5 + +#define R_ATA_TRANSFER_CNT (IO_TYPECAST_UDWORD 0xb0000048) +#define R_ATA_TRANSFER_CNT__count__BITNR 0 +#define R_ATA_TRANSFER_CNT__count__WIDTH 17 + +/* +!* SCSI registers +!*/ + +#define R_SCSI0_CTRL (IO_TYPECAST_UDWORD 0xb0000044) +#define R_SCSI0_CTRL__id_type__BITNR 31 +#define R_SCSI0_CTRL__id_type__WIDTH 1 +#define R_SCSI0_CTRL__id_type__software 1 +#define R_SCSI0_CTRL__id_type__hardware 0 +#define R_SCSI0_CTRL__sel_timeout__BITNR 24 +#define R_SCSI0_CTRL__sel_timeout__WIDTH 7 +#define R_SCSI0_CTRL__synch_per__BITNR 16 +#define R_SCSI0_CTRL__synch_per__WIDTH 8 +#define R_SCSI0_CTRL__rst__BITNR 15 +#define R_SCSI0_CTRL__rst__WIDTH 1 +#define R_SCSI0_CTRL__rst__yes 1 +#define R_SCSI0_CTRL__rst__no 0 +#define R_SCSI0_CTRL__atn__BITNR 14 +#define R_SCSI0_CTRL__atn__WIDTH 1 +#define R_SCSI0_CTRL__atn__yes 1 +#define R_SCSI0_CTRL__atn__no 0 +#define R_SCSI0_CTRL__my_id__BITNR 9 +#define R_SCSI0_CTRL__my_id__WIDTH 4 +#define R_SCSI0_CTRL__target_id__BITNR 4 +#define R_SCSI0_CTRL__target_id__WIDTH 4 +#define R_SCSI0_CTRL__fast_20__BITNR 3 +#define R_SCSI0_CTRL__fast_20__WIDTH 1 +#define R_SCSI0_CTRL__fast_20__yes 1 +#define R_SCSI0_CTRL__fast_20__no 0 +#define R_SCSI0_CTRL__bus_width__BITNR 2 +#define R_SCSI0_CTRL__bus_width__WIDTH 1 +#define R_SCSI0_CTRL__bus_width__wide 1 +#define R_SCSI0_CTRL__bus_width__narrow 0 +#define R_SCSI0_CTRL__synch__BITNR 1 +#define R_SCSI0_CTRL__synch__WIDTH 1 +#define R_SCSI0_CTRL__synch__synch 1 +#define R_SCSI0_CTRL__synch__asynch 0 +#define R_SCSI0_CTRL__enable__BITNR 0 +#define R_SCSI0_CTRL__enable__WIDTH 1 +#define R_SCSI0_CTRL__enable__on 1 +#define R_SCSI0_CTRL__enable__off 0 + +#define R_SCSI0_CMD_DATA (IO_TYPECAST_UDWORD 0xb0000040) +#define R_SCSI0_CMD_DATA__parity_in__BITNR 26 +#define R_SCSI0_CMD_DATA__parity_in__WIDTH 1 +#define R_SCSI0_CMD_DATA__parity_in__on 0 +#define R_SCSI0_CMD_DATA__parity_in__off 1 +#define R_SCSI0_CMD_DATA__skip__BITNR 25 +#define R_SCSI0_CMD_DATA__skip__WIDTH 1 +#define R_SCSI0_CMD_DATA__skip__on 1 +#define R_SCSI0_CMD_DATA__skip__off 0 +#define R_SCSI0_CMD_DATA__clr_status__BITNR 24 +#define R_SCSI0_CMD_DATA__clr_status__WIDTH 1 +#define R_SCSI0_CMD_DATA__clr_status__yes 1 +#define R_SCSI0_CMD_DATA__clr_status__nop 0 +#define R_SCSI0_CMD_DATA__asynch_setup__BITNR 20 +#define R_SCSI0_CMD_DATA__asynch_setup__WIDTH 4 +#define R_SCSI0_CMD_DATA__command__BITNR 16 +#define R_SCSI0_CMD_DATA__command__WIDTH 4 +#define R_SCSI0_CMD_DATA__command__full_din_1 0 +#define R_SCSI0_CMD_DATA__command__full_dout_1 1 +#define R_SCSI0_CMD_DATA__command__full_stat_1 2 +#define R_SCSI0_CMD_DATA__command__resel_din 3 +#define R_SCSI0_CMD_DATA__command__resel_dout 4 +#define R_SCSI0_CMD_DATA__command__resel_stat 5 +#define R_SCSI0_CMD_DATA__command__arb_only 6 +#define R_SCSI0_CMD_DATA__command__full_din_3 8 +#define R_SCSI0_CMD_DATA__command__full_dout_3 9 +#define R_SCSI0_CMD_DATA__command__full_stat_3 10 +#define R_SCSI0_CMD_DATA__command__man_data_in 11 +#define R_SCSI0_CMD_DATA__command__man_data_out 12 +#define R_SCSI0_CMD_DATA__command__man_rat 13 +#define R_SCSI0_CMD_DATA__data_out__BITNR 0 +#define R_SCSI0_CMD_DATA__data_out__WIDTH 16 + +#define R_SCSI0_DATA (IO_TYPECAST_UWORD 0xb0000040) +#define R_SCSI0_DATA__data_out__BITNR 0 +#define R_SCSI0_DATA__data_out__WIDTH 16 + +#define R_SCSI0_CMD (IO_TYPECAST_BYTE 0xb0000042) +#define R_SCSI0_CMD__asynch_setup__BITNR 4 +#define R_SCSI0_CMD__asynch_setup__WIDTH 4 +#define R_SCSI0_CMD__command__BITNR 0 +#define R_SCSI0_CMD__command__WIDTH 4 +#define R_SCSI0_CMD__command__full_din_1 0 +#define R_SCSI0_CMD__command__full_dout_1 1 +#define R_SCSI0_CMD__command__full_stat_1 2 +#define R_SCSI0_CMD__command__resel_din 3 +#define R_SCSI0_CMD__command__resel_dout 4 +#define R_SCSI0_CMD__command__resel_stat 5 +#define R_SCSI0_CMD__command__arb_only 6 +#define R_SCSI0_CMD__command__full_din_3 8 +#define R_SCSI0_CMD__command__full_dout_3 9 +#define R_SCSI0_CMD__command__full_stat_3 10 +#define R_SCSI0_CMD__command__man_data_in 11 +#define R_SCSI0_CMD__command__man_data_out 12 +#define R_SCSI0_CMD__command__man_rat 13 + +#define R_SCSI0_STATUS_CTRL (IO_TYPECAST_BYTE 0xb0000043) +#define R_SCSI0_STATUS_CTRL__parity_in__BITNR 2 +#define R_SCSI0_STATUS_CTRL__parity_in__WIDTH 1 +#define R_SCSI0_STATUS_CTRL__parity_in__on 0 +#define R_SCSI0_STATUS_CTRL__parity_in__off 1 +#define R_SCSI0_STATUS_CTRL__skip__BITNR 1 +#define R_SCSI0_STATUS_CTRL__skip__WIDTH 1 +#define R_SCSI0_STATUS_CTRL__skip__on 1 +#define R_SCSI0_STATUS_CTRL__skip__off 0 +#define R_SCSI0_STATUS_CTRL__clr_status__BITNR 0 +#define R_SCSI0_STATUS_CTRL__clr_status__WIDTH 1 +#define R_SCSI0_STATUS_CTRL__clr_status__yes 1 +#define R_SCSI0_STATUS_CTRL__clr_status__nop 0 + +#define R_SCSI0_STATUS (IO_TYPECAST_RO_UDWORD 0xb0000048) +#define R_SCSI0_STATUS__tst_arb_won__BITNR 23 +#define R_SCSI0_STATUS__tst_arb_won__WIDTH 1 +#define R_SCSI0_STATUS__tst_resel__BITNR 22 +#define R_SCSI0_STATUS__tst_resel__WIDTH 1 +#define R_SCSI0_STATUS__parity_error__BITNR 21 +#define R_SCSI0_STATUS__parity_error__WIDTH 1 +#define R_SCSI0_STATUS__bus_reset__BITNR 20 +#define R_SCSI0_STATUS__bus_reset__WIDTH 1 +#define R_SCSI0_STATUS__bus_reset__yes 1 +#define R_SCSI0_STATUS__bus_reset__no 0 +#define R_SCSI0_STATUS__resel_target__BITNR 15 +#define R_SCSI0_STATUS__resel_target__WIDTH 4 +#define R_SCSI0_STATUS__resel__BITNR 14 +#define R_SCSI0_STATUS__resel__WIDTH 1 +#define R_SCSI0_STATUS__resel__yes 1 +#define R_SCSI0_STATUS__resel__no 0 +#define R_SCSI0_STATUS__curr_phase__BITNR 11 +#define R_SCSI0_STATUS__curr_phase__WIDTH 3 +#define R_SCSI0_STATUS__curr_phase__ph_undef 0 +#define R_SCSI0_STATUS__curr_phase__ph_msg_in 7 +#define R_SCSI0_STATUS__curr_phase__ph_msg_out 6 +#define R_SCSI0_STATUS__curr_phase__ph_status 3 +#define R_SCSI0_STATUS__curr_phase__ph_command 2 +#define R_SCSI0_STATUS__curr_phase__ph_data_in 5 +#define R_SCSI0_STATUS__curr_phase__ph_data_out 4 +#define R_SCSI0_STATUS__curr_phase__ph_resel 1 +#define R_SCSI0_STATUS__last_seq_step__BITNR 6 +#define R_SCSI0_STATUS__last_seq_step__WIDTH 5 +#define R_SCSI0_STATUS__last_seq_step__st_bus_free 24 +#define R_SCSI0_STATUS__last_seq_step__st_arbitrate 8 +#define R_SCSI0_STATUS__last_seq_step__st_resel_req 29 +#define R_SCSI0_STATUS__last_seq_step__st_msg_1 2 +#define R_SCSI0_STATUS__last_seq_step__st_manual 28 +#define R_SCSI0_STATUS__last_seq_step__st_transf_cmd 30 +#define R_SCSI0_STATUS__last_seq_step__st_msg_2 6 +#define R_SCSI0_STATUS__last_seq_step__st_msg_3 22 +#define R_SCSI0_STATUS__last_seq_step__st_answer 3 +#define R_SCSI0_STATUS__last_seq_step__st_synch_din_perr 1 +#define R_SCSI0_STATUS__last_seq_step__st_transfer_done 15 +#define R_SCSI0_STATUS__last_seq_step__st_synch_dout 0 +#define R_SCSI0_STATUS__last_seq_step__st_asynch_dout 25 +#define R_SCSI0_STATUS__last_seq_step__st_synch_din 13 +#define R_SCSI0_STATUS__last_seq_step__st_asynch_din 9 +#define R_SCSI0_STATUS__last_seq_step__st_synch_dout_ack 4 +#define R_SCSI0_STATUS__last_seq_step__st_synch_din_ack 12 +#define R_SCSI0_STATUS__last_seq_step__st_synch_din_ack_perr 5 +#define R_SCSI0_STATUS__last_seq_step__st_asynch_dout_end 11 +#define R_SCSI0_STATUS__last_seq_step__st_iwr 27 +#define R_SCSI0_STATUS__last_seq_step__st_wait_free_disc 21 +#define R_SCSI0_STATUS__last_seq_step__st_sdp_disc 7 +#define R_SCSI0_STATUS__last_seq_step__st_cc 31 +#define R_SCSI0_STATUS__last_seq_step__st_iwr_good 14 +#define R_SCSI0_STATUS__last_seq_step__st_iwr_cc 23 +#define R_SCSI0_STATUS__last_seq_step__st_wait_free_iwr_cc 17 +#define R_SCSI0_STATUS__last_seq_step__st_wait_free_cc 20 +#define R_SCSI0_STATUS__last_seq_step__st_wait_free_sdp_disc 16 +#define R_SCSI0_STATUS__last_seq_step__st_manual_req 10 +#define R_SCSI0_STATUS__last_seq_step__st_manual_din_prot 18 +#define R_SCSI0_STATUS__valid_status__BITNR 5 +#define R_SCSI0_STATUS__valid_status__WIDTH 1 +#define R_SCSI0_STATUS__valid_status__yes 1 +#define R_SCSI0_STATUS__valid_status__no 0 +#define R_SCSI0_STATUS__seq_status__BITNR 0 +#define R_SCSI0_STATUS__seq_status__WIDTH 5 +#define R_SCSI0_STATUS__seq_status__info_seq_complete 0 +#define R_SCSI0_STATUS__seq_status__info_parity_error 1 +#define R_SCSI0_STATUS__seq_status__info_unhandled_msg_in 2 +#define R_SCSI0_STATUS__seq_status__info_unexp_ph_change 3 +#define R_SCSI0_STATUS__seq_status__info_arb_lost 4 +#define R_SCSI0_STATUS__seq_status__info_sel_timeout 5 +#define R_SCSI0_STATUS__seq_status__info_unexp_bf 6 +#define R_SCSI0_STATUS__seq_status__info_illegal_op 7 +#define R_SCSI0_STATUS__seq_status__info_rec_recvd 8 +#define R_SCSI0_STATUS__seq_status__info_reselected 9 +#define R_SCSI0_STATUS__seq_status__info_unhandled_status 10 +#define R_SCSI0_STATUS__seq_status__info_bus_reset 11 +#define R_SCSI0_STATUS__seq_status__info_illegal_bf 12 +#define R_SCSI0_STATUS__seq_status__info_bus_free 13 + +#define R_SCSI0_DATA_IN (IO_TYPECAST_RO_UWORD 0xb0000040) +#define R_SCSI0_DATA_IN__data_in__BITNR 0 +#define R_SCSI0_DATA_IN__data_in__WIDTH 16 + +#define R_SCSI1_CTRL (IO_TYPECAST_UDWORD 0xb0000054) +#define R_SCSI1_CTRL__id_type__BITNR 31 +#define R_SCSI1_CTRL__id_type__WIDTH 1 +#define R_SCSI1_CTRL__id_type__software 1 +#define R_SCSI1_CTRL__id_type__hardware 0 +#define R_SCSI1_CTRL__sel_timeout__BITNR 24 +#define R_SCSI1_CTRL__sel_timeout__WIDTH 7 +#define R_SCSI1_CTRL__synch_per__BITNR 16 +#define R_SCSI1_CTRL__synch_per__WIDTH 8 +#define R_SCSI1_CTRL__rst__BITNR 15 +#define R_SCSI1_CTRL__rst__WIDTH 1 +#define R_SCSI1_CTRL__rst__yes 1 +#define R_SCSI1_CTRL__rst__no 0 +#define R_SCSI1_CTRL__atn__BITNR 14 +#define R_SCSI1_CTRL__atn__WIDTH 1 +#define R_SCSI1_CTRL__atn__yes 1 +#define R_SCSI1_CTRL__atn__no 0 +#define R_SCSI1_CTRL__my_id__BITNR 9 +#define R_SCSI1_CTRL__my_id__WIDTH 4 +#define R_SCSI1_CTRL__target_id__BITNR 4 +#define R_SCSI1_CTRL__target_id__WIDTH 4 +#define R_SCSI1_CTRL__fast_20__BITNR 3 +#define R_SCSI1_CTRL__fast_20__WIDTH 1 +#define R_SCSI1_CTRL__fast_20__yes 1 +#define R_SCSI1_CTRL__fast_20__no 0 +#define R_SCSI1_CTRL__bus_width__BITNR 2 +#define R_SCSI1_CTRL__bus_width__WIDTH 1 +#define R_SCSI1_CTRL__bus_width__wide 1 +#define R_SCSI1_CTRL__bus_width__narrow 0 +#define R_SCSI1_CTRL__synch__BITNR 1 +#define R_SCSI1_CTRL__synch__WIDTH 1 +#define R_SCSI1_CTRL__synch__synch 1 +#define R_SCSI1_CTRL__synch__asynch 0 +#define R_SCSI1_CTRL__enable__BITNR 0 +#define R_SCSI1_CTRL__enable__WIDTH 1 +#define R_SCSI1_CTRL__enable__on 1 +#define R_SCSI1_CTRL__enable__off 0 + +#define R_SCSI1_CMD_DATA (IO_TYPECAST_UDWORD 0xb0000050) +#define R_SCSI1_CMD_DATA__parity_in__BITNR 26 +#define R_SCSI1_CMD_DATA__parity_in__WIDTH 1 +#define R_SCSI1_CMD_DATA__parity_in__on 0 +#define R_SCSI1_CMD_DATA__parity_in__off 1 +#define R_SCSI1_CMD_DATA__skip__BITNR 25 +#define R_SCSI1_CMD_DATA__skip__WIDTH 1 +#define R_SCSI1_CMD_DATA__skip__on 1 +#define R_SCSI1_CMD_DATA__skip__off 0 +#define R_SCSI1_CMD_DATA__clr_status__BITNR 24 +#define R_SCSI1_CMD_DATA__clr_status__WIDTH 1 +#define R_SCSI1_CMD_DATA__clr_status__yes 1 +#define R_SCSI1_CMD_DATA__clr_status__nop 0 +#define R_SCSI1_CMD_DATA__asynch_setup__BITNR 20 +#define R_SCSI1_CMD_DATA__asynch_setup__WIDTH 4 +#define R_SCSI1_CMD_DATA__command__BITNR 16 +#define R_SCSI1_CMD_DATA__command__WIDTH 4 +#define R_SCSI1_CMD_DATA__command__full_din_1 0 +#define R_SCSI1_CMD_DATA__command__full_dout_1 1 +#define R_SCSI1_CMD_DATA__command__full_stat_1 2 +#define R_SCSI1_CMD_DATA__command__resel_din 3 +#define R_SCSI1_CMD_DATA__command__resel_dout 4 +#define R_SCSI1_CMD_DATA__command__resel_stat 5 +#define R_SCSI1_CMD_DATA__command__arb_only 6 +#define R_SCSI1_CMD_DATA__command__full_din_3 8 +#define R_SCSI1_CMD_DATA__command__full_dout_3 9 +#define R_SCSI1_CMD_DATA__command__full_stat_3 10 +#define R_SCSI1_CMD_DATA__command__man_data_in 11 +#define R_SCSI1_CMD_DATA__command__man_data_out 12 +#define R_SCSI1_CMD_DATA__command__man_rat 13 +#define R_SCSI1_CMD_DATA__data_out__BITNR 0 +#define R_SCSI1_CMD_DATA__data_out__WIDTH 16 + +#define R_SCSI1_DATA (IO_TYPECAST_UWORD 0xb0000050) +#define R_SCSI1_DATA__data_out__BITNR 0 +#define R_SCSI1_DATA__data_out__WIDTH 16 + +#define R_SCSI1_CMD (IO_TYPECAST_BYTE 0xb0000052) +#define R_SCSI1_CMD__asynch_setup__BITNR 4 +#define R_SCSI1_CMD__asynch_setup__WIDTH 4 +#define R_SCSI1_CMD__command__BITNR 0 +#define R_SCSI1_CMD__command__WIDTH 4 +#define R_SCSI1_CMD__command__full_din_1 0 +#define R_SCSI1_CMD__command__full_dout_1 1 +#define R_SCSI1_CMD__command__full_stat_1 2 +#define R_SCSI1_CMD__command__resel_din 3 +#define R_SCSI1_CMD__command__resel_dout 4 +#define R_SCSI1_CMD__command__resel_stat 5 +#define R_SCSI1_CMD__command__arb_only 6 +#define R_SCSI1_CMD__command__full_din_3 8 +#define R_SCSI1_CMD__command__full_dout_3 9 +#define R_SCSI1_CMD__command__full_stat_3 10 +#define R_SCSI1_CMD__command__man_data_in 11 +#define R_SCSI1_CMD__command__man_data_out 12 +#define R_SCSI1_CMD__command__man_rat 13 + +#define R_SCSI1_STATUS_CTRL (IO_TYPECAST_BYTE 0xb0000053) +#define R_SCSI1_STATUS_CTRL__parity_in__BITNR 2 +#define R_SCSI1_STATUS_CTRL__parity_in__WIDTH 1 +#define R_SCSI1_STATUS_CTRL__parity_in__on 0 +#define R_SCSI1_STATUS_CTRL__parity_in__off 1 +#define R_SCSI1_STATUS_CTRL__skip__BITNR 1 +#define R_SCSI1_STATUS_CTRL__skip__WIDTH 1 +#define R_SCSI1_STATUS_CTRL__skip__on 1 +#define R_SCSI1_STATUS_CTRL__skip__off 0 +#define R_SCSI1_STATUS_CTRL__clr_status__BITNR 0 +#define R_SCSI1_STATUS_CTRL__clr_status__WIDTH 1 +#define R_SCSI1_STATUS_CTRL__clr_status__yes 1 +#define R_SCSI1_STATUS_CTRL__clr_status__nop 0 + +#define R_SCSI1_STATUS (IO_TYPECAST_RO_UDWORD 0xb0000058) +#define R_SCSI1_STATUS__tst_arb_won__BITNR 23 +#define R_SCSI1_STATUS__tst_arb_won__WIDTH 1 +#define R_SCSI1_STATUS__tst_resel__BITNR 22 +#define R_SCSI1_STATUS__tst_resel__WIDTH 1 +#define R_SCSI1_STATUS__parity_error__BITNR 21 +#define R_SCSI1_STATUS__parity_error__WIDTH 1 +#define R_SCSI1_STATUS__bus_reset__BITNR 20 +#define R_SCSI1_STATUS__bus_reset__WIDTH 1 +#define R_SCSI1_STATUS__bus_reset__yes 1 +#define R_SCSI1_STATUS__bus_reset__no 0 +#define R_SCSI1_STATUS__resel_target__BITNR 15 +#define R_SCSI1_STATUS__resel_target__WIDTH 4 +#define R_SCSI1_STATUS__resel__BITNR 14 +#define R_SCSI1_STATUS__resel__WIDTH 1 +#define R_SCSI1_STATUS__resel__yes 1 +#define R_SCSI1_STATUS__resel__no 0 +#define R_SCSI1_STATUS__curr_phase__BITNR 11 +#define R_SCSI1_STATUS__curr_phase__WIDTH 3 +#define R_SCSI1_STATUS__curr_phase__ph_undef 0 +#define R_SCSI1_STATUS__curr_phase__ph_msg_in 7 +#define R_SCSI1_STATUS__curr_phase__ph_msg_out 6 +#define R_SCSI1_STATUS__curr_phase__ph_status 3 +#define R_SCSI1_STATUS__curr_phase__ph_command 2 +#define R_SCSI1_STATUS__curr_phase__ph_data_in 5 +#define R_SCSI1_STATUS__curr_phase__ph_data_out 4 +#define R_SCSI1_STATUS__curr_phase__ph_resel 1 +#define R_SCSI1_STATUS__last_seq_step__BITNR 6 +#define R_SCSI1_STATUS__last_seq_step__WIDTH 5 +#define R_SCSI1_STATUS__last_seq_step__st_bus_free 24 +#define R_SCSI1_STATUS__last_seq_step__st_arbitrate 8 +#define R_SCSI1_STATUS__last_seq_step__st_resel_req 29 +#define R_SCSI1_STATUS__last_seq_step__st_msg_1 2 +#define R_SCSI1_STATUS__last_seq_step__st_manual 28 +#define R_SCSI1_STATUS__last_seq_step__st_transf_cmd 30 +#define R_SCSI1_STATUS__last_seq_step__st_msg_2 6 +#define R_SCSI1_STATUS__last_seq_step__st_msg_3 22 +#define R_SCSI1_STATUS__last_seq_step__st_answer 3 +#define R_SCSI1_STATUS__last_seq_step__st_synch_din_perr 1 +#define R_SCSI1_STATUS__last_seq_step__st_transfer_done 15 +#define R_SCSI1_STATUS__last_seq_step__st_synch_dout 0 +#define R_SCSI1_STATUS__last_seq_step__st_asynch_dout 25 +#define R_SCSI1_STATUS__last_seq_step__st_synch_din 13 +#define R_SCSI1_STATUS__last_seq_step__st_asynch_din 9 +#define R_SCSI1_STATUS__last_seq_step__st_synch_dout_ack 4 +#define R_SCSI1_STATUS__last_seq_step__st_synch_din_ack 12 +#define R_SCSI1_STATUS__last_seq_step__st_synch_din_ack_perr 5 +#define R_SCSI1_STATUS__last_seq_step__st_asynch_dout_end 11 +#define R_SCSI1_STATUS__last_seq_step__st_iwr 27 +#define R_SCSI1_STATUS__last_seq_step__st_wait_free_disc 21 +#define R_SCSI1_STATUS__last_seq_step__st_sdp_disc 7 +#define R_SCSI1_STATUS__last_seq_step__st_cc 31 +#define R_SCSI1_STATUS__last_seq_step__st_iwr_good 14 +#define R_SCSI1_STATUS__last_seq_step__st_iwr_cc 23 +#define R_SCSI1_STATUS__last_seq_step__st_wait_free_iwr_cc 17 +#define R_SCSI1_STATUS__last_seq_step__st_wait_free_cc 20 +#define R_SCSI1_STATUS__last_seq_step__st_wait_free_sdp_disc 16 +#define R_SCSI1_STATUS__last_seq_step__st_manual_req 10 +#define R_SCSI1_STATUS__last_seq_step__st_manual_din_prot 18 +#define R_SCSI1_STATUS__valid_status__BITNR 5 +#define R_SCSI1_STATUS__valid_status__WIDTH 1 +#define R_SCSI1_STATUS__valid_status__yes 1 +#define R_SCSI1_STATUS__valid_status__no 0 +#define R_SCSI1_STATUS__seq_status__BITNR 0 +#define R_SCSI1_STATUS__seq_status__WIDTH 5 +#define R_SCSI1_STATUS__seq_status__info_seq_complete 0 +#define R_SCSI1_STATUS__seq_status__info_parity_error 1 +#define R_SCSI1_STATUS__seq_status__info_unhandled_msg_in 2 +#define R_SCSI1_STATUS__seq_status__info_unexp_ph_change 3 +#define R_SCSI1_STATUS__seq_status__info_arb_lost 4 +#define R_SCSI1_STATUS__seq_status__info_sel_timeout 5 +#define R_SCSI1_STATUS__seq_status__info_unexp_bf 6 +#define R_SCSI1_STATUS__seq_status__info_illegal_op 7 +#define R_SCSI1_STATUS__seq_status__info_rec_recvd 8 +#define R_SCSI1_STATUS__seq_status__info_reselected 9 +#define R_SCSI1_STATUS__seq_status__info_unhandled_status 10 +#define R_SCSI1_STATUS__seq_status__info_bus_reset 11 +#define R_SCSI1_STATUS__seq_status__info_illegal_bf 12 +#define R_SCSI1_STATUS__seq_status__info_bus_free 13 + +#define R_SCSI1_DATA_IN (IO_TYPECAST_RO_UWORD 0xb0000050) +#define R_SCSI1_DATA_IN__data_in__BITNR 0 +#define R_SCSI1_DATA_IN__data_in__WIDTH 16 + +/* +!* Interrupt mask and status registers +!*/ + +#define R_IRQ_MASK0_RD (IO_TYPECAST_RO_UDWORD 0xb00000c0) +#define R_IRQ_MASK0_RD__nmi_pin__BITNR 31 +#define R_IRQ_MASK0_RD__nmi_pin__WIDTH 1 +#define R_IRQ_MASK0_RD__nmi_pin__active 1 +#define R_IRQ_MASK0_RD__nmi_pin__inactive 0 +#define R_IRQ_MASK0_RD__watchdog_nmi__BITNR 30 +#define R_IRQ_MASK0_RD__watchdog_nmi__WIDTH 1 +#define R_IRQ_MASK0_RD__watchdog_nmi__active 1 +#define R_IRQ_MASK0_RD__watchdog_nmi__inactive 0 +#define R_IRQ_MASK0_RD__sqe_test_error__BITNR 29 +#define R_IRQ_MASK0_RD__sqe_test_error__WIDTH 1 +#define R_IRQ_MASK0_RD__sqe_test_error__active 1 +#define R_IRQ_MASK0_RD__sqe_test_error__inactive 0 +#define R_IRQ_MASK0_RD__carrier_loss__BITNR 28 +#define R_IRQ_MASK0_RD__carrier_loss__WIDTH 1 +#define R_IRQ_MASK0_RD__carrier_loss__active 1 +#define R_IRQ_MASK0_RD__carrier_loss__inactive 0 +#define R_IRQ_MASK0_RD__deferred__BITNR 27 +#define R_IRQ_MASK0_RD__deferred__WIDTH 1 +#define R_IRQ_MASK0_RD__deferred__active 1 +#define R_IRQ_MASK0_RD__deferred__inactive 0 +#define R_IRQ_MASK0_RD__late_col__BITNR 26 +#define R_IRQ_MASK0_RD__late_col__WIDTH 1 +#define R_IRQ_MASK0_RD__late_col__active 1 +#define R_IRQ_MASK0_RD__late_col__inactive 0 +#define R_IRQ_MASK0_RD__multiple_col__BITNR 25 +#define R_IRQ_MASK0_RD__multiple_col__WIDTH 1 +#define R_IRQ_MASK0_RD__multiple_col__active 1 +#define R_IRQ_MASK0_RD__multiple_col__inactive 0 +#define R_IRQ_MASK0_RD__single_col__BITNR 24 +#define R_IRQ_MASK0_RD__single_col__WIDTH 1 +#define R_IRQ_MASK0_RD__single_col__active 1 +#define R_IRQ_MASK0_RD__single_col__inactive 0 +#define R_IRQ_MASK0_RD__congestion__BITNR 23 +#define R_IRQ_MASK0_RD__congestion__WIDTH 1 +#define R_IRQ_MASK0_RD__congestion__active 1 +#define R_IRQ_MASK0_RD__congestion__inactive 0 +#define R_IRQ_MASK0_RD__oversize__BITNR 22 +#define R_IRQ_MASK0_RD__oversize__WIDTH 1 +#define R_IRQ_MASK0_RD__oversize__active 1 +#define R_IRQ_MASK0_RD__oversize__inactive 0 +#define R_IRQ_MASK0_RD__alignment_error__BITNR 21 +#define R_IRQ_MASK0_RD__alignment_error__WIDTH 1 +#define R_IRQ_MASK0_RD__alignment_error__active 1 +#define R_IRQ_MASK0_RD__alignment_error__inactive 0 +#define R_IRQ_MASK0_RD__crc_error__BITNR 20 +#define R_IRQ_MASK0_RD__crc_error__WIDTH 1 +#define R_IRQ_MASK0_RD__crc_error__active 1 +#define R_IRQ_MASK0_RD__crc_error__inactive 0 +#define R_IRQ_MASK0_RD__overrun__BITNR 19 +#define R_IRQ_MASK0_RD__overrun__WIDTH 1 +#define R_IRQ_MASK0_RD__overrun__active 1 +#define R_IRQ_MASK0_RD__overrun__inactive 0 +#define R_IRQ_MASK0_RD__underrun__BITNR 18 +#define R_IRQ_MASK0_RD__underrun__WIDTH 1 +#define R_IRQ_MASK0_RD__underrun__active 1 +#define R_IRQ_MASK0_RD__underrun__inactive 0 +#define R_IRQ_MASK0_RD__excessive_col__BITNR 17 +#define R_IRQ_MASK0_RD__excessive_col__WIDTH 1 +#define R_IRQ_MASK0_RD__excessive_col__active 1 +#define R_IRQ_MASK0_RD__excessive_col__inactive 0 +#define R_IRQ_MASK0_RD__mdio__BITNR 16 +#define R_IRQ_MASK0_RD__mdio__WIDTH 1 +#define R_IRQ_MASK0_RD__mdio__active 1 +#define R_IRQ_MASK0_RD__mdio__inactive 0 +#define R_IRQ_MASK0_RD__ata_drq3__BITNR 15 +#define R_IRQ_MASK0_RD__ata_drq3__WIDTH 1 +#define R_IRQ_MASK0_RD__ata_drq3__active 1 +#define R_IRQ_MASK0_RD__ata_drq3__inactive 0 +#define R_IRQ_MASK0_RD__ata_drq2__BITNR 14 +#define R_IRQ_MASK0_RD__ata_drq2__WIDTH 1 +#define R_IRQ_MASK0_RD__ata_drq2__active 1 +#define R_IRQ_MASK0_RD__ata_drq2__inactive 0 +#define R_IRQ_MASK0_RD__ata_drq1__BITNR 13 +#define R_IRQ_MASK0_RD__ata_drq1__WIDTH 1 +#define R_IRQ_MASK0_RD__ata_drq1__active 1 +#define R_IRQ_MASK0_RD__ata_drq1__inactive 0 +#define R_IRQ_MASK0_RD__ata_drq0__BITNR 12 +#define R_IRQ_MASK0_RD__ata_drq0__WIDTH 1 +#define R_IRQ_MASK0_RD__ata_drq0__active 1 +#define R_IRQ_MASK0_RD__ata_drq0__inactive 0 +#define R_IRQ_MASK0_RD__par0_ecp_cmd__BITNR 11 +#define R_IRQ_MASK0_RD__par0_ecp_cmd__WIDTH 1 +#define R_IRQ_MASK0_RD__par0_ecp_cmd__active 1 +#define R_IRQ_MASK0_RD__par0_ecp_cmd__inactive 0 +#define R_IRQ_MASK0_RD__ata_irq3__BITNR 11 +#define R_IRQ_MASK0_RD__ata_irq3__WIDTH 1 +#define R_IRQ_MASK0_RD__ata_irq3__active 1 +#define R_IRQ_MASK0_RD__ata_irq3__inactive 0 +#define R_IRQ_MASK0_RD__par0_peri__BITNR 10 +#define R_IRQ_MASK0_RD__par0_peri__WIDTH 1 +#define R_IRQ_MASK0_RD__par0_peri__active 1 +#define R_IRQ_MASK0_RD__par0_peri__inactive 0 +#define R_IRQ_MASK0_RD__ata_irq2__BITNR 10 +#define R_IRQ_MASK0_RD__ata_irq2__WIDTH 1 +#define R_IRQ_MASK0_RD__ata_irq2__active 1 +#define R_IRQ_MASK0_RD__ata_irq2__inactive 0 +#define R_IRQ_MASK0_RD__par0_data__BITNR 9 +#define R_IRQ_MASK0_RD__par0_data__WIDTH 1 +#define R_IRQ_MASK0_RD__par0_data__active 1 +#define R_IRQ_MASK0_RD__par0_data__inactive 0 +#define R_IRQ_MASK0_RD__ata_irq1__BITNR 9 +#define R_IRQ_MASK0_RD__ata_irq1__WIDTH 1 +#define R_IRQ_MASK0_RD__ata_irq1__active 1 +#define R_IRQ_MASK0_RD__ata_irq1__inactive 0 +#define R_IRQ_MASK0_RD__par0_ready__BITNR 8 +#define R_IRQ_MASK0_RD__par0_ready__WIDTH 1 +#define R_IRQ_MASK0_RD__par0_ready__active 1 +#define R_IRQ_MASK0_RD__par0_ready__inactive 0 +#define R_IRQ_MASK0_RD__ata_irq0__BITNR 8 +#define R_IRQ_MASK0_RD__ata_irq0__WIDTH 1 +#define R_IRQ_MASK0_RD__ata_irq0__active 1 +#define R_IRQ_MASK0_RD__ata_irq0__inactive 0 +#define R_IRQ_MASK0_RD__mio__BITNR 8 +#define R_IRQ_MASK0_RD__mio__WIDTH 1 +#define R_IRQ_MASK0_RD__mio__active 1 +#define R_IRQ_MASK0_RD__mio__inactive 0 +#define R_IRQ_MASK0_RD__scsi0__BITNR 8 +#define R_IRQ_MASK0_RD__scsi0__WIDTH 1 +#define R_IRQ_MASK0_RD__scsi0__active 1 +#define R_IRQ_MASK0_RD__scsi0__inactive 0 +#define R_IRQ_MASK0_RD__ata_dmaend__BITNR 7 +#define R_IRQ_MASK0_RD__ata_dmaend__WIDTH 1 +#define R_IRQ_MASK0_RD__ata_dmaend__active 1 +#define R_IRQ_MASK0_RD__ata_dmaend__inactive 0 +#define R_IRQ_MASK0_RD__irq_ext_vector_nr__BITNR 5 +#define R_IRQ_MASK0_RD__irq_ext_vector_nr__WIDTH 1 +#define R_IRQ_MASK0_RD__irq_ext_vector_nr__active 1 +#define R_IRQ_MASK0_RD__irq_ext_vector_nr__inactive 0 +#define R_IRQ_MASK0_RD__irq_int_vector_nr__BITNR 4 +#define R_IRQ_MASK0_RD__irq_int_vector_nr__WIDTH 1 +#define R_IRQ_MASK0_RD__irq_int_vector_nr__active 1 +#define R_IRQ_MASK0_RD__irq_int_vector_nr__inactive 0 +#define R_IRQ_MASK0_RD__ext_dma1__BITNR 3 +#define R_IRQ_MASK0_RD__ext_dma1__WIDTH 1 +#define R_IRQ_MASK0_RD__ext_dma1__active 1 +#define R_IRQ_MASK0_RD__ext_dma1__inactive 0 +#define R_IRQ_MASK0_RD__ext_dma0__BITNR 2 +#define R_IRQ_MASK0_RD__ext_dma0__WIDTH 1 +#define R_IRQ_MASK0_RD__ext_dma0__active 1 +#define R_IRQ_MASK0_RD__ext_dma0__inactive 0 +#define R_IRQ_MASK0_RD__timer1__BITNR 1 +#define R_IRQ_MASK0_RD__timer1__WIDTH 1 +#define R_IRQ_MASK0_RD__timer1__active 1 +#define R_IRQ_MASK0_RD__timer1__inactive 0 +#define R_IRQ_MASK0_RD__timer0__BITNR 0 +#define R_IRQ_MASK0_RD__timer0__WIDTH 1 +#define R_IRQ_MASK0_RD__timer0__active 1 +#define R_IRQ_MASK0_RD__timer0__inactive 0 + +#define R_IRQ_MASK0_CLR (IO_TYPECAST_UDWORD 0xb00000c0) +#define R_IRQ_MASK0_CLR__nmi_pin__BITNR 31 +#define R_IRQ_MASK0_CLR__nmi_pin__WIDTH 1 +#define R_IRQ_MASK0_CLR__nmi_pin__clr 1 +#define R_IRQ_MASK0_CLR__nmi_pin__nop 0 +#define R_IRQ_MASK0_CLR__watchdog_nmi__BITNR 30 +#define R_IRQ_MASK0_CLR__watchdog_nmi__WIDTH 1 +#define R_IRQ_MASK0_CLR__watchdog_nmi__clr 1 +#define R_IRQ_MASK0_CLR__watchdog_nmi__nop 0 +#define R_IRQ_MASK0_CLR__sqe_test_error__BITNR 29 +#define R_IRQ_MASK0_CLR__sqe_test_error__WIDTH 1 +#define R_IRQ_MASK0_CLR__sqe_test_error__clr 1 +#define R_IRQ_MASK0_CLR__sqe_test_error__nop 0 +#define R_IRQ_MASK0_CLR__carrier_loss__BITNR 28 +#define R_IRQ_MASK0_CLR__carrier_loss__WIDTH 1 +#define R_IRQ_MASK0_CLR__carrier_loss__clr 1 +#define R_IRQ_MASK0_CLR__carrier_loss__nop 0 +#define R_IRQ_MASK0_CLR__deferred__BITNR 27 +#define R_IRQ_MASK0_CLR__deferred__WIDTH 1 +#define R_IRQ_MASK0_CLR__deferred__clr 1 +#define R_IRQ_MASK0_CLR__deferred__nop 0 +#define R_IRQ_MASK0_CLR__late_col__BITNR 26 +#define R_IRQ_MASK0_CLR__late_col__WIDTH 1 +#define R_IRQ_MASK0_CLR__late_col__clr 1 +#define R_IRQ_MASK0_CLR__late_col__nop 0 +#define R_IRQ_MASK0_CLR__multiple_col__BITNR 25 +#define R_IRQ_MASK0_CLR__multiple_col__WIDTH 1 +#define R_IRQ_MASK0_CLR__multiple_col__clr 1 +#define R_IRQ_MASK0_CLR__multiple_col__nop 0 +#define R_IRQ_MASK0_CLR__single_col__BITNR 24 +#define R_IRQ_MASK0_CLR__single_col__WIDTH 1 +#define R_IRQ_MASK0_CLR__single_col__clr 1 +#define R_IRQ_MASK0_CLR__single_col__nop 0 +#define R_IRQ_MASK0_CLR__congestion__BITNR 23 +#define R_IRQ_MASK0_CLR__congestion__WIDTH 1 +#define R_IRQ_MASK0_CLR__congestion__clr 1 +#define R_IRQ_MASK0_CLR__congestion__nop 0 +#define R_IRQ_MASK0_CLR__oversize__BITNR 22 +#define R_IRQ_MASK0_CLR__oversize__WIDTH 1 +#define R_IRQ_MASK0_CLR__oversize__clr 1 +#define R_IRQ_MASK0_CLR__oversize__nop 0 +#define R_IRQ_MASK0_CLR__alignment_error__BITNR 21 +#define R_IRQ_MASK0_CLR__alignment_error__WIDTH 1 +#define R_IRQ_MASK0_CLR__alignment_error__clr 1 +#define R_IRQ_MASK0_CLR__alignment_error__nop 0 +#define R_IRQ_MASK0_CLR__crc_error__BITNR 20 +#define R_IRQ_MASK0_CLR__crc_error__WIDTH 1 +#define R_IRQ_MASK0_CLR__crc_error__clr 1 +#define R_IRQ_MASK0_CLR__crc_error__nop 0 +#define R_IRQ_MASK0_CLR__overrun__BITNR 19 +#define R_IRQ_MASK0_CLR__overrun__WIDTH 1 +#define R_IRQ_MASK0_CLR__overrun__clr 1 +#define R_IRQ_MASK0_CLR__overrun__nop 0 +#define R_IRQ_MASK0_CLR__underrun__BITNR 18 +#define R_IRQ_MASK0_CLR__underrun__WIDTH 1 +#define R_IRQ_MASK0_CLR__underrun__clr 1 +#define R_IRQ_MASK0_CLR__underrun__nop 0 +#define R_IRQ_MASK0_CLR__excessive_col__BITNR 17 +#define R_IRQ_MASK0_CLR__excessive_col__WIDTH 1 +#define R_IRQ_MASK0_CLR__excessive_col__clr 1 +#define R_IRQ_MASK0_CLR__excessive_col__nop 0 +#define R_IRQ_MASK0_CLR__mdio__BITNR 16 +#define R_IRQ_MASK0_CLR__mdio__WIDTH 1 +#define R_IRQ_MASK0_CLR__mdio__clr 1 +#define R_IRQ_MASK0_CLR__mdio__nop 0 +#define R_IRQ_MASK0_CLR__ata_drq3__BITNR 15 +#define R_IRQ_MASK0_CLR__ata_drq3__WIDTH 1 +#define R_IRQ_MASK0_CLR__ata_drq3__clr 1 +#define R_IRQ_MASK0_CLR__ata_drq3__nop 0 +#define R_IRQ_MASK0_CLR__ata_drq2__BITNR 14 +#define R_IRQ_MASK0_CLR__ata_drq2__WIDTH 1 +#define R_IRQ_MASK0_CLR__ata_drq2__clr 1 +#define R_IRQ_MASK0_CLR__ata_drq2__nop 0 +#define R_IRQ_MASK0_CLR__ata_drq1__BITNR 13 +#define R_IRQ_MASK0_CLR__ata_drq1__WIDTH 1 +#define R_IRQ_MASK0_CLR__ata_drq1__clr 1 +#define R_IRQ_MASK0_CLR__ata_drq1__nop 0 +#define R_IRQ_MASK0_CLR__ata_drq0__BITNR 12 +#define R_IRQ_MASK0_CLR__ata_drq0__WIDTH 1 +#define R_IRQ_MASK0_CLR__ata_drq0__clr 1 +#define R_IRQ_MASK0_CLR__ata_drq0__nop 0 +#define R_IRQ_MASK0_CLR__par0_ecp_cmd__BITNR 11 +#define R_IRQ_MASK0_CLR__par0_ecp_cmd__WIDTH 1 +#define R_IRQ_MASK0_CLR__par0_ecp_cmd__clr 1 +#define R_IRQ_MASK0_CLR__par0_ecp_cmd__nop 0 +#define R_IRQ_MASK0_CLR__ata_irq3__BITNR 11 +#define R_IRQ_MASK0_CLR__ata_irq3__WIDTH 1 +#define R_IRQ_MASK0_CLR__ata_irq3__clr 1 +#define R_IRQ_MASK0_CLR__ata_irq3__nop 0 +#define R_IRQ_MASK0_CLR__par0_peri__BITNR 10 +#define R_IRQ_MASK0_CLR__par0_peri__WIDTH 1 +#define R_IRQ_MASK0_CLR__par0_peri__clr 1 +#define R_IRQ_MASK0_CLR__par0_peri__nop 0 +#define R_IRQ_MASK0_CLR__ata_irq2__BITNR 10 +#define R_IRQ_MASK0_CLR__ata_irq2__WIDTH 1 +#define R_IRQ_MASK0_CLR__ata_irq2__clr 1 +#define R_IRQ_MASK0_CLR__ata_irq2__nop 0 +#define R_IRQ_MASK0_CLR__par0_data__BITNR 9 +#define R_IRQ_MASK0_CLR__par0_data__WIDTH 1 +#define R_IRQ_MASK0_CLR__par0_data__clr 1 +#define R_IRQ_MASK0_CLR__par0_data__nop 0 +#define R_IRQ_MASK0_CLR__ata_irq1__BITNR 9 +#define R_IRQ_MASK0_CLR__ata_irq1__WIDTH 1 +#define R_IRQ_MASK0_CLR__ata_irq1__clr 1 +#define R_IRQ_MASK0_CLR__ata_irq1__nop 0 +#define R_IRQ_MASK0_CLR__par0_ready__BITNR 8 +#define R_IRQ_MASK0_CLR__par0_ready__WIDTH 1 +#define R_IRQ_MASK0_CLR__par0_ready__clr 1 +#define R_IRQ_MASK0_CLR__par0_ready__nop 0 +#define R_IRQ_MASK0_CLR__ata_irq0__BITNR 8 +#define R_IRQ_MASK0_CLR__ata_irq0__WIDTH 1 +#define R_IRQ_MASK0_CLR__ata_irq0__clr 1 +#define R_IRQ_MASK0_CLR__ata_irq0__nop 0 +#define R_IRQ_MASK0_CLR__mio__BITNR 8 +#define R_IRQ_MASK0_CLR__mio__WIDTH 1 +#define R_IRQ_MASK0_CLR__mio__clr 1 +#define R_IRQ_MASK0_CLR__mio__nop 0 +#define R_IRQ_MASK0_CLR__scsi0__BITNR 8 +#define R_IRQ_MASK0_CLR__scsi0__WIDTH 1 +#define R_IRQ_MASK0_CLR__scsi0__clr 1 +#define R_IRQ_MASK0_CLR__scsi0__nop 0 +#define R_IRQ_MASK0_CLR__ata_dmaend__BITNR 7 +#define R_IRQ_MASK0_CLR__ata_dmaend__WIDTH 1 +#define R_IRQ_MASK0_CLR__ata_dmaend__clr 1 +#define R_IRQ_MASK0_CLR__ata_dmaend__nop 0 +#define R_IRQ_MASK0_CLR__irq_ext_vector_nr__BITNR 5 +#define R_IRQ_MASK0_CLR__irq_ext_vector_nr__WIDTH 1 +#define R_IRQ_MASK0_CLR__irq_ext_vector_nr__clr 1 +#define R_IRQ_MASK0_CLR__irq_ext_vector_nr__nop 0 +#define R_IRQ_MASK0_CLR__irq_int_vector_nr__BITNR 4 +#define R_IRQ_MASK0_CLR__irq_int_vector_nr__WIDTH 1 +#define R_IRQ_MASK0_CLR__irq_int_vector_nr__clr 1 +#define R_IRQ_MASK0_CLR__irq_int_vector_nr__nop 0 +#define R_IRQ_MASK0_CLR__ext_dma1__BITNR 3 +#define R_IRQ_MASK0_CLR__ext_dma1__WIDTH 1 +#define R_IRQ_MASK0_CLR__ext_dma1__clr 1 +#define R_IRQ_MASK0_CLR__ext_dma1__nop 0 +#define R_IRQ_MASK0_CLR__ext_dma0__BITNR 2 +#define R_IRQ_MASK0_CLR__ext_dma0__WIDTH 1 +#define R_IRQ_MASK0_CLR__ext_dma0__clr 1 +#define R_IRQ_MASK0_CLR__ext_dma0__nop 0 +#define R_IRQ_MASK0_CLR__timer1__BITNR 1 +#define R_IRQ_MASK0_CLR__timer1__WIDTH 1 +#define R_IRQ_MASK0_CLR__timer1__clr 1 +#define R_IRQ_MASK0_CLR__timer1__nop 0 +#define R_IRQ_MASK0_CLR__timer0__BITNR 0 +#define R_IRQ_MASK0_CLR__timer0__WIDTH 1 +#define R_IRQ_MASK0_CLR__timer0__clr 1 +#define R_IRQ_MASK0_CLR__timer0__nop 0 + +#define R_IRQ_READ0 (IO_TYPECAST_RO_UDWORD 0xb00000c4) +#define R_IRQ_READ0__nmi_pin__BITNR 31 +#define R_IRQ_READ0__nmi_pin__WIDTH 1 +#define R_IRQ_READ0__nmi_pin__active 1 +#define R_IRQ_READ0__nmi_pin__inactive 0 +#define R_IRQ_READ0__watchdog_nmi__BITNR 30 +#define R_IRQ_READ0__watchdog_nmi__WIDTH 1 +#define R_IRQ_READ0__watchdog_nmi__active 1 +#define R_IRQ_READ0__watchdog_nmi__inactive 0 +#define R_IRQ_READ0__sqe_test_error__BITNR 29 +#define R_IRQ_READ0__sqe_test_error__WIDTH 1 +#define R_IRQ_READ0__sqe_test_error__active 1 +#define R_IRQ_READ0__sqe_test_error__inactive 0 +#define R_IRQ_READ0__carrier_loss__BITNR 28 +#define R_IRQ_READ0__carrier_loss__WIDTH 1 +#define R_IRQ_READ0__carrier_loss__active 1 +#define R_IRQ_READ0__carrier_loss__inactive 0 +#define R_IRQ_READ0__deferred__BITNR 27 +#define R_IRQ_READ0__deferred__WIDTH 1 +#define R_IRQ_READ0__deferred__active 1 +#define R_IRQ_READ0__deferred__inactive 0 +#define R_IRQ_READ0__late_col__BITNR 26 +#define R_IRQ_READ0__late_col__WIDTH 1 +#define R_IRQ_READ0__late_col__active 1 +#define R_IRQ_READ0__late_col__inactive 0 +#define R_IRQ_READ0__multiple_col__BITNR 25 +#define R_IRQ_READ0__multiple_col__WIDTH 1 +#define R_IRQ_READ0__multiple_col__active 1 +#define R_IRQ_READ0__multiple_col__inactive 0 +#define R_IRQ_READ0__single_col__BITNR 24 +#define R_IRQ_READ0__single_col__WIDTH 1 +#define R_IRQ_READ0__single_col__active 1 +#define R_IRQ_READ0__single_col__inactive 0 +#define R_IRQ_READ0__congestion__BITNR 23 +#define R_IRQ_READ0__congestion__WIDTH 1 +#define R_IRQ_READ0__congestion__active 1 +#define R_IRQ_READ0__congestion__inactive 0 +#define R_IRQ_READ0__oversize__BITNR 22 +#define R_IRQ_READ0__oversize__WIDTH 1 +#define R_IRQ_READ0__oversize__active 1 +#define R_IRQ_READ0__oversize__inactive 0 +#define R_IRQ_READ0__alignment_error__BITNR 21 +#define R_IRQ_READ0__alignment_error__WIDTH 1 +#define R_IRQ_READ0__alignment_error__active 1 +#define R_IRQ_READ0__alignment_error__inactive 0 +#define R_IRQ_READ0__crc_error__BITNR 20 +#define R_IRQ_READ0__crc_error__WIDTH 1 +#define R_IRQ_READ0__crc_error__active 1 +#define R_IRQ_READ0__crc_error__inactive 0 +#define R_IRQ_READ0__overrun__BITNR 19 +#define R_IRQ_READ0__overrun__WIDTH 1 +#define R_IRQ_READ0__overrun__active 1 +#define R_IRQ_READ0__overrun__inactive 0 +#define R_IRQ_READ0__underrun__BITNR 18 +#define R_IRQ_READ0__underrun__WIDTH 1 +#define R_IRQ_READ0__underrun__active 1 +#define R_IRQ_READ0__underrun__inactive 0 +#define R_IRQ_READ0__excessive_col__BITNR 17 +#define R_IRQ_READ0__excessive_col__WIDTH 1 +#define R_IRQ_READ0__excessive_col__active 1 +#define R_IRQ_READ0__excessive_col__inactive 0 +#define R_IRQ_READ0__mdio__BITNR 16 +#define R_IRQ_READ0__mdio__WIDTH 1 +#define R_IRQ_READ0__mdio__active 1 +#define R_IRQ_READ0__mdio__inactive 0 +#define R_IRQ_READ0__ata_drq3__BITNR 15 +#define R_IRQ_READ0__ata_drq3__WIDTH 1 +#define R_IRQ_READ0__ata_drq3__active 1 +#define R_IRQ_READ0__ata_drq3__inactive 0 +#define R_IRQ_READ0__ata_drq2__BITNR 14 +#define R_IRQ_READ0__ata_drq2__WIDTH 1 +#define R_IRQ_READ0__ata_drq2__active 1 +#define R_IRQ_READ0__ata_drq2__inactive 0 +#define R_IRQ_READ0__ata_drq1__BITNR 13 +#define R_IRQ_READ0__ata_drq1__WIDTH 1 +#define R_IRQ_READ0__ata_drq1__active 1 +#define R_IRQ_READ0__ata_drq1__inactive 0 +#define R_IRQ_READ0__ata_drq0__BITNR 12 +#define R_IRQ_READ0__ata_drq0__WIDTH 1 +#define R_IRQ_READ0__ata_drq0__active 1 +#define R_IRQ_READ0__ata_drq0__inactive 0 +#define R_IRQ_READ0__par0_ecp_cmd__BITNR 11 +#define R_IRQ_READ0__par0_ecp_cmd__WIDTH 1 +#define R_IRQ_READ0__par0_ecp_cmd__active 1 +#define R_IRQ_READ0__par0_ecp_cmd__inactive 0 +#define R_IRQ_READ0__ata_irq3__BITNR 11 +#define R_IRQ_READ0__ata_irq3__WIDTH 1 +#define R_IRQ_READ0__ata_irq3__active 1 +#define R_IRQ_READ0__ata_irq3__inactive 0 +#define R_IRQ_READ0__par0_peri__BITNR 10 +#define R_IRQ_READ0__par0_peri__WIDTH 1 +#define R_IRQ_READ0__par0_peri__active 1 +#define R_IRQ_READ0__par0_peri__inactive 0 +#define R_IRQ_READ0__ata_irq2__BITNR 10 +#define R_IRQ_READ0__ata_irq2__WIDTH 1 +#define R_IRQ_READ0__ata_irq2__active 1 +#define R_IRQ_READ0__ata_irq2__inactive 0 +#define R_IRQ_READ0__par0_data__BITNR 9 +#define R_IRQ_READ0__par0_data__WIDTH 1 +#define R_IRQ_READ0__par0_data__active 1 +#define R_IRQ_READ0__par0_data__inactive 0 +#define R_IRQ_READ0__ata_irq1__BITNR 9 +#define R_IRQ_READ0__ata_irq1__WIDTH 1 +#define R_IRQ_READ0__ata_irq1__active 1 +#define R_IRQ_READ0__ata_irq1__inactive 0 +#define R_IRQ_READ0__par0_ready__BITNR 8 +#define R_IRQ_READ0__par0_ready__WIDTH 1 +#define R_IRQ_READ0__par0_ready__active 1 +#define R_IRQ_READ0__par0_ready__inactive 0 +#define R_IRQ_READ0__ata_irq0__BITNR 8 +#define R_IRQ_READ0__ata_irq0__WIDTH 1 +#define R_IRQ_READ0__ata_irq0__active 1 +#define R_IRQ_READ0__ata_irq0__inactive 0 +#define R_IRQ_READ0__mio__BITNR 8 +#define R_IRQ_READ0__mio__WIDTH 1 +#define R_IRQ_READ0__mio__active 1 +#define R_IRQ_READ0__mio__inactive 0 +#define R_IRQ_READ0__scsi0__BITNR 8 +#define R_IRQ_READ0__scsi0__WIDTH 1 +#define R_IRQ_READ0__scsi0__active 1 +#define R_IRQ_READ0__scsi0__inactive 0 +#define R_IRQ_READ0__ata_dmaend__BITNR 7 +#define R_IRQ_READ0__ata_dmaend__WIDTH 1 +#define R_IRQ_READ0__ata_dmaend__active 1 +#define R_IRQ_READ0__ata_dmaend__inactive 0 +#define R_IRQ_READ0__irq_ext_vector_nr__BITNR 5 +#define R_IRQ_READ0__irq_ext_vector_nr__WIDTH 1 +#define R_IRQ_READ0__irq_ext_vector_nr__active 1 +#define R_IRQ_READ0__irq_ext_vector_nr__inactive 0 +#define R_IRQ_READ0__irq_int_vector_nr__BITNR 4 +#define R_IRQ_READ0__irq_int_vector_nr__WIDTH 1 +#define R_IRQ_READ0__irq_int_vector_nr__active 1 +#define R_IRQ_READ0__irq_int_vector_nr__inactive 0 +#define R_IRQ_READ0__ext_dma1__BITNR 3 +#define R_IRQ_READ0__ext_dma1__WIDTH 1 +#define R_IRQ_READ0__ext_dma1__active 1 +#define R_IRQ_READ0__ext_dma1__inactive 0 +#define R_IRQ_READ0__ext_dma0__BITNR 2 +#define R_IRQ_READ0__ext_dma0__WIDTH 1 +#define R_IRQ_READ0__ext_dma0__active 1 +#define R_IRQ_READ0__ext_dma0__inactive 0 +#define R_IRQ_READ0__timer1__BITNR 1 +#define R_IRQ_READ0__timer1__WIDTH 1 +#define R_IRQ_READ0__timer1__active 1 +#define R_IRQ_READ0__timer1__inactive 0 +#define R_IRQ_READ0__timer0__BITNR 0 +#define R_IRQ_READ0__timer0__WIDTH 1 +#define R_IRQ_READ0__timer0__active 1 +#define R_IRQ_READ0__timer0__inactive 0 + +#define R_IRQ_MASK0_SET (IO_TYPECAST_UDWORD 0xb00000c4) +#define R_IRQ_MASK0_SET__nmi_pin__BITNR 31 +#define R_IRQ_MASK0_SET__nmi_pin__WIDTH 1 +#define R_IRQ_MASK0_SET__nmi_pin__set 1 +#define R_IRQ_MASK0_SET__nmi_pin__nop 0 +#define R_IRQ_MASK0_SET__watchdog_nmi__BITNR 30 +#define R_IRQ_MASK0_SET__watchdog_nmi__WIDTH 1 +#define R_IRQ_MASK0_SET__watchdog_nmi__set 1 +#define R_IRQ_MASK0_SET__watchdog_nmi__nop 0 +#define R_IRQ_MASK0_SET__sqe_test_error__BITNR 29 +#define R_IRQ_MASK0_SET__sqe_test_error__WIDTH 1 +#define R_IRQ_MASK0_SET__sqe_test_error__set 1 +#define R_IRQ_MASK0_SET__sqe_test_error__nop 0 +#define R_IRQ_MASK0_SET__carrier_loss__BITNR 28 +#define R_IRQ_MASK0_SET__carrier_loss__WIDTH 1 +#define R_IRQ_MASK0_SET__carrier_loss__set 1 +#define R_IRQ_MASK0_SET__carrier_loss__nop 0 +#define R_IRQ_MASK0_SET__deferred__BITNR 27 +#define R_IRQ_MASK0_SET__deferred__WIDTH 1 +#define R_IRQ_MASK0_SET__deferred__set 1 +#define R_IRQ_MASK0_SET__deferred__nop 0 +#define R_IRQ_MASK0_SET__late_col__BITNR 26 +#define R_IRQ_MASK0_SET__late_col__WIDTH 1 +#define R_IRQ_MASK0_SET__late_col__set 1 +#define R_IRQ_MASK0_SET__late_col__nop 0 +#define R_IRQ_MASK0_SET__multiple_col__BITNR 25 +#define R_IRQ_MASK0_SET__multiple_col__WIDTH 1 +#define R_IRQ_MASK0_SET__multiple_col__set 1 +#define R_IRQ_MASK0_SET__multiple_col__nop 0 +#define R_IRQ_MASK0_SET__single_col__BITNR 24 +#define R_IRQ_MASK0_SET__single_col__WIDTH 1 +#define R_IRQ_MASK0_SET__single_col__set 1 +#define R_IRQ_MASK0_SET__single_col__nop 0 +#define R_IRQ_MASK0_SET__congestion__BITNR 23 +#define R_IRQ_MASK0_SET__congestion__WIDTH 1 +#define R_IRQ_MASK0_SET__congestion__set 1 +#define R_IRQ_MASK0_SET__congestion__nop 0 +#define R_IRQ_MASK0_SET__oversize__BITNR 22 +#define R_IRQ_MASK0_SET__oversize__WIDTH 1 +#define R_IRQ_MASK0_SET__oversize__set 1 +#define R_IRQ_MASK0_SET__oversize__nop 0 +#define R_IRQ_MASK0_SET__alignment_error__BITNR 21 +#define R_IRQ_MASK0_SET__alignment_error__WIDTH 1 +#define R_IRQ_MASK0_SET__alignment_error__set 1 +#define R_IRQ_MASK0_SET__alignment_error__nop 0 +#define R_IRQ_MASK0_SET__crc_error__BITNR 20 +#define R_IRQ_MASK0_SET__crc_error__WIDTH 1 +#define R_IRQ_MASK0_SET__crc_error__set 1 +#define R_IRQ_MASK0_SET__crc_error__nop 0 +#define R_IRQ_MASK0_SET__overrun__BITNR 19 +#define R_IRQ_MASK0_SET__overrun__WIDTH 1 +#define R_IRQ_MASK0_SET__overrun__set 1 +#define R_IRQ_MASK0_SET__overrun__nop 0 +#define R_IRQ_MASK0_SET__underrun__BITNR 18 +#define R_IRQ_MASK0_SET__underrun__WIDTH 1 +#define R_IRQ_MASK0_SET__underrun__set 1 +#define R_IRQ_MASK0_SET__underrun__nop 0 +#define R_IRQ_MASK0_SET__excessive_col__BITNR 17 +#define R_IRQ_MASK0_SET__excessive_col__WIDTH 1 +#define R_IRQ_MASK0_SET__excessive_col__set 1 +#define R_IRQ_MASK0_SET__excessive_col__nop 0 +#define R_IRQ_MASK0_SET__mdio__BITNR 16 +#define R_IRQ_MASK0_SET__mdio__WIDTH 1 +#define R_IRQ_MASK0_SET__mdio__set 1 +#define R_IRQ_MASK0_SET__mdio__nop 0 +#define R_IRQ_MASK0_SET__ata_drq3__BITNR 15 +#define R_IRQ_MASK0_SET__ata_drq3__WIDTH 1 +#define R_IRQ_MASK0_SET__ata_drq3__set 1 +#define R_IRQ_MASK0_SET__ata_drq3__nop 0 +#define R_IRQ_MASK0_SET__ata_drq2__BITNR 14 +#define R_IRQ_MASK0_SET__ata_drq2__WIDTH 1 +#define R_IRQ_MASK0_SET__ata_drq2__set 1 +#define R_IRQ_MASK0_SET__ata_drq2__nop 0 +#define R_IRQ_MASK0_SET__ata_drq1__BITNR 13 +#define R_IRQ_MASK0_SET__ata_drq1__WIDTH 1 +#define R_IRQ_MASK0_SET__ata_drq1__set 1 +#define R_IRQ_MASK0_SET__ata_drq1__nop 0 +#define R_IRQ_MASK0_SET__ata_drq0__BITNR 12 +#define R_IRQ_MASK0_SET__ata_drq0__WIDTH 1 +#define R_IRQ_MASK0_SET__ata_drq0__set 1 +#define R_IRQ_MASK0_SET__ata_drq0__nop 0 +#define R_IRQ_MASK0_SET__par0_ecp_cmd__BITNR 11 +#define R_IRQ_MASK0_SET__par0_ecp_cmd__WIDTH 1 +#define R_IRQ_MASK0_SET__par0_ecp_cmd__set 1 +#define R_IRQ_MASK0_SET__par0_ecp_cmd__nop 0 +#define R_IRQ_MASK0_SET__ata_irq3__BITNR 11 +#define R_IRQ_MASK0_SET__ata_irq3__WIDTH 1 +#define R_IRQ_MASK0_SET__ata_irq3__set 1 +#define R_IRQ_MASK0_SET__ata_irq3__nop 0 +#define R_IRQ_MASK0_SET__par0_peri__BITNR 10 +#define R_IRQ_MASK0_SET__par0_peri__WIDTH 1 +#define R_IRQ_MASK0_SET__par0_peri__set 1 +#define R_IRQ_MASK0_SET__par0_peri__nop 0 +#define R_IRQ_MASK0_SET__ata_irq2__BITNR 10 +#define R_IRQ_MASK0_SET__ata_irq2__WIDTH 1 +#define R_IRQ_MASK0_SET__ata_irq2__set 1 +#define R_IRQ_MASK0_SET__ata_irq2__nop 0 +#define R_IRQ_MASK0_SET__par0_data__BITNR 9 +#define R_IRQ_MASK0_SET__par0_data__WIDTH 1 +#define R_IRQ_MASK0_SET__par0_data__set 1 +#define R_IRQ_MASK0_SET__par0_data__nop 0 +#define R_IRQ_MASK0_SET__ata_irq1__BITNR 9 +#define R_IRQ_MASK0_SET__ata_irq1__WIDTH 1 +#define R_IRQ_MASK0_SET__ata_irq1__set 1 +#define R_IRQ_MASK0_SET__ata_irq1__nop 0 +#define R_IRQ_MASK0_SET__par0_ready__BITNR 8 +#define R_IRQ_MASK0_SET__par0_ready__WIDTH 1 +#define R_IRQ_MASK0_SET__par0_ready__set 1 +#define R_IRQ_MASK0_SET__par0_ready__nop 0 +#define R_IRQ_MASK0_SET__ata_irq0__BITNR 8 +#define R_IRQ_MASK0_SET__ata_irq0__WIDTH 1 +#define R_IRQ_MASK0_SET__ata_irq0__set 1 +#define R_IRQ_MASK0_SET__ata_irq0__nop 0 +#define R_IRQ_MASK0_SET__mio__BITNR 8 +#define R_IRQ_MASK0_SET__mio__WIDTH 1 +#define R_IRQ_MASK0_SET__mio__set 1 +#define R_IRQ_MASK0_SET__mio__nop 0 +#define R_IRQ_MASK0_SET__scsi0__BITNR 8 +#define R_IRQ_MASK0_SET__scsi0__WIDTH 1 +#define R_IRQ_MASK0_SET__scsi0__set 1 +#define R_IRQ_MASK0_SET__scsi0__nop 0 +#define R_IRQ_MASK0_SET__ata_dmaend__BITNR 7 +#define R_IRQ_MASK0_SET__ata_dmaend__WIDTH 1 +#define R_IRQ_MASK0_SET__ata_dmaend__set 1 +#define R_IRQ_MASK0_SET__ata_dmaend__nop 0 +#define R_IRQ_MASK0_SET__irq_ext_vector_nr__BITNR 5 +#define R_IRQ_MASK0_SET__irq_ext_vector_nr__WIDTH 1 +#define R_IRQ_MASK0_SET__irq_ext_vector_nr__set 1 +#define R_IRQ_MASK0_SET__irq_ext_vector_nr__nop 0 +#define R_IRQ_MASK0_SET__irq_int_vector_nr__BITNR 4 +#define R_IRQ_MASK0_SET__irq_int_vector_nr__WIDTH 1 +#define R_IRQ_MASK0_SET__irq_int_vector_nr__set 1 +#define R_IRQ_MASK0_SET__irq_int_vector_nr__nop 0 +#define R_IRQ_MASK0_SET__ext_dma1__BITNR 3 +#define R_IRQ_MASK0_SET__ext_dma1__WIDTH 1 +#define R_IRQ_MASK0_SET__ext_dma1__set 1 +#define R_IRQ_MASK0_SET__ext_dma1__nop 0 +#define R_IRQ_MASK0_SET__ext_dma0__BITNR 2 +#define R_IRQ_MASK0_SET__ext_dma0__WIDTH 1 +#define R_IRQ_MASK0_SET__ext_dma0__set 1 +#define R_IRQ_MASK0_SET__ext_dma0__nop 0 +#define R_IRQ_MASK0_SET__timer1__BITNR 1 +#define R_IRQ_MASK0_SET__timer1__WIDTH 1 +#define R_IRQ_MASK0_SET__timer1__set 1 +#define R_IRQ_MASK0_SET__timer1__nop 0 +#define R_IRQ_MASK0_SET__timer0__BITNR 0 +#define R_IRQ_MASK0_SET__timer0__WIDTH 1 +#define R_IRQ_MASK0_SET__timer0__set 1 +#define R_IRQ_MASK0_SET__timer0__nop 0 + +#define R_IRQ_MASK1_RD (IO_TYPECAST_RO_UDWORD 0xb00000c8) +#define R_IRQ_MASK1_RD__sw_int7__BITNR 31 +#define R_IRQ_MASK1_RD__sw_int7__WIDTH 1 +#define R_IRQ_MASK1_RD__sw_int7__active 1 +#define R_IRQ_MASK1_RD__sw_int7__inactive 0 +#define R_IRQ_MASK1_RD__sw_int6__BITNR 30 +#define R_IRQ_MASK1_RD__sw_int6__WIDTH 1 +#define R_IRQ_MASK1_RD__sw_int6__active 1 +#define R_IRQ_MASK1_RD__sw_int6__inactive 0 +#define R_IRQ_MASK1_RD__sw_int5__BITNR 29 +#define R_IRQ_MASK1_RD__sw_int5__WIDTH 1 +#define R_IRQ_MASK1_RD__sw_int5__active 1 +#define R_IRQ_MASK1_RD__sw_int5__inactive 0 +#define R_IRQ_MASK1_RD__sw_int4__BITNR 28 +#define R_IRQ_MASK1_RD__sw_int4__WIDTH 1 +#define R_IRQ_MASK1_RD__sw_int4__active 1 +#define R_IRQ_MASK1_RD__sw_int4__inactive 0 +#define R_IRQ_MASK1_RD__sw_int3__BITNR 27 +#define R_IRQ_MASK1_RD__sw_int3__WIDTH 1 +#define R_IRQ_MASK1_RD__sw_int3__active 1 +#define R_IRQ_MASK1_RD__sw_int3__inactive 0 +#define R_IRQ_MASK1_RD__sw_int2__BITNR 26 +#define R_IRQ_MASK1_RD__sw_int2__WIDTH 1 +#define R_IRQ_MASK1_RD__sw_int2__active 1 +#define R_IRQ_MASK1_RD__sw_int2__inactive 0 +#define R_IRQ_MASK1_RD__sw_int1__BITNR 25 +#define R_IRQ_MASK1_RD__sw_int1__WIDTH 1 +#define R_IRQ_MASK1_RD__sw_int1__active 1 +#define R_IRQ_MASK1_RD__sw_int1__inactive 0 +#define R_IRQ_MASK1_RD__sw_int0__BITNR 24 +#define R_IRQ_MASK1_RD__sw_int0__WIDTH 1 +#define R_IRQ_MASK1_RD__sw_int0__active 1 +#define R_IRQ_MASK1_RD__sw_int0__inactive 0 +#define R_IRQ_MASK1_RD__par1_ecp_cmd__BITNR 19 +#define R_IRQ_MASK1_RD__par1_ecp_cmd__WIDTH 1 +#define R_IRQ_MASK1_RD__par1_ecp_cmd__active 1 +#define R_IRQ_MASK1_RD__par1_ecp_cmd__inactive 0 +#define R_IRQ_MASK1_RD__par1_peri__BITNR 18 +#define R_IRQ_MASK1_RD__par1_peri__WIDTH 1 +#define R_IRQ_MASK1_RD__par1_peri__active 1 +#define R_IRQ_MASK1_RD__par1_peri__inactive 0 +#define R_IRQ_MASK1_RD__par1_data__BITNR 17 +#define R_IRQ_MASK1_RD__par1_data__WIDTH 1 +#define R_IRQ_MASK1_RD__par1_data__active 1 +#define R_IRQ_MASK1_RD__par1_data__inactive 0 +#define R_IRQ_MASK1_RD__par1_ready__BITNR 16 +#define R_IRQ_MASK1_RD__par1_ready__WIDTH 1 +#define R_IRQ_MASK1_RD__par1_ready__active 1 +#define R_IRQ_MASK1_RD__par1_ready__inactive 0 +#define R_IRQ_MASK1_RD__scsi1__BITNR 16 +#define R_IRQ_MASK1_RD__scsi1__WIDTH 1 +#define R_IRQ_MASK1_RD__scsi1__active 1 +#define R_IRQ_MASK1_RD__scsi1__inactive 0 +#define R_IRQ_MASK1_RD__ser3_ready__BITNR 15 +#define R_IRQ_MASK1_RD__ser3_ready__WIDTH 1 +#define R_IRQ_MASK1_RD__ser3_ready__active 1 +#define R_IRQ_MASK1_RD__ser3_ready__inactive 0 +#define R_IRQ_MASK1_RD__ser3_data__BITNR 14 +#define R_IRQ_MASK1_RD__ser3_data__WIDTH 1 +#define R_IRQ_MASK1_RD__ser3_data__active 1 +#define R_IRQ_MASK1_RD__ser3_data__inactive 0 +#define R_IRQ_MASK1_RD__ser2_ready__BITNR 13 +#define R_IRQ_MASK1_RD__ser2_ready__WIDTH 1 +#define R_IRQ_MASK1_RD__ser2_ready__active 1 +#define R_IRQ_MASK1_RD__ser2_ready__inactive 0 +#define R_IRQ_MASK1_RD__ser2_data__BITNR 12 +#define R_IRQ_MASK1_RD__ser2_data__WIDTH 1 +#define R_IRQ_MASK1_RD__ser2_data__active 1 +#define R_IRQ_MASK1_RD__ser2_data__inactive 0 +#define R_IRQ_MASK1_RD__ser1_ready__BITNR 11 +#define R_IRQ_MASK1_RD__ser1_ready__WIDTH 1 +#define R_IRQ_MASK1_RD__ser1_ready__active 1 +#define R_IRQ_MASK1_RD__ser1_ready__inactive 0 +#define R_IRQ_MASK1_RD__ser1_data__BITNR 10 +#define R_IRQ_MASK1_RD__ser1_data__WIDTH 1 +#define R_IRQ_MASK1_RD__ser1_data__active 1 +#define R_IRQ_MASK1_RD__ser1_data__inactive 0 +#define R_IRQ_MASK1_RD__ser0_ready__BITNR 9 +#define R_IRQ_MASK1_RD__ser0_ready__WIDTH 1 +#define R_IRQ_MASK1_RD__ser0_ready__active 1 +#define R_IRQ_MASK1_RD__ser0_ready__inactive 0 +#define R_IRQ_MASK1_RD__ser0_data__BITNR 8 +#define R_IRQ_MASK1_RD__ser0_data__WIDTH 1 +#define R_IRQ_MASK1_RD__ser0_data__active 1 +#define R_IRQ_MASK1_RD__ser0_data__inactive 0 +#define R_IRQ_MASK1_RD__pa7__BITNR 7 +#define R_IRQ_MASK1_RD__pa7__WIDTH 1 +#define R_IRQ_MASK1_RD__pa7__active 1 +#define R_IRQ_MASK1_RD__pa7__inactive 0 +#define R_IRQ_MASK1_RD__pa6__BITNR 6 +#define R_IRQ_MASK1_RD__pa6__WIDTH 1 +#define R_IRQ_MASK1_RD__pa6__active 1 +#define R_IRQ_MASK1_RD__pa6__inactive 0 +#define R_IRQ_MASK1_RD__pa5__BITNR 5 +#define R_IRQ_MASK1_RD__pa5__WIDTH 1 +#define R_IRQ_MASK1_RD__pa5__active 1 +#define R_IRQ_MASK1_RD__pa5__inactive 0 +#define R_IRQ_MASK1_RD__pa4__BITNR 4 +#define R_IRQ_MASK1_RD__pa4__WIDTH 1 +#define R_IRQ_MASK1_RD__pa4__active 1 +#define R_IRQ_MASK1_RD__pa4__inactive 0 +#define R_IRQ_MASK1_RD__pa3__BITNR 3 +#define R_IRQ_MASK1_RD__pa3__WIDTH 1 +#define R_IRQ_MASK1_RD__pa3__active 1 +#define R_IRQ_MASK1_RD__pa3__inactive 0 +#define R_IRQ_MASK1_RD__pa2__BITNR 2 +#define R_IRQ_MASK1_RD__pa2__WIDTH 1 +#define R_IRQ_MASK1_RD__pa2__active 1 +#define R_IRQ_MASK1_RD__pa2__inactive 0 +#define R_IRQ_MASK1_RD__pa1__BITNR 1 +#define R_IRQ_MASK1_RD__pa1__WIDTH 1 +#define R_IRQ_MASK1_RD__pa1__active 1 +#define R_IRQ_MASK1_RD__pa1__inactive 0 +#define R_IRQ_MASK1_RD__pa0__BITNR 0 +#define R_IRQ_MASK1_RD__pa0__WIDTH 1 +#define R_IRQ_MASK1_RD__pa0__active 1 +#define R_IRQ_MASK1_RD__pa0__inactive 0 + +#define R_IRQ_MASK1_CLR (IO_TYPECAST_UDWORD 0xb00000c8) +#define R_IRQ_MASK1_CLR__sw_int7__BITNR 31 +#define R_IRQ_MASK1_CLR__sw_int7__WIDTH 1 +#define R_IRQ_MASK1_CLR__sw_int7__clr 1 +#define R_IRQ_MASK1_CLR__sw_int7__nop 0 +#define R_IRQ_MASK1_CLR__sw_int6__BITNR 30 +#define R_IRQ_MASK1_CLR__sw_int6__WIDTH 1 +#define R_IRQ_MASK1_CLR__sw_int6__clr 1 +#define R_IRQ_MASK1_CLR__sw_int6__nop 0 +#define R_IRQ_MASK1_CLR__sw_int5__BITNR 29 +#define R_IRQ_MASK1_CLR__sw_int5__WIDTH 1 +#define R_IRQ_MASK1_CLR__sw_int5__clr 1 +#define R_IRQ_MASK1_CLR__sw_int5__nop 0 +#define R_IRQ_MASK1_CLR__sw_int4__BITNR 28 +#define R_IRQ_MASK1_CLR__sw_int4__WIDTH 1 +#define R_IRQ_MASK1_CLR__sw_int4__clr 1 +#define R_IRQ_MASK1_CLR__sw_int4__nop 0 +#define R_IRQ_MASK1_CLR__sw_int3__BITNR 27 +#define R_IRQ_MASK1_CLR__sw_int3__WIDTH 1 +#define R_IRQ_MASK1_CLR__sw_int3__clr 1 +#define R_IRQ_MASK1_CLR__sw_int3__nop 0 +#define R_IRQ_MASK1_CLR__sw_int2__BITNR 26 +#define R_IRQ_MASK1_CLR__sw_int2__WIDTH 1 +#define R_IRQ_MASK1_CLR__sw_int2__clr 1 +#define R_IRQ_MASK1_CLR__sw_int2__nop 0 +#define R_IRQ_MASK1_CLR__sw_int1__BITNR 25 +#define R_IRQ_MASK1_CLR__sw_int1__WIDTH 1 +#define R_IRQ_MASK1_CLR__sw_int1__clr 1 +#define R_IRQ_MASK1_CLR__sw_int1__nop 0 +#define R_IRQ_MASK1_CLR__sw_int0__BITNR 24 +#define R_IRQ_MASK1_CLR__sw_int0__WIDTH 1 +#define R_IRQ_MASK1_CLR__sw_int0__clr 1 +#define R_IRQ_MASK1_CLR__sw_int0__nop 0 +#define R_IRQ_MASK1_CLR__par1_ecp_cmd__BITNR 19 +#define R_IRQ_MASK1_CLR__par1_ecp_cmd__WIDTH 1 +#define R_IRQ_MASK1_CLR__par1_ecp_cmd__clr 1 +#define R_IRQ_MASK1_CLR__par1_ecp_cmd__nop 0 +#define R_IRQ_MASK1_CLR__par1_peri__BITNR 18 +#define R_IRQ_MASK1_CLR__par1_peri__WIDTH 1 +#define R_IRQ_MASK1_CLR__par1_peri__clr 1 +#define R_IRQ_MASK1_CLR__par1_peri__nop 0 +#define R_IRQ_MASK1_CLR__par1_data__BITNR 17 +#define R_IRQ_MASK1_CLR__par1_data__WIDTH 1 +#define R_IRQ_MASK1_CLR__par1_data__clr 1 +#define R_IRQ_MASK1_CLR__par1_data__nop 0 +#define R_IRQ_MASK1_CLR__par1_ready__BITNR 16 +#define R_IRQ_MASK1_CLR__par1_ready__WIDTH 1 +#define R_IRQ_MASK1_CLR__par1_ready__clr 1 +#define R_IRQ_MASK1_CLR__par1_ready__nop 0 +#define R_IRQ_MASK1_CLR__scsi1__BITNR 16 +#define R_IRQ_MASK1_CLR__scsi1__WIDTH 1 +#define R_IRQ_MASK1_CLR__scsi1__clr 1 +#define R_IRQ_MASK1_CLR__scsi1__nop 0 +#define R_IRQ_MASK1_CLR__ser3_ready__BITNR 15 +#define R_IRQ_MASK1_CLR__ser3_ready__WIDTH 1 +#define R_IRQ_MASK1_CLR__ser3_ready__clr 1 +#define R_IRQ_MASK1_CLR__ser3_ready__nop 0 +#define R_IRQ_MASK1_CLR__ser3_data__BITNR 14 +#define R_IRQ_MASK1_CLR__ser3_data__WIDTH 1 +#define R_IRQ_MASK1_CLR__ser3_data__clr 1 +#define R_IRQ_MASK1_CLR__ser3_data__nop 0 +#define R_IRQ_MASK1_CLR__ser2_ready__BITNR 13 +#define R_IRQ_MASK1_CLR__ser2_ready__WIDTH 1 +#define R_IRQ_MASK1_CLR__ser2_ready__clr 1 +#define R_IRQ_MASK1_CLR__ser2_ready__nop 0 +#define R_IRQ_MASK1_CLR__ser2_data__BITNR 12 +#define R_IRQ_MASK1_CLR__ser2_data__WIDTH 1 +#define R_IRQ_MASK1_CLR__ser2_data__clr 1 +#define R_IRQ_MASK1_CLR__ser2_data__nop 0 +#define R_IRQ_MASK1_CLR__ser1_ready__BITNR 11 +#define R_IRQ_MASK1_CLR__ser1_ready__WIDTH 1 +#define R_IRQ_MASK1_CLR__ser1_ready__clr 1 +#define R_IRQ_MASK1_CLR__ser1_ready__nop 0 +#define R_IRQ_MASK1_CLR__ser1_data__BITNR 10 +#define R_IRQ_MASK1_CLR__ser1_data__WIDTH 1 +#define R_IRQ_MASK1_CLR__ser1_data__clr 1 +#define R_IRQ_MASK1_CLR__ser1_data__nop 0 +#define R_IRQ_MASK1_CLR__ser0_ready__BITNR 9 +#define R_IRQ_MASK1_CLR__ser0_ready__WIDTH 1 +#define R_IRQ_MASK1_CLR__ser0_ready__clr 1 +#define R_IRQ_MASK1_CLR__ser0_ready__nop 0 +#define R_IRQ_MASK1_CLR__ser0_data__BITNR 8 +#define R_IRQ_MASK1_CLR__ser0_data__WIDTH 1 +#define R_IRQ_MASK1_CLR__ser0_data__clr 1 +#define R_IRQ_MASK1_CLR__ser0_data__nop 0 +#define R_IRQ_MASK1_CLR__pa7__BITNR 7 +#define R_IRQ_MASK1_CLR__pa7__WIDTH 1 +#define R_IRQ_MASK1_CLR__pa7__clr 1 +#define R_IRQ_MASK1_CLR__pa7__nop 0 +#define R_IRQ_MASK1_CLR__pa6__BITNR 6 +#define R_IRQ_MASK1_CLR__pa6__WIDTH 1 +#define R_IRQ_MASK1_CLR__pa6__clr 1 +#define R_IRQ_MASK1_CLR__pa6__nop 0 +#define R_IRQ_MASK1_CLR__pa5__BITNR 5 +#define R_IRQ_MASK1_CLR__pa5__WIDTH 1 +#define R_IRQ_MASK1_CLR__pa5__clr 1 +#define R_IRQ_MASK1_CLR__pa5__nop 0 +#define R_IRQ_MASK1_CLR__pa4__BITNR 4 +#define R_IRQ_MASK1_CLR__pa4__WIDTH 1 +#define R_IRQ_MASK1_CLR__pa4__clr 1 +#define R_IRQ_MASK1_CLR__pa4__nop 0 +#define R_IRQ_MASK1_CLR__pa3__BITNR 3 +#define R_IRQ_MASK1_CLR__pa3__WIDTH 1 +#define R_IRQ_MASK1_CLR__pa3__clr 1 +#define R_IRQ_MASK1_CLR__pa3__nop 0 +#define R_IRQ_MASK1_CLR__pa2__BITNR 2 +#define R_IRQ_MASK1_CLR__pa2__WIDTH 1 +#define R_IRQ_MASK1_CLR__pa2__clr 1 +#define R_IRQ_MASK1_CLR__pa2__nop 0 +#define R_IRQ_MASK1_CLR__pa1__BITNR 1 +#define R_IRQ_MASK1_CLR__pa1__WIDTH 1 +#define R_IRQ_MASK1_CLR__pa1__clr 1 +#define R_IRQ_MASK1_CLR__pa1__nop 0 +#define R_IRQ_MASK1_CLR__pa0__BITNR 0 +#define R_IRQ_MASK1_CLR__pa0__WIDTH 1 +#define R_IRQ_MASK1_CLR__pa0__clr 1 +#define R_IRQ_MASK1_CLR__pa0__nop 0 + +#define R_IRQ_READ1 (IO_TYPECAST_RO_UDWORD 0xb00000cc) +#define R_IRQ_READ1__sw_int7__BITNR 31 +#define R_IRQ_READ1__sw_int7__WIDTH 1 +#define R_IRQ_READ1__sw_int7__active 1 +#define R_IRQ_READ1__sw_int7__inactive 0 +#define R_IRQ_READ1__sw_int6__BITNR 30 +#define R_IRQ_READ1__sw_int6__WIDTH 1 +#define R_IRQ_READ1__sw_int6__active 1 +#define R_IRQ_READ1__sw_int6__inactive 0 +#define R_IRQ_READ1__sw_int5__BITNR 29 +#define R_IRQ_READ1__sw_int5__WIDTH 1 +#define R_IRQ_READ1__sw_int5__active 1 +#define R_IRQ_READ1__sw_int5__inactive 0 +#define R_IRQ_READ1__sw_int4__BITNR 28 +#define R_IRQ_READ1__sw_int4__WIDTH 1 +#define R_IRQ_READ1__sw_int4__active 1 +#define R_IRQ_READ1__sw_int4__inactive 0 +#define R_IRQ_READ1__sw_int3__BITNR 27 +#define R_IRQ_READ1__sw_int3__WIDTH 1 +#define R_IRQ_READ1__sw_int3__active 1 +#define R_IRQ_READ1__sw_int3__inactive 0 +#define R_IRQ_READ1__sw_int2__BITNR 26 +#define R_IRQ_READ1__sw_int2__WIDTH 1 +#define R_IRQ_READ1__sw_int2__active 1 +#define R_IRQ_READ1__sw_int2__inactive 0 +#define R_IRQ_READ1__sw_int1__BITNR 25 +#define R_IRQ_READ1__sw_int1__WIDTH 1 +#define R_IRQ_READ1__sw_int1__active 1 +#define R_IRQ_READ1__sw_int1__inactive 0 +#define R_IRQ_READ1__sw_int0__BITNR 24 +#define R_IRQ_READ1__sw_int0__WIDTH 1 +#define R_IRQ_READ1__sw_int0__active 1 +#define R_IRQ_READ1__sw_int0__inactive 0 +#define R_IRQ_READ1__par1_ecp_cmd__BITNR 19 +#define R_IRQ_READ1__par1_ecp_cmd__WIDTH 1 +#define R_IRQ_READ1__par1_ecp_cmd__active 1 +#define R_IRQ_READ1__par1_ecp_cmd__inactive 0 +#define R_IRQ_READ1__par1_peri__BITNR 18 +#define R_IRQ_READ1__par1_peri__WIDTH 1 +#define R_IRQ_READ1__par1_peri__active 1 +#define R_IRQ_READ1__par1_peri__inactive 0 +#define R_IRQ_READ1__par1_data__BITNR 17 +#define R_IRQ_READ1__par1_data__WIDTH 1 +#define R_IRQ_READ1__par1_data__active 1 +#define R_IRQ_READ1__par1_data__inactive 0 +#define R_IRQ_READ1__par1_ready__BITNR 16 +#define R_IRQ_READ1__par1_ready__WIDTH 1 +#define R_IRQ_READ1__par1_ready__active 1 +#define R_IRQ_READ1__par1_ready__inactive 0 +#define R_IRQ_READ1__scsi1__BITNR 16 +#define R_IRQ_READ1__scsi1__WIDTH 1 +#define R_IRQ_READ1__scsi1__active 1 +#define R_IRQ_READ1__scsi1__inactive 0 +#define R_IRQ_READ1__ser3_ready__BITNR 15 +#define R_IRQ_READ1__ser3_ready__WIDTH 1 +#define R_IRQ_READ1__ser3_ready__active 1 +#define R_IRQ_READ1__ser3_ready__inactive 0 +#define R_IRQ_READ1__ser3_data__BITNR 14 +#define R_IRQ_READ1__ser3_data__WIDTH 1 +#define R_IRQ_READ1__ser3_data__active 1 +#define R_IRQ_READ1__ser3_data__inactive 0 +#define R_IRQ_READ1__ser2_ready__BITNR 13 +#define R_IRQ_READ1__ser2_ready__WIDTH 1 +#define R_IRQ_READ1__ser2_ready__active 1 +#define R_IRQ_READ1__ser2_ready__inactive 0 +#define R_IRQ_READ1__ser2_data__BITNR 12 +#define R_IRQ_READ1__ser2_data__WIDTH 1 +#define R_IRQ_READ1__ser2_data__active 1 +#define R_IRQ_READ1__ser2_data__inactive 0 +#define R_IRQ_READ1__ser1_ready__BITNR 11 +#define R_IRQ_READ1__ser1_ready__WIDTH 1 +#define R_IRQ_READ1__ser1_ready__active 1 +#define R_IRQ_READ1__ser1_ready__inactive 0 +#define R_IRQ_READ1__ser1_data__BITNR 10 +#define R_IRQ_READ1__ser1_data__WIDTH 1 +#define R_IRQ_READ1__ser1_data__active 1 +#define R_IRQ_READ1__ser1_data__inactive 0 +#define R_IRQ_READ1__ser0_ready__BITNR 9 +#define R_IRQ_READ1__ser0_ready__WIDTH 1 +#define R_IRQ_READ1__ser0_ready__active 1 +#define R_IRQ_READ1__ser0_ready__inactive 0 +#define R_IRQ_READ1__ser0_data__BITNR 8 +#define R_IRQ_READ1__ser0_data__WIDTH 1 +#define R_IRQ_READ1__ser0_data__active 1 +#define R_IRQ_READ1__ser0_data__inactive 0 +#define R_IRQ_READ1__pa7__BITNR 7 +#define R_IRQ_READ1__pa7__WIDTH 1 +#define R_IRQ_READ1__pa7__active 1 +#define R_IRQ_READ1__pa7__inactive 0 +#define R_IRQ_READ1__pa6__BITNR 6 +#define R_IRQ_READ1__pa6__WIDTH 1 +#define R_IRQ_READ1__pa6__active 1 +#define R_IRQ_READ1__pa6__inactive 0 +#define R_IRQ_READ1__pa5__BITNR 5 +#define R_IRQ_READ1__pa5__WIDTH 1 +#define R_IRQ_READ1__pa5__active 1 +#define R_IRQ_READ1__pa5__inactive 0 +#define R_IRQ_READ1__pa4__BITNR 4 +#define R_IRQ_READ1__pa4__WIDTH 1 +#define R_IRQ_READ1__pa4__active 1 +#define R_IRQ_READ1__pa4__inactive 0 +#define R_IRQ_READ1__pa3__BITNR 3 +#define R_IRQ_READ1__pa3__WIDTH 1 +#define R_IRQ_READ1__pa3__active 1 +#define R_IRQ_READ1__pa3__inactive 0 +#define R_IRQ_READ1__pa2__BITNR 2 +#define R_IRQ_READ1__pa2__WIDTH 1 +#define R_IRQ_READ1__pa2__active 1 +#define R_IRQ_READ1__pa2__inactive 0 +#define R_IRQ_READ1__pa1__BITNR 1 +#define R_IRQ_READ1__pa1__WIDTH 1 +#define R_IRQ_READ1__pa1__active 1 +#define R_IRQ_READ1__pa1__inactive 0 +#define R_IRQ_READ1__pa0__BITNR 0 +#define R_IRQ_READ1__pa0__WIDTH 1 +#define R_IRQ_READ1__pa0__active 1 +#define R_IRQ_READ1__pa0__inactive 0 + +#define R_IRQ_MASK1_SET (IO_TYPECAST_UDWORD 0xb00000cc) +#define R_IRQ_MASK1_SET__sw_int7__BITNR 31 +#define R_IRQ_MASK1_SET__sw_int7__WIDTH 1 +#define R_IRQ_MASK1_SET__sw_int7__set 1 +#define R_IRQ_MASK1_SET__sw_int7__nop 0 +#define R_IRQ_MASK1_SET__sw_int6__BITNR 30 +#define R_IRQ_MASK1_SET__sw_int6__WIDTH 1 +#define R_IRQ_MASK1_SET__sw_int6__set 1 +#define R_IRQ_MASK1_SET__sw_int6__nop 0 +#define R_IRQ_MASK1_SET__sw_int5__BITNR 29 +#define R_IRQ_MASK1_SET__sw_int5__WIDTH 1 +#define R_IRQ_MASK1_SET__sw_int5__set 1 +#define R_IRQ_MASK1_SET__sw_int5__nop 0 +#define R_IRQ_MASK1_SET__sw_int4__BITNR 28 +#define R_IRQ_MASK1_SET__sw_int4__WIDTH 1 +#define R_IRQ_MASK1_SET__sw_int4__set 1 +#define R_IRQ_MASK1_SET__sw_int4__nop 0 +#define R_IRQ_MASK1_SET__sw_int3__BITNR 27 +#define R_IRQ_MASK1_SET__sw_int3__WIDTH 1 +#define R_IRQ_MASK1_SET__sw_int3__set 1 +#define R_IRQ_MASK1_SET__sw_int3__nop 0 +#define R_IRQ_MASK1_SET__sw_int2__BITNR 26 +#define R_IRQ_MASK1_SET__sw_int2__WIDTH 1 +#define R_IRQ_MASK1_SET__sw_int2__set 1 +#define R_IRQ_MASK1_SET__sw_int2__nop 0 +#define R_IRQ_MASK1_SET__sw_int1__BITNR 25 +#define R_IRQ_MASK1_SET__sw_int1__WIDTH 1 +#define R_IRQ_MASK1_SET__sw_int1__set 1 +#define R_IRQ_MASK1_SET__sw_int1__nop 0 +#define R_IRQ_MASK1_SET__sw_int0__BITNR 24 +#define R_IRQ_MASK1_SET__sw_int0__WIDTH 1 +#define R_IRQ_MASK1_SET__sw_int0__set 1 +#define R_IRQ_MASK1_SET__sw_int0__nop 0 +#define R_IRQ_MASK1_SET__par1_ecp_cmd__BITNR 19 +#define R_IRQ_MASK1_SET__par1_ecp_cmd__WIDTH 1 +#define R_IRQ_MASK1_SET__par1_ecp_cmd__set 1 +#define R_IRQ_MASK1_SET__par1_ecp_cmd__nop 0 +#define R_IRQ_MASK1_SET__par1_peri__BITNR 18 +#define R_IRQ_MASK1_SET__par1_peri__WIDTH 1 +#define R_IRQ_MASK1_SET__par1_peri__set 1 +#define R_IRQ_MASK1_SET__par1_peri__nop 0 +#define R_IRQ_MASK1_SET__par1_data__BITNR 17 +#define R_IRQ_MASK1_SET__par1_data__WIDTH 1 +#define R_IRQ_MASK1_SET__par1_data__set 1 +#define R_IRQ_MASK1_SET__par1_data__nop 0 +#define R_IRQ_MASK1_SET__par1_ready__BITNR 16 +#define R_IRQ_MASK1_SET__par1_ready__WIDTH 1 +#define R_IRQ_MASK1_SET__par1_ready__set 1 +#define R_IRQ_MASK1_SET__par1_ready__nop 0 +#define R_IRQ_MASK1_SET__scsi1__BITNR 16 +#define R_IRQ_MASK1_SET__scsi1__WIDTH 1 +#define R_IRQ_MASK1_SET__scsi1__set 1 +#define R_IRQ_MASK1_SET__scsi1__nop 0 +#define R_IRQ_MASK1_SET__ser3_ready__BITNR 15 +#define R_IRQ_MASK1_SET__ser3_ready__WIDTH 1 +#define R_IRQ_MASK1_SET__ser3_ready__set 1 +#define R_IRQ_MASK1_SET__ser3_ready__nop 0 +#define R_IRQ_MASK1_SET__ser3_data__BITNR 14 +#define R_IRQ_MASK1_SET__ser3_data__WIDTH 1 +#define R_IRQ_MASK1_SET__ser3_data__set 1 +#define R_IRQ_MASK1_SET__ser3_data__nop 0 +#define R_IRQ_MASK1_SET__ser2_ready__BITNR 13 +#define R_IRQ_MASK1_SET__ser2_ready__WIDTH 1 +#define R_IRQ_MASK1_SET__ser2_ready__set 1 +#define R_IRQ_MASK1_SET__ser2_ready__nop 0 +#define R_IRQ_MASK1_SET__ser2_data__BITNR 12 +#define R_IRQ_MASK1_SET__ser2_data__WIDTH 1 +#define R_IRQ_MASK1_SET__ser2_data__set 1 +#define R_IRQ_MASK1_SET__ser2_data__nop 0 +#define R_IRQ_MASK1_SET__ser1_ready__BITNR 11 +#define R_IRQ_MASK1_SET__ser1_ready__WIDTH 1 +#define R_IRQ_MASK1_SET__ser1_ready__set 1 +#define R_IRQ_MASK1_SET__ser1_ready__nop 0 +#define R_IRQ_MASK1_SET__ser1_data__BITNR 10 +#define R_IRQ_MASK1_SET__ser1_data__WIDTH 1 +#define R_IRQ_MASK1_SET__ser1_data__set 1 +#define R_IRQ_MASK1_SET__ser1_data__nop 0 +#define R_IRQ_MASK1_SET__ser0_ready__BITNR 9 +#define R_IRQ_MASK1_SET__ser0_ready__WIDTH 1 +#define R_IRQ_MASK1_SET__ser0_ready__set 1 +#define R_IRQ_MASK1_SET__ser0_ready__nop 0 +#define R_IRQ_MASK1_SET__ser0_data__BITNR 8 +#define R_IRQ_MASK1_SET__ser0_data__WIDTH 1 +#define R_IRQ_MASK1_SET__ser0_data__set 1 +#define R_IRQ_MASK1_SET__ser0_data__nop 0 +#define R_IRQ_MASK1_SET__pa7__BITNR 7 +#define R_IRQ_MASK1_SET__pa7__WIDTH 1 +#define R_IRQ_MASK1_SET__pa7__set 1 +#define R_IRQ_MASK1_SET__pa7__nop 0 +#define R_IRQ_MASK1_SET__pa6__BITNR 6 +#define R_IRQ_MASK1_SET__pa6__WIDTH 1 +#define R_IRQ_MASK1_SET__pa6__set 1 +#define R_IRQ_MASK1_SET__pa6__nop 0 +#define R_IRQ_MASK1_SET__pa5__BITNR 5 +#define R_IRQ_MASK1_SET__pa5__WIDTH 1 +#define R_IRQ_MASK1_SET__pa5__set 1 +#define R_IRQ_MASK1_SET__pa5__nop 0 +#define R_IRQ_MASK1_SET__pa4__BITNR 4 +#define R_IRQ_MASK1_SET__pa4__WIDTH 1 +#define R_IRQ_MASK1_SET__pa4__set 1 +#define R_IRQ_MASK1_SET__pa4__nop 0 +#define R_IRQ_MASK1_SET__pa3__BITNR 3 +#define R_IRQ_MASK1_SET__pa3__WIDTH 1 +#define R_IRQ_MASK1_SET__pa3__set 1 +#define R_IRQ_MASK1_SET__pa3__nop 0 +#define R_IRQ_MASK1_SET__pa2__BITNR 2 +#define R_IRQ_MASK1_SET__pa2__WIDTH 1 +#define R_IRQ_MASK1_SET__pa2__set 1 +#define R_IRQ_MASK1_SET__pa2__nop 0 +#define R_IRQ_MASK1_SET__pa1__BITNR 1 +#define R_IRQ_MASK1_SET__pa1__WIDTH 1 +#define R_IRQ_MASK1_SET__pa1__set 1 +#define R_IRQ_MASK1_SET__pa1__nop 0 +#define R_IRQ_MASK1_SET__pa0__BITNR 0 +#define R_IRQ_MASK1_SET__pa0__WIDTH 1 +#define R_IRQ_MASK1_SET__pa0__set 1 +#define R_IRQ_MASK1_SET__pa0__nop 0 + +#define R_IRQ_MASK2_RD (IO_TYPECAST_RO_UDWORD 0xb00000d0) +#define R_IRQ_MASK2_RD__dma8_sub3_descr__BITNR 23 +#define R_IRQ_MASK2_RD__dma8_sub3_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma8_sub3_descr__active 1 +#define R_IRQ_MASK2_RD__dma8_sub3_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma8_sub2_descr__BITNR 22 +#define R_IRQ_MASK2_RD__dma8_sub2_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma8_sub2_descr__active 1 +#define R_IRQ_MASK2_RD__dma8_sub2_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma8_sub1_descr__BITNR 21 +#define R_IRQ_MASK2_RD__dma8_sub1_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma8_sub1_descr__active 1 +#define R_IRQ_MASK2_RD__dma8_sub1_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma8_sub0_descr__BITNR 20 +#define R_IRQ_MASK2_RD__dma8_sub0_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma8_sub0_descr__active 1 +#define R_IRQ_MASK2_RD__dma8_sub0_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma9_eop__BITNR 19 +#define R_IRQ_MASK2_RD__dma9_eop__WIDTH 1 +#define R_IRQ_MASK2_RD__dma9_eop__active 1 +#define R_IRQ_MASK2_RD__dma9_eop__inactive 0 +#define R_IRQ_MASK2_RD__dma9_descr__BITNR 18 +#define R_IRQ_MASK2_RD__dma9_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma9_descr__active 1 +#define R_IRQ_MASK2_RD__dma9_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma8_eop__BITNR 17 +#define R_IRQ_MASK2_RD__dma8_eop__WIDTH 1 +#define R_IRQ_MASK2_RD__dma8_eop__active 1 +#define R_IRQ_MASK2_RD__dma8_eop__inactive 0 +#define R_IRQ_MASK2_RD__dma8_descr__BITNR 16 +#define R_IRQ_MASK2_RD__dma8_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma8_descr__active 1 +#define R_IRQ_MASK2_RD__dma8_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma7_eop__BITNR 15 +#define R_IRQ_MASK2_RD__dma7_eop__WIDTH 1 +#define R_IRQ_MASK2_RD__dma7_eop__active 1 +#define R_IRQ_MASK2_RD__dma7_eop__inactive 0 +#define R_IRQ_MASK2_RD__dma7_descr__BITNR 14 +#define R_IRQ_MASK2_RD__dma7_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma7_descr__active 1 +#define R_IRQ_MASK2_RD__dma7_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma6_eop__BITNR 13 +#define R_IRQ_MASK2_RD__dma6_eop__WIDTH 1 +#define R_IRQ_MASK2_RD__dma6_eop__active 1 +#define R_IRQ_MASK2_RD__dma6_eop__inactive 0 +#define R_IRQ_MASK2_RD__dma6_descr__BITNR 12 +#define R_IRQ_MASK2_RD__dma6_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma6_descr__active 1 +#define R_IRQ_MASK2_RD__dma6_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma5_eop__BITNR 11 +#define R_IRQ_MASK2_RD__dma5_eop__WIDTH 1 +#define R_IRQ_MASK2_RD__dma5_eop__active 1 +#define R_IRQ_MASK2_RD__dma5_eop__inactive 0 +#define R_IRQ_MASK2_RD__dma5_descr__BITNR 10 +#define R_IRQ_MASK2_RD__dma5_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma5_descr__active 1 +#define R_IRQ_MASK2_RD__dma5_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma4_eop__BITNR 9 +#define R_IRQ_MASK2_RD__dma4_eop__WIDTH 1 +#define R_IRQ_MASK2_RD__dma4_eop__active 1 +#define R_IRQ_MASK2_RD__dma4_eop__inactive 0 +#define R_IRQ_MASK2_RD__dma4_descr__BITNR 8 +#define R_IRQ_MASK2_RD__dma4_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma4_descr__active 1 +#define R_IRQ_MASK2_RD__dma4_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma3_eop__BITNR 7 +#define R_IRQ_MASK2_RD__dma3_eop__WIDTH 1 +#define R_IRQ_MASK2_RD__dma3_eop__active 1 +#define R_IRQ_MASK2_RD__dma3_eop__inactive 0 +#define R_IRQ_MASK2_RD__dma3_descr__BITNR 6 +#define R_IRQ_MASK2_RD__dma3_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma3_descr__active 1 +#define R_IRQ_MASK2_RD__dma3_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma2_eop__BITNR 5 +#define R_IRQ_MASK2_RD__dma2_eop__WIDTH 1 +#define R_IRQ_MASK2_RD__dma2_eop__active 1 +#define R_IRQ_MASK2_RD__dma2_eop__inactive 0 +#define R_IRQ_MASK2_RD__dma2_descr__BITNR 4 +#define R_IRQ_MASK2_RD__dma2_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma2_descr__active 1 +#define R_IRQ_MASK2_RD__dma2_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma1_eop__BITNR 3 +#define R_IRQ_MASK2_RD__dma1_eop__WIDTH 1 +#define R_IRQ_MASK2_RD__dma1_eop__active 1 +#define R_IRQ_MASK2_RD__dma1_eop__inactive 0 +#define R_IRQ_MASK2_RD__dma1_descr__BITNR 2 +#define R_IRQ_MASK2_RD__dma1_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma1_descr__active 1 +#define R_IRQ_MASK2_RD__dma1_descr__inactive 0 +#define R_IRQ_MASK2_RD__dma0_eop__BITNR 1 +#define R_IRQ_MASK2_RD__dma0_eop__WIDTH 1 +#define R_IRQ_MASK2_RD__dma0_eop__active 1 +#define R_IRQ_MASK2_RD__dma0_eop__inactive 0 +#define R_IRQ_MASK2_RD__dma0_descr__BITNR 0 +#define R_IRQ_MASK2_RD__dma0_descr__WIDTH 1 +#define R_IRQ_MASK2_RD__dma0_descr__active 1 +#define R_IRQ_MASK2_RD__dma0_descr__inactive 0 + +#define R_IRQ_MASK2_CLR (IO_TYPECAST_UDWORD 0xb00000d0) +#define R_IRQ_MASK2_CLR__dma8_sub3_descr__BITNR 23 +#define R_IRQ_MASK2_CLR__dma8_sub3_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma8_sub3_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma8_sub3_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma8_sub2_descr__BITNR 22 +#define R_IRQ_MASK2_CLR__dma8_sub2_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma8_sub2_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma8_sub2_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma8_sub1_descr__BITNR 21 +#define R_IRQ_MASK2_CLR__dma8_sub1_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma8_sub1_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma8_sub1_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma8_sub0_descr__BITNR 20 +#define R_IRQ_MASK2_CLR__dma8_sub0_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma8_sub0_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma8_sub0_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma9_eop__BITNR 19 +#define R_IRQ_MASK2_CLR__dma9_eop__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma9_eop__clr 1 +#define R_IRQ_MASK2_CLR__dma9_eop__nop 0 +#define R_IRQ_MASK2_CLR__dma9_descr__BITNR 18 +#define R_IRQ_MASK2_CLR__dma9_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma9_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma9_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma8_eop__BITNR 17 +#define R_IRQ_MASK2_CLR__dma8_eop__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma8_eop__clr 1 +#define R_IRQ_MASK2_CLR__dma8_eop__nop 0 +#define R_IRQ_MASK2_CLR__dma8_descr__BITNR 16 +#define R_IRQ_MASK2_CLR__dma8_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma8_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma8_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma7_eop__BITNR 15 +#define R_IRQ_MASK2_CLR__dma7_eop__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma7_eop__clr 1 +#define R_IRQ_MASK2_CLR__dma7_eop__nop 0 +#define R_IRQ_MASK2_CLR__dma7_descr__BITNR 14 +#define R_IRQ_MASK2_CLR__dma7_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma7_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma7_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma6_eop__BITNR 13 +#define R_IRQ_MASK2_CLR__dma6_eop__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma6_eop__clr 1 +#define R_IRQ_MASK2_CLR__dma6_eop__nop 0 +#define R_IRQ_MASK2_CLR__dma6_descr__BITNR 12 +#define R_IRQ_MASK2_CLR__dma6_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma6_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma6_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma5_eop__BITNR 11 +#define R_IRQ_MASK2_CLR__dma5_eop__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma5_eop__clr 1 +#define R_IRQ_MASK2_CLR__dma5_eop__nop 0 +#define R_IRQ_MASK2_CLR__dma5_descr__BITNR 10 +#define R_IRQ_MASK2_CLR__dma5_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma5_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma5_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma4_eop__BITNR 9 +#define R_IRQ_MASK2_CLR__dma4_eop__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma4_eop__clr 1 +#define R_IRQ_MASK2_CLR__dma4_eop__nop 0 +#define R_IRQ_MASK2_CLR__dma4_descr__BITNR 8 +#define R_IRQ_MASK2_CLR__dma4_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma4_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma4_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma3_eop__BITNR 7 +#define R_IRQ_MASK2_CLR__dma3_eop__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma3_eop__clr 1 +#define R_IRQ_MASK2_CLR__dma3_eop__nop 0 +#define R_IRQ_MASK2_CLR__dma3_descr__BITNR 6 +#define R_IRQ_MASK2_CLR__dma3_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma3_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma3_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma2_eop__BITNR 5 +#define R_IRQ_MASK2_CLR__dma2_eop__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma2_eop__clr 1 +#define R_IRQ_MASK2_CLR__dma2_eop__nop 0 +#define R_IRQ_MASK2_CLR__dma2_descr__BITNR 4 +#define R_IRQ_MASK2_CLR__dma2_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma2_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma2_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma1_eop__BITNR 3 +#define R_IRQ_MASK2_CLR__dma1_eop__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma1_eop__clr 1 +#define R_IRQ_MASK2_CLR__dma1_eop__nop 0 +#define R_IRQ_MASK2_CLR__dma1_descr__BITNR 2 +#define R_IRQ_MASK2_CLR__dma1_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma1_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma1_descr__nop 0 +#define R_IRQ_MASK2_CLR__dma0_eop__BITNR 1 +#define R_IRQ_MASK2_CLR__dma0_eop__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma0_eop__clr 1 +#define R_IRQ_MASK2_CLR__dma0_eop__nop 0 +#define R_IRQ_MASK2_CLR__dma0_descr__BITNR 0 +#define R_IRQ_MASK2_CLR__dma0_descr__WIDTH 1 +#define R_IRQ_MASK2_CLR__dma0_descr__clr 1 +#define R_IRQ_MASK2_CLR__dma0_descr__nop 0 + +#define R_IRQ_READ2 (IO_TYPECAST_RO_UDWORD 0xb00000d4) +#define R_IRQ_READ2__dma8_sub3_descr__BITNR 23 +#define R_IRQ_READ2__dma8_sub3_descr__WIDTH 1 +#define R_IRQ_READ2__dma8_sub3_descr__active 1 +#define R_IRQ_READ2__dma8_sub3_descr__inactive 0 +#define R_IRQ_READ2__dma8_sub2_descr__BITNR 22 +#define R_IRQ_READ2__dma8_sub2_descr__WIDTH 1 +#define R_IRQ_READ2__dma8_sub2_descr__active 1 +#define R_IRQ_READ2__dma8_sub2_descr__inactive 0 +#define R_IRQ_READ2__dma8_sub1_descr__BITNR 21 +#define R_IRQ_READ2__dma8_sub1_descr__WIDTH 1 +#define R_IRQ_READ2__dma8_sub1_descr__active 1 +#define R_IRQ_READ2__dma8_sub1_descr__inactive 0 +#define R_IRQ_READ2__dma8_sub0_descr__BITNR 20 +#define R_IRQ_READ2__dma8_sub0_descr__WIDTH 1 +#define R_IRQ_READ2__dma8_sub0_descr__active 1 +#define R_IRQ_READ2__dma8_sub0_descr__inactive 0 +#define R_IRQ_READ2__dma9_eop__BITNR 19 +#define R_IRQ_READ2__dma9_eop__WIDTH 1 +#define R_IRQ_READ2__dma9_eop__active 1 +#define R_IRQ_READ2__dma9_eop__inactive 0 +#define R_IRQ_READ2__dma9_descr__BITNR 18 +#define R_IRQ_READ2__dma9_descr__WIDTH 1 +#define R_IRQ_READ2__dma9_descr__active 1 +#define R_IRQ_READ2__dma9_descr__inactive 0 +#define R_IRQ_READ2__dma8_eop__BITNR 17 +#define R_IRQ_READ2__dma8_eop__WIDTH 1 +#define R_IRQ_READ2__dma8_eop__active 1 +#define R_IRQ_READ2__dma8_eop__inactive 0 +#define R_IRQ_READ2__dma8_descr__BITNR 16 +#define R_IRQ_READ2__dma8_descr__WIDTH 1 +#define R_IRQ_READ2__dma8_descr__active 1 +#define R_IRQ_READ2__dma8_descr__inactive 0 +#define R_IRQ_READ2__dma7_eop__BITNR 15 +#define R_IRQ_READ2__dma7_eop__WIDTH 1 +#define R_IRQ_READ2__dma7_eop__active 1 +#define R_IRQ_READ2__dma7_eop__inactive 0 +#define R_IRQ_READ2__dma7_descr__BITNR 14 +#define R_IRQ_READ2__dma7_descr__WIDTH 1 +#define R_IRQ_READ2__dma7_descr__active 1 +#define R_IRQ_READ2__dma7_descr__inactive 0 +#define R_IRQ_READ2__dma6_eop__BITNR 13 +#define R_IRQ_READ2__dma6_eop__WIDTH 1 +#define R_IRQ_READ2__dma6_eop__active 1 +#define R_IRQ_READ2__dma6_eop__inactive 0 +#define R_IRQ_READ2__dma6_descr__BITNR 12 +#define R_IRQ_READ2__dma6_descr__WIDTH 1 +#define R_IRQ_READ2__dma6_descr__active 1 +#define R_IRQ_READ2__dma6_descr__inactive 0 +#define R_IRQ_READ2__dma5_eop__BITNR 11 +#define R_IRQ_READ2__dma5_eop__WIDTH 1 +#define R_IRQ_READ2__dma5_eop__active 1 +#define R_IRQ_READ2__dma5_eop__inactive 0 +#define R_IRQ_READ2__dma5_descr__BITNR 10 +#define R_IRQ_READ2__dma5_descr__WIDTH 1 +#define R_IRQ_READ2__dma5_descr__active 1 +#define R_IRQ_READ2__dma5_descr__inactive 0 +#define R_IRQ_READ2__dma4_eop__BITNR 9 +#define R_IRQ_READ2__dma4_eop__WIDTH 1 +#define R_IRQ_READ2__dma4_eop__active 1 +#define R_IRQ_READ2__dma4_eop__inactive 0 +#define R_IRQ_READ2__dma4_descr__BITNR 8 +#define R_IRQ_READ2__dma4_descr__WIDTH 1 +#define R_IRQ_READ2__dma4_descr__active 1 +#define R_IRQ_READ2__dma4_descr__inactive 0 +#define R_IRQ_READ2__dma3_eop__BITNR 7 +#define R_IRQ_READ2__dma3_eop__WIDTH 1 +#define R_IRQ_READ2__dma3_eop__active 1 +#define R_IRQ_READ2__dma3_eop__inactive 0 +#define R_IRQ_READ2__dma3_descr__BITNR 6 +#define R_IRQ_READ2__dma3_descr__WIDTH 1 +#define R_IRQ_READ2__dma3_descr__active 1 +#define R_IRQ_READ2__dma3_descr__inactive 0 +#define R_IRQ_READ2__dma2_eop__BITNR 5 +#define R_IRQ_READ2__dma2_eop__WIDTH 1 +#define R_IRQ_READ2__dma2_eop__active 1 +#define R_IRQ_READ2__dma2_eop__inactive 0 +#define R_IRQ_READ2__dma2_descr__BITNR 4 +#define R_IRQ_READ2__dma2_descr__WIDTH 1 +#define R_IRQ_READ2__dma2_descr__active 1 +#define R_IRQ_READ2__dma2_descr__inactive 0 +#define R_IRQ_READ2__dma1_eop__BITNR 3 +#define R_IRQ_READ2__dma1_eop__WIDTH 1 +#define R_IRQ_READ2__dma1_eop__active 1 +#define R_IRQ_READ2__dma1_eop__inactive 0 +#define R_IRQ_READ2__dma1_descr__BITNR 2 +#define R_IRQ_READ2__dma1_descr__WIDTH 1 +#define R_IRQ_READ2__dma1_descr__active 1 +#define R_IRQ_READ2__dma1_descr__inactive 0 +#define R_IRQ_READ2__dma0_eop__BITNR 1 +#define R_IRQ_READ2__dma0_eop__WIDTH 1 +#define R_IRQ_READ2__dma0_eop__active 1 +#define R_IRQ_READ2__dma0_eop__inactive 0 +#define R_IRQ_READ2__dma0_descr__BITNR 0 +#define R_IRQ_READ2__dma0_descr__WIDTH 1 +#define R_IRQ_READ2__dma0_descr__active 1 +#define R_IRQ_READ2__dma0_descr__inactive 0 + +#define R_IRQ_MASK2_SET (IO_TYPECAST_UDWORD 0xb00000d4) +#define R_IRQ_MASK2_SET__dma8_sub3_descr__BITNR 23 +#define R_IRQ_MASK2_SET__dma8_sub3_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma8_sub3_descr__set 1 +#define R_IRQ_MASK2_SET__dma8_sub3_descr__nop 0 +#define R_IRQ_MASK2_SET__dma8_sub2_descr__BITNR 22 +#define R_IRQ_MASK2_SET__dma8_sub2_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma8_sub2_descr__set 1 +#define R_IRQ_MASK2_SET__dma8_sub2_descr__nop 0 +#define R_IRQ_MASK2_SET__dma8_sub1_descr__BITNR 21 +#define R_IRQ_MASK2_SET__dma8_sub1_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma8_sub1_descr__set 1 +#define R_IRQ_MASK2_SET__dma8_sub1_descr__nop 0 +#define R_IRQ_MASK2_SET__dma8_sub0_descr__BITNR 20 +#define R_IRQ_MASK2_SET__dma8_sub0_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma8_sub0_descr__set 1 +#define R_IRQ_MASK2_SET__dma8_sub0_descr__nop 0 +#define R_IRQ_MASK2_SET__dma9_eop__BITNR 19 +#define R_IRQ_MASK2_SET__dma9_eop__WIDTH 1 +#define R_IRQ_MASK2_SET__dma9_eop__set 1 +#define R_IRQ_MASK2_SET__dma9_eop__nop 0 +#define R_IRQ_MASK2_SET__dma9_descr__BITNR 18 +#define R_IRQ_MASK2_SET__dma9_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma9_descr__set 1 +#define R_IRQ_MASK2_SET__dma9_descr__nop 0 +#define R_IRQ_MASK2_SET__dma8_eop__BITNR 17 +#define R_IRQ_MASK2_SET__dma8_eop__WIDTH 1 +#define R_IRQ_MASK2_SET__dma8_eop__set 1 +#define R_IRQ_MASK2_SET__dma8_eop__nop 0 +#define R_IRQ_MASK2_SET__dma8_descr__BITNR 16 +#define R_IRQ_MASK2_SET__dma8_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma8_descr__set 1 +#define R_IRQ_MASK2_SET__dma8_descr__nop 0 +#define R_IRQ_MASK2_SET__dma7_eop__BITNR 15 +#define R_IRQ_MASK2_SET__dma7_eop__WIDTH 1 +#define R_IRQ_MASK2_SET__dma7_eop__set 1 +#define R_IRQ_MASK2_SET__dma7_eop__nop 0 +#define R_IRQ_MASK2_SET__dma7_descr__BITNR 14 +#define R_IRQ_MASK2_SET__dma7_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma7_descr__set 1 +#define R_IRQ_MASK2_SET__dma7_descr__nop 0 +#define R_IRQ_MASK2_SET__dma6_eop__BITNR 13 +#define R_IRQ_MASK2_SET__dma6_eop__WIDTH 1 +#define R_IRQ_MASK2_SET__dma6_eop__set 1 +#define R_IRQ_MASK2_SET__dma6_eop__nop 0 +#define R_IRQ_MASK2_SET__dma6_descr__BITNR 12 +#define R_IRQ_MASK2_SET__dma6_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma6_descr__set 1 +#define R_IRQ_MASK2_SET__dma6_descr__nop 0 +#define R_IRQ_MASK2_SET__dma5_eop__BITNR 11 +#define R_IRQ_MASK2_SET__dma5_eop__WIDTH 1 +#define R_IRQ_MASK2_SET__dma5_eop__set 1 +#define R_IRQ_MASK2_SET__dma5_eop__nop 0 +#define R_IRQ_MASK2_SET__dma5_descr__BITNR 10 +#define R_IRQ_MASK2_SET__dma5_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma5_descr__set 1 +#define R_IRQ_MASK2_SET__dma5_descr__nop 0 +#define R_IRQ_MASK2_SET__dma4_eop__BITNR 9 +#define R_IRQ_MASK2_SET__dma4_eop__WIDTH 1 +#define R_IRQ_MASK2_SET__dma4_eop__set 1 +#define R_IRQ_MASK2_SET__dma4_eop__nop 0 +#define R_IRQ_MASK2_SET__dma4_descr__BITNR 8 +#define R_IRQ_MASK2_SET__dma4_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma4_descr__set 1 +#define R_IRQ_MASK2_SET__dma4_descr__nop 0 +#define R_IRQ_MASK2_SET__dma3_eop__BITNR 7 +#define R_IRQ_MASK2_SET__dma3_eop__WIDTH 1 +#define R_IRQ_MASK2_SET__dma3_eop__set 1 +#define R_IRQ_MASK2_SET__dma3_eop__nop 0 +#define R_IRQ_MASK2_SET__dma3_descr__BITNR 6 +#define R_IRQ_MASK2_SET__dma3_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma3_descr__set 1 +#define R_IRQ_MASK2_SET__dma3_descr__nop 0 +#define R_IRQ_MASK2_SET__dma2_eop__BITNR 5 +#define R_IRQ_MASK2_SET__dma2_eop__WIDTH 1 +#define R_IRQ_MASK2_SET__dma2_eop__set 1 +#define R_IRQ_MASK2_SET__dma2_eop__nop 0 +#define R_IRQ_MASK2_SET__dma2_descr__BITNR 4 +#define R_IRQ_MASK2_SET__dma2_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma2_descr__set 1 +#define R_IRQ_MASK2_SET__dma2_descr__nop 0 +#define R_IRQ_MASK2_SET__dma1_eop__BITNR 3 +#define R_IRQ_MASK2_SET__dma1_eop__WIDTH 1 +#define R_IRQ_MASK2_SET__dma1_eop__set 1 +#define R_IRQ_MASK2_SET__dma1_eop__nop 0 +#define R_IRQ_MASK2_SET__dma1_descr__BITNR 2 +#define R_IRQ_MASK2_SET__dma1_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma1_descr__set 1 +#define R_IRQ_MASK2_SET__dma1_descr__nop 0 +#define R_IRQ_MASK2_SET__dma0_eop__BITNR 1 +#define R_IRQ_MASK2_SET__dma0_eop__WIDTH 1 +#define R_IRQ_MASK2_SET__dma0_eop__set 1 +#define R_IRQ_MASK2_SET__dma0_eop__nop 0 +#define R_IRQ_MASK2_SET__dma0_descr__BITNR 0 +#define R_IRQ_MASK2_SET__dma0_descr__WIDTH 1 +#define R_IRQ_MASK2_SET__dma0_descr__set 1 +#define R_IRQ_MASK2_SET__dma0_descr__nop 0 + +#define R_VECT_MASK_RD (IO_TYPECAST_RO_UDWORD 0xb00000d8) +#define R_VECT_MASK_RD__usb__BITNR 31 +#define R_VECT_MASK_RD__usb__WIDTH 1 +#define R_VECT_MASK_RD__usb__active 1 +#define R_VECT_MASK_RD__usb__inactive 0 +#define R_VECT_MASK_RD__dma9__BITNR 25 +#define R_VECT_MASK_RD__dma9__WIDTH 1 +#define R_VECT_MASK_RD__dma9__active 1 +#define R_VECT_MASK_RD__dma9__inactive 0 +#define R_VECT_MASK_RD__dma8__BITNR 24 +#define R_VECT_MASK_RD__dma8__WIDTH 1 +#define R_VECT_MASK_RD__dma8__active 1 +#define R_VECT_MASK_RD__dma8__inactive 0 +#define R_VECT_MASK_RD__dma7__BITNR 23 +#define R_VECT_MASK_RD__dma7__WIDTH 1 +#define R_VECT_MASK_RD__dma7__active 1 +#define R_VECT_MASK_RD__dma7__inactive 0 +#define R_VECT_MASK_RD__dma6__BITNR 22 +#define R_VECT_MASK_RD__dma6__WIDTH 1 +#define R_VECT_MASK_RD__dma6__active 1 +#define R_VECT_MASK_RD__dma6__inactive 0 +#define R_VECT_MASK_RD__dma5__BITNR 21 +#define R_VECT_MASK_RD__dma5__WIDTH 1 +#define R_VECT_MASK_RD__dma5__active 1 +#define R_VECT_MASK_RD__dma5__inactive 0 +#define R_VECT_MASK_RD__dma4__BITNR 20 +#define R_VECT_MASK_RD__dma4__WIDTH 1 +#define R_VECT_MASK_RD__dma4__active 1 +#define R_VECT_MASK_RD__dma4__inactive 0 +#define R_VECT_MASK_RD__dma3__BITNR 19 +#define R_VECT_MASK_RD__dma3__WIDTH 1 +#define R_VECT_MASK_RD__dma3__active 1 +#define R_VECT_MASK_RD__dma3__inactive 0 +#define R_VECT_MASK_RD__dma2__BITNR 18 +#define R_VECT_MASK_RD__dma2__WIDTH 1 +#define R_VECT_MASK_RD__dma2__active 1 +#define R_VECT_MASK_RD__dma2__inactive 0 +#define R_VECT_MASK_RD__dma1__BITNR 17 +#define R_VECT_MASK_RD__dma1__WIDTH 1 +#define R_VECT_MASK_RD__dma1__active 1 +#define R_VECT_MASK_RD__dma1__inactive 0 +#define R_VECT_MASK_RD__dma0__BITNR 16 +#define R_VECT_MASK_RD__dma0__WIDTH 1 +#define R_VECT_MASK_RD__dma0__active 1 +#define R_VECT_MASK_RD__dma0__inactive 0 +#define R_VECT_MASK_RD__ext_dma1__BITNR 13 +#define R_VECT_MASK_RD__ext_dma1__WIDTH 1 +#define R_VECT_MASK_RD__ext_dma1__active 1 +#define R_VECT_MASK_RD__ext_dma1__inactive 0 +#define R_VECT_MASK_RD__ext_dma0__BITNR 12 +#define R_VECT_MASK_RD__ext_dma0__WIDTH 1 +#define R_VECT_MASK_RD__ext_dma0__active 1 +#define R_VECT_MASK_RD__ext_dma0__inactive 0 +#define R_VECT_MASK_RD__pa__BITNR 11 +#define R_VECT_MASK_RD__pa__WIDTH 1 +#define R_VECT_MASK_RD__pa__active 1 +#define R_VECT_MASK_RD__pa__inactive 0 +#define R_VECT_MASK_RD__irq_intnr__BITNR 10 +#define R_VECT_MASK_RD__irq_intnr__WIDTH 1 +#define R_VECT_MASK_RD__irq_intnr__active 1 +#define R_VECT_MASK_RD__irq_intnr__inactive 0 +#define R_VECT_MASK_RD__sw__BITNR 9 +#define R_VECT_MASK_RD__sw__WIDTH 1 +#define R_VECT_MASK_RD__sw__active 1 +#define R_VECT_MASK_RD__sw__inactive 0 +#define R_VECT_MASK_RD__serial__BITNR 8 +#define R_VECT_MASK_RD__serial__WIDTH 1 +#define R_VECT_MASK_RD__serial__active 1 +#define R_VECT_MASK_RD__serial__inactive 0 +#define R_VECT_MASK_RD__snmp__BITNR 7 +#define R_VECT_MASK_RD__snmp__WIDTH 1 +#define R_VECT_MASK_RD__snmp__active 1 +#define R_VECT_MASK_RD__snmp__inactive 0 +#define R_VECT_MASK_RD__network__BITNR 6 +#define R_VECT_MASK_RD__network__WIDTH 1 +#define R_VECT_MASK_RD__network__active 1 +#define R_VECT_MASK_RD__network__inactive 0 +#define R_VECT_MASK_RD__scsi1__BITNR 5 +#define R_VECT_MASK_RD__scsi1__WIDTH 1 +#define R_VECT_MASK_RD__scsi1__active 1 +#define R_VECT_MASK_RD__scsi1__inactive 0 +#define R_VECT_MASK_RD__par1__BITNR 5 +#define R_VECT_MASK_RD__par1__WIDTH 1 +#define R_VECT_MASK_RD__par1__active 1 +#define R_VECT_MASK_RD__par1__inactive 0 +#define R_VECT_MASK_RD__scsi0__BITNR 4 +#define R_VECT_MASK_RD__scsi0__WIDTH 1 +#define R_VECT_MASK_RD__scsi0__active 1 +#define R_VECT_MASK_RD__scsi0__inactive 0 +#define R_VECT_MASK_RD__par0__BITNR 4 +#define R_VECT_MASK_RD__par0__WIDTH 1 +#define R_VECT_MASK_RD__par0__active 1 +#define R_VECT_MASK_RD__par0__inactive 0 +#define R_VECT_MASK_RD__ata__BITNR 4 +#define R_VECT_MASK_RD__ata__WIDTH 1 +#define R_VECT_MASK_RD__ata__active 1 +#define R_VECT_MASK_RD__ata__inactive 0 +#define R_VECT_MASK_RD__mio__BITNR 4 +#define R_VECT_MASK_RD__mio__WIDTH 1 +#define R_VECT_MASK_RD__mio__active 1 +#define R_VECT_MASK_RD__mio__inactive 0 +#define R_VECT_MASK_RD__timer1__BITNR 3 +#define R_VECT_MASK_RD__timer1__WIDTH 1 +#define R_VECT_MASK_RD__timer1__active 1 +#define R_VECT_MASK_RD__timer1__inactive 0 +#define R_VECT_MASK_RD__timer0__BITNR 2 +#define R_VECT_MASK_RD__timer0__WIDTH 1 +#define R_VECT_MASK_RD__timer0__active 1 +#define R_VECT_MASK_RD__timer0__inactive 0 +#define R_VECT_MASK_RD__nmi__BITNR 1 +#define R_VECT_MASK_RD__nmi__WIDTH 1 +#define R_VECT_MASK_RD__nmi__active 1 +#define R_VECT_MASK_RD__nmi__inactive 0 +#define R_VECT_MASK_RD__some__BITNR 0 +#define R_VECT_MASK_RD__some__WIDTH 1 +#define R_VECT_MASK_RD__some__active 1 +#define R_VECT_MASK_RD__some__inactive 0 + +#define R_VECT_MASK_CLR (IO_TYPECAST_UDWORD 0xb00000d8) +#define R_VECT_MASK_CLR__usb__BITNR 31 +#define R_VECT_MASK_CLR__usb__WIDTH 1 +#define R_VECT_MASK_CLR__usb__clr 1 +#define R_VECT_MASK_CLR__usb__nop 0 +#define R_VECT_MASK_CLR__dma9__BITNR 25 +#define R_VECT_MASK_CLR__dma9__WIDTH 1 +#define R_VECT_MASK_CLR__dma9__clr 1 +#define R_VECT_MASK_CLR__dma9__nop 0 +#define R_VECT_MASK_CLR__dma8__BITNR 24 +#define R_VECT_MASK_CLR__dma8__WIDTH 1 +#define R_VECT_MASK_CLR__dma8__clr 1 +#define R_VECT_MASK_CLR__dma8__nop 0 +#define R_VECT_MASK_CLR__dma7__BITNR 23 +#define R_VECT_MASK_CLR__dma7__WIDTH 1 +#define R_VECT_MASK_CLR__dma7__clr 1 +#define R_VECT_MASK_CLR__dma7__nop 0 +#define R_VECT_MASK_CLR__dma6__BITNR 22 +#define R_VECT_MASK_CLR__dma6__WIDTH 1 +#define R_VECT_MASK_CLR__dma6__clr 1 +#define R_VECT_MASK_CLR__dma6__nop 0 +#define R_VECT_MASK_CLR__dma5__BITNR 21 +#define R_VECT_MASK_CLR__dma5__WIDTH 1 +#define R_VECT_MASK_CLR__dma5__clr 1 +#define R_VECT_MASK_CLR__dma5__nop 0 +#define R_VECT_MASK_CLR__dma4__BITNR 20 +#define R_VECT_MASK_CLR__dma4__WIDTH 1 +#define R_VECT_MASK_CLR__dma4__clr 1 +#define R_VECT_MASK_CLR__dma4__nop 0 +#define R_VECT_MASK_CLR__dma3__BITNR 19 +#define R_VECT_MASK_CLR__dma3__WIDTH 1 +#define R_VECT_MASK_CLR__dma3__clr 1 +#define R_VECT_MASK_CLR__dma3__nop 0 +#define R_VECT_MASK_CLR__dma2__BITNR 18 +#define R_VECT_MASK_CLR__dma2__WIDTH 1 +#define R_VECT_MASK_CLR__dma2__clr 1 +#define R_VECT_MASK_CLR__dma2__nop 0 +#define R_VECT_MASK_CLR__dma1__BITNR 17 +#define R_VECT_MASK_CLR__dma1__WIDTH 1 +#define R_VECT_MASK_CLR__dma1__clr 1 +#define R_VECT_MASK_CLR__dma1__nop 0 +#define R_VECT_MASK_CLR__dma0__BITNR 16 +#define R_VECT_MASK_CLR__dma0__WIDTH 1 +#define R_VECT_MASK_CLR__dma0__clr 1 +#define R_VECT_MASK_CLR__dma0__nop 0 +#define R_VECT_MASK_CLR__ext_dma1__BITNR 13 +#define R_VECT_MASK_CLR__ext_dma1__WIDTH 1 +#define R_VECT_MASK_CLR__ext_dma1__clr 1 +#define R_VECT_MASK_CLR__ext_dma1__nop 0 +#define R_VECT_MASK_CLR__ext_dma0__BITNR 12 +#define R_VECT_MASK_CLR__ext_dma0__WIDTH 1 +#define R_VECT_MASK_CLR__ext_dma0__clr 1 +#define R_VECT_MASK_CLR__ext_dma0__nop 0 +#define R_VECT_MASK_CLR__pa__BITNR 11 +#define R_VECT_MASK_CLR__pa__WIDTH 1 +#define R_VECT_MASK_CLR__pa__clr 1 +#define R_VECT_MASK_CLR__pa__nop 0 +#define R_VECT_MASK_CLR__irq_intnr__BITNR 10 +#define R_VECT_MASK_CLR__irq_intnr__WIDTH 1 +#define R_VECT_MASK_CLR__irq_intnr__clr 1 +#define R_VECT_MASK_CLR__irq_intnr__nop 0 +#define R_VECT_MASK_CLR__sw__BITNR 9 +#define R_VECT_MASK_CLR__sw__WIDTH 1 +#define R_VECT_MASK_CLR__sw__clr 1 +#define R_VECT_MASK_CLR__sw__nop 0 +#define R_VECT_MASK_CLR__serial__BITNR 8 +#define R_VECT_MASK_CLR__serial__WIDTH 1 +#define R_VECT_MASK_CLR__serial__clr 1 +#define R_VECT_MASK_CLR__serial__nop 0 +#define R_VECT_MASK_CLR__snmp__BITNR 7 +#define R_VECT_MASK_CLR__snmp__WIDTH 1 +#define R_VECT_MASK_CLR__snmp__clr 1 +#define R_VECT_MASK_CLR__snmp__nop 0 +#define R_VECT_MASK_CLR__network__BITNR 6 +#define R_VECT_MASK_CLR__network__WIDTH 1 +#define R_VECT_MASK_CLR__network__clr 1 +#define R_VECT_MASK_CLR__network__nop 0 +#define R_VECT_MASK_CLR__scsi1__BITNR 5 +#define R_VECT_MASK_CLR__scsi1__WIDTH 1 +#define R_VECT_MASK_CLR__scsi1__clr 1 +#define R_VECT_MASK_CLR__scsi1__nop 0 +#define R_VECT_MASK_CLR__par1__BITNR 5 +#define R_VECT_MASK_CLR__par1__WIDTH 1 +#define R_VECT_MASK_CLR__par1__clr 1 +#define R_VECT_MASK_CLR__par1__nop 0 +#define R_VECT_MASK_CLR__scsi0__BITNR 4 +#define R_VECT_MASK_CLR__scsi0__WIDTH 1 +#define R_VECT_MASK_CLR__scsi0__clr 1 +#define R_VECT_MASK_CLR__scsi0__nop 0 +#define R_VECT_MASK_CLR__par0__BITNR 4 +#define R_VECT_MASK_CLR__par0__WIDTH 1 +#define R_VECT_MASK_CLR__par0__clr 1 +#define R_VECT_MASK_CLR__par0__nop 0 +#define R_VECT_MASK_CLR__ata__BITNR 4 +#define R_VECT_MASK_CLR__ata__WIDTH 1 +#define R_VECT_MASK_CLR__ata__clr 1 +#define R_VECT_MASK_CLR__ata__nop 0 +#define R_VECT_MASK_CLR__mio__BITNR 4 +#define R_VECT_MASK_CLR__mio__WIDTH 1 +#define R_VECT_MASK_CLR__mio__clr 1 +#define R_VECT_MASK_CLR__mio__nop 0 +#define R_VECT_MASK_CLR__timer1__BITNR 3 +#define R_VECT_MASK_CLR__timer1__WIDTH 1 +#define R_VECT_MASK_CLR__timer1__clr 1 +#define R_VECT_MASK_CLR__timer1__nop 0 +#define R_VECT_MASK_CLR__timer0__BITNR 2 +#define R_VECT_MASK_CLR__timer0__WIDTH 1 +#define R_VECT_MASK_CLR__timer0__clr 1 +#define R_VECT_MASK_CLR__timer0__nop 0 +#define R_VECT_MASK_CLR__nmi__BITNR 1 +#define R_VECT_MASK_CLR__nmi__WIDTH 1 +#define R_VECT_MASK_CLR__nmi__clr 1 +#define R_VECT_MASK_CLR__nmi__nop 0 +#define R_VECT_MASK_CLR__some__BITNR 0 +#define R_VECT_MASK_CLR__some__WIDTH 1 +#define R_VECT_MASK_CLR__some__clr 1 +#define R_VECT_MASK_CLR__some__nop 0 + +#define R_VECT_READ (IO_TYPECAST_RO_UDWORD 0xb00000dc) +#define R_VECT_READ__usb__BITNR 31 +#define R_VECT_READ__usb__WIDTH 1 +#define R_VECT_READ__usb__active 1 +#define R_VECT_READ__usb__inactive 0 +#define R_VECT_READ__dma9__BITNR 25 +#define R_VECT_READ__dma9__WIDTH 1 +#define R_VECT_READ__dma9__active 1 +#define R_VECT_READ__dma9__inactive 0 +#define R_VECT_READ__dma8__BITNR 24 +#define R_VECT_READ__dma8__WIDTH 1 +#define R_VECT_READ__dma8__active 1 +#define R_VECT_READ__dma8__inactive 0 +#define R_VECT_READ__dma7__BITNR 23 +#define R_VECT_READ__dma7__WIDTH 1 +#define R_VECT_READ__dma7__active 1 +#define R_VECT_READ__dma7__inactive 0 +#define R_VECT_READ__dma6__BITNR 22 +#define R_VECT_READ__dma6__WIDTH 1 +#define R_VECT_READ__dma6__active 1 +#define R_VECT_READ__dma6__inactive 0 +#define R_VECT_READ__dma5__BITNR 21 +#define R_VECT_READ__dma5__WIDTH 1 +#define R_VECT_READ__dma5__active 1 +#define R_VECT_READ__dma5__inactive 0 +#define R_VECT_READ__dma4__BITNR 20 +#define R_VECT_READ__dma4__WIDTH 1 +#define R_VECT_READ__dma4__active 1 +#define R_VECT_READ__dma4__inactive 0 +#define R_VECT_READ__dma3__BITNR 19 +#define R_VECT_READ__dma3__WIDTH 1 +#define R_VECT_READ__dma3__active 1 +#define R_VECT_READ__dma3__inactive 0 +#define R_VECT_READ__dma2__BITNR 18 +#define R_VECT_READ__dma2__WIDTH 1 +#define R_VECT_READ__dma2__active 1 +#define R_VECT_READ__dma2__inactive 0 +#define R_VECT_READ__dma1__BITNR 17 +#define R_VECT_READ__dma1__WIDTH 1 +#define R_VECT_READ__dma1__active 1 +#define R_VECT_READ__dma1__inactive 0 +#define R_VECT_READ__dma0__BITNR 16 +#define R_VECT_READ__dma0__WIDTH 1 +#define R_VECT_READ__dma0__active 1 +#define R_VECT_READ__dma0__inactive 0 +#define R_VECT_READ__ext_dma1__BITNR 13 +#define R_VECT_READ__ext_dma1__WIDTH 1 +#define R_VECT_READ__ext_dma1__active 1 +#define R_VECT_READ__ext_dma1__inactive 0 +#define R_VECT_READ__ext_dma0__BITNR 12 +#define R_VECT_READ__ext_dma0__WIDTH 1 +#define R_VECT_READ__ext_dma0__active 1 +#define R_VECT_READ__ext_dma0__inactive 0 +#define R_VECT_READ__pa__BITNR 11 +#define R_VECT_READ__pa__WIDTH 1 +#define R_VECT_READ__pa__active 1 +#define R_VECT_READ__pa__inactive 0 +#define R_VECT_READ__irq_intnr__BITNR 10 +#define R_VECT_READ__irq_intnr__WIDTH 1 +#define R_VECT_READ__irq_intnr__active 1 +#define R_VECT_READ__irq_intnr__inactive 0 +#define R_VECT_READ__sw__BITNR 9 +#define R_VECT_READ__sw__WIDTH 1 +#define R_VECT_READ__sw__active 1 +#define R_VECT_READ__sw__inactive 0 +#define R_VECT_READ__serial__BITNR 8 +#define R_VECT_READ__serial__WIDTH 1 +#define R_VECT_READ__serial__active 1 +#define R_VECT_READ__serial__inactive 0 +#define R_VECT_READ__snmp__BITNR 7 +#define R_VECT_READ__snmp__WIDTH 1 +#define R_VECT_READ__snmp__active 1 +#define R_VECT_READ__snmp__inactive 0 +#define R_VECT_READ__network__BITNR 6 +#define R_VECT_READ__network__WIDTH 1 +#define R_VECT_READ__network__active 1 +#define R_VECT_READ__network__inactive 0 +#define R_VECT_READ__scsi1__BITNR 5 +#define R_VECT_READ__scsi1__WIDTH 1 +#define R_VECT_READ__scsi1__active 1 +#define R_VECT_READ__scsi1__inactive 0 +#define R_VECT_READ__par1__BITNR 5 +#define R_VECT_READ__par1__WIDTH 1 +#define R_VECT_READ__par1__active 1 +#define R_VECT_READ__par1__inactive 0 +#define R_VECT_READ__scsi0__BITNR 4 +#define R_VECT_READ__scsi0__WIDTH 1 +#define R_VECT_READ__scsi0__active 1 +#define R_VECT_READ__scsi0__inactive 0 +#define R_VECT_READ__par0__BITNR 4 +#define R_VECT_READ__par0__WIDTH 1 +#define R_VECT_READ__par0__active 1 +#define R_VECT_READ__par0__inactive 0 +#define R_VECT_READ__ata__BITNR 4 +#define R_VECT_READ__ata__WIDTH 1 +#define R_VECT_READ__ata__active 1 +#define R_VECT_READ__ata__inactive 0 +#define R_VECT_READ__mio__BITNR 4 +#define R_VECT_READ__mio__WIDTH 1 +#define R_VECT_READ__mio__active 1 +#define R_VECT_READ__mio__inactive 0 +#define R_VECT_READ__timer1__BITNR 3 +#define R_VECT_READ__timer1__WIDTH 1 +#define R_VECT_READ__timer1__active 1 +#define R_VECT_READ__timer1__inactive 0 +#define R_VECT_READ__timer0__BITNR 2 +#define R_VECT_READ__timer0__WIDTH 1 +#define R_VECT_READ__timer0__active 1 +#define R_VECT_READ__timer0__inactive 0 +#define R_VECT_READ__nmi__BITNR 1 +#define R_VECT_READ__nmi__WIDTH 1 +#define R_VECT_READ__nmi__active 1 +#define R_VECT_READ__nmi__inactive 0 +#define R_VECT_READ__some__BITNR 0 +#define R_VECT_READ__some__WIDTH 1 +#define R_VECT_READ__some__active 1 +#define R_VECT_READ__some__inactive 0 + +#define R_VECT_MASK_SET (IO_TYPECAST_UDWORD 0xb00000dc) +#define R_VECT_MASK_SET__usb__BITNR 31 +#define R_VECT_MASK_SET__usb__WIDTH 1 +#define R_VECT_MASK_SET__usb__set 1 +#define R_VECT_MASK_SET__usb__nop 0 +#define R_VECT_MASK_SET__dma9__BITNR 25 +#define R_VECT_MASK_SET__dma9__WIDTH 1 +#define R_VECT_MASK_SET__dma9__set 1 +#define R_VECT_MASK_SET__dma9__nop 0 +#define R_VECT_MASK_SET__dma8__BITNR 24 +#define R_VECT_MASK_SET__dma8__WIDTH 1 +#define R_VECT_MASK_SET__dma8__set 1 +#define R_VECT_MASK_SET__dma8__nop 0 +#define R_VECT_MASK_SET__dma7__BITNR 23 +#define R_VECT_MASK_SET__dma7__WIDTH 1 +#define R_VECT_MASK_SET__dma7__set 1 +#define R_VECT_MASK_SET__dma7__nop 0 +#define R_VECT_MASK_SET__dma6__BITNR 22 +#define R_VECT_MASK_SET__dma6__WIDTH 1 +#define R_VECT_MASK_SET__dma6__set 1 +#define R_VECT_MASK_SET__dma6__nop 0 +#define R_VECT_MASK_SET__dma5__BITNR 21 +#define R_VECT_MASK_SET__dma5__WIDTH 1 +#define R_VECT_MASK_SET__dma5__set 1 +#define R_VECT_MASK_SET__dma5__nop 0 +#define R_VECT_MASK_SET__dma4__BITNR 20 +#define R_VECT_MASK_SET__dma4__WIDTH 1 +#define R_VECT_MASK_SET__dma4__set 1 +#define R_VECT_MASK_SET__dma4__nop 0 +#define R_VECT_MASK_SET__dma3__BITNR 19 +#define R_VECT_MASK_SET__dma3__WIDTH 1 +#define R_VECT_MASK_SET__dma3__set 1 +#define R_VECT_MASK_SET__dma3__nop 0 +#define R_VECT_MASK_SET__dma2__BITNR 18 +#define R_VECT_MASK_SET__dma2__WIDTH 1 +#define R_VECT_MASK_SET__dma2__set 1 +#define R_VECT_MASK_SET__dma2__nop 0 +#define R_VECT_MASK_SET__dma1__BITNR 17 +#define R_VECT_MASK_SET__dma1__WIDTH 1 +#define R_VECT_MASK_SET__dma1__set 1 +#define R_VECT_MASK_SET__dma1__nop 0 +#define R_VECT_MASK_SET__dma0__BITNR 16 +#define R_VECT_MASK_SET__dma0__WIDTH 1 +#define R_VECT_MASK_SET__dma0__set 1 +#define R_VECT_MASK_SET__dma0__nop 0 +#define R_VECT_MASK_SET__ext_dma1__BITNR 13 +#define R_VECT_MASK_SET__ext_dma1__WIDTH 1 +#define R_VECT_MASK_SET__ext_dma1__set 1 +#define R_VECT_MASK_SET__ext_dma1__nop 0 +#define R_VECT_MASK_SET__ext_dma0__BITNR 12 +#define R_VECT_MASK_SET__ext_dma0__WIDTH 1 +#define R_VECT_MASK_SET__ext_dma0__set 1 +#define R_VECT_MASK_SET__ext_dma0__nop 0 +#define R_VECT_MASK_SET__pa__BITNR 11 +#define R_VECT_MASK_SET__pa__WIDTH 1 +#define R_VECT_MASK_SET__pa__set 1 +#define R_VECT_MASK_SET__pa__nop 0 +#define R_VECT_MASK_SET__irq_intnr__BITNR 10 +#define R_VECT_MASK_SET__irq_intnr__WIDTH 1 +#define R_VECT_MASK_SET__irq_intnr__set 1 +#define R_VECT_MASK_SET__irq_intnr__nop 0 +#define R_VECT_MASK_SET__sw__BITNR 9 +#define R_VECT_MASK_SET__sw__WIDTH 1 +#define R_VECT_MASK_SET__sw__set 1 +#define R_VECT_MASK_SET__sw__nop 0 +#define R_VECT_MASK_SET__serial__BITNR 8 +#define R_VECT_MASK_SET__serial__WIDTH 1 +#define R_VECT_MASK_SET__serial__set 1 +#define R_VECT_MASK_SET__serial__nop 0 +#define R_VECT_MASK_SET__snmp__BITNR 7 +#define R_VECT_MASK_SET__snmp__WIDTH 1 +#define R_VECT_MASK_SET__snmp__set 1 +#define R_VECT_MASK_SET__snmp__nop 0 +#define R_VECT_MASK_SET__network__BITNR 6 +#define R_VECT_MASK_SET__network__WIDTH 1 +#define R_VECT_MASK_SET__network__set 1 +#define R_VECT_MASK_SET__network__nop 0 +#define R_VECT_MASK_SET__scsi1__BITNR 5 +#define R_VECT_MASK_SET__scsi1__WIDTH 1 +#define R_VECT_MASK_SET__scsi1__set 1 +#define R_VECT_MASK_SET__scsi1__nop 0 +#define R_VECT_MASK_SET__par1__BITNR 5 +#define R_VECT_MASK_SET__par1__WIDTH 1 +#define R_VECT_MASK_SET__par1__set 1 +#define R_VECT_MASK_SET__par1__nop 0 +#define R_VECT_MASK_SET__scsi0__BITNR 4 +#define R_VECT_MASK_SET__scsi0__WIDTH 1 +#define R_VECT_MASK_SET__scsi0__set 1 +#define R_VECT_MASK_SET__scsi0__nop 0 +#define R_VECT_MASK_SET__par0__BITNR 4 +#define R_VECT_MASK_SET__par0__WIDTH 1 +#define R_VECT_MASK_SET__par0__set 1 +#define R_VECT_MASK_SET__par0__nop 0 +#define R_VECT_MASK_SET__ata__BITNR 4 +#define R_VECT_MASK_SET__ata__WIDTH 1 +#define R_VECT_MASK_SET__ata__set 1 +#define R_VECT_MASK_SET__ata__nop 0 +#define R_VECT_MASK_SET__mio__BITNR 4 +#define R_VECT_MASK_SET__mio__WIDTH 1 +#define R_VECT_MASK_SET__mio__set 1 +#define R_VECT_MASK_SET__mio__nop 0 +#define R_VECT_MASK_SET__timer1__BITNR 3 +#define R_VECT_MASK_SET__timer1__WIDTH 1 +#define R_VECT_MASK_SET__timer1__set 1 +#define R_VECT_MASK_SET__timer1__nop 0 +#define R_VECT_MASK_SET__timer0__BITNR 2 +#define R_VECT_MASK_SET__timer0__WIDTH 1 +#define R_VECT_MASK_SET__timer0__set 1 +#define R_VECT_MASK_SET__timer0__nop 0 +#define R_VECT_MASK_SET__nmi__BITNR 1 +#define R_VECT_MASK_SET__nmi__WIDTH 1 +#define R_VECT_MASK_SET__nmi__set 1 +#define R_VECT_MASK_SET__nmi__nop 0 +#define R_VECT_MASK_SET__some__BITNR 0 +#define R_VECT_MASK_SET__some__WIDTH 1 +#define R_VECT_MASK_SET__some__set 1 +#define R_VECT_MASK_SET__some__nop 0 + +/* +!* DMA registers +!*/ + +#define R_SET_EOP (IO_TYPECAST_UDWORD 0xb000003c) +#define R_SET_EOP__ch9_eop__BITNR 3 +#define R_SET_EOP__ch9_eop__WIDTH 1 +#define R_SET_EOP__ch9_eop__set 1 +#define R_SET_EOP__ch9_eop__nop 0 +#define R_SET_EOP__ch7_eop__BITNR 2 +#define R_SET_EOP__ch7_eop__WIDTH 1 +#define R_SET_EOP__ch7_eop__set 1 +#define R_SET_EOP__ch7_eop__nop 0 +#define R_SET_EOP__ch5_eop__BITNR 1 +#define R_SET_EOP__ch5_eop__WIDTH 1 +#define R_SET_EOP__ch5_eop__set 1 +#define R_SET_EOP__ch5_eop__nop 0 +#define R_SET_EOP__ch3_eop__BITNR 0 +#define R_SET_EOP__ch3_eop__WIDTH 1 +#define R_SET_EOP__ch3_eop__set 1 +#define R_SET_EOP__ch3_eop__nop 0 + +#define R_DMA_CH0_HWSW (IO_TYPECAST_UDWORD 0xb0000100) +#define R_DMA_CH0_HWSW__hw__BITNR 16 +#define R_DMA_CH0_HWSW__hw__WIDTH 16 +#define R_DMA_CH0_HWSW__sw__BITNR 0 +#define R_DMA_CH0_HWSW__sw__WIDTH 16 + +#define R_DMA_CH0_DESCR (IO_TYPECAST_UDWORD 0xb000010c) +#define R_DMA_CH0_DESCR__descr__BITNR 0 +#define R_DMA_CH0_DESCR__descr__WIDTH 32 + +#define R_DMA_CH0_NEXT (IO_TYPECAST_UDWORD 0xb0000104) +#define R_DMA_CH0_NEXT__next__BITNR 0 +#define R_DMA_CH0_NEXT__next__WIDTH 32 + +#define R_DMA_CH0_BUF (IO_TYPECAST_UDWORD 0xb0000108) +#define R_DMA_CH0_BUF__buf__BITNR 0 +#define R_DMA_CH0_BUF__buf__WIDTH 32 + +#define R_DMA_CH0_FIRST (IO_TYPECAST_UDWORD 0xb00001a0) +#define R_DMA_CH0_FIRST__first__BITNR 0 +#define R_DMA_CH0_FIRST__first__WIDTH 32 + +#define R_DMA_CH0_CMD (IO_TYPECAST_BYTE 0xb00001d0) +#define R_DMA_CH0_CMD__cmd__BITNR 0 +#define R_DMA_CH0_CMD__cmd__WIDTH 3 +#define R_DMA_CH0_CMD__cmd__hold 0 +#define R_DMA_CH0_CMD__cmd__start 1 +#define R_DMA_CH0_CMD__cmd__restart 3 +#define R_DMA_CH0_CMD__cmd__continue 3 +#define R_DMA_CH0_CMD__cmd__reset 4 + +#define R_DMA_CH0_CLR_INTR (IO_TYPECAST_BYTE 0xb00001d1) +#define R_DMA_CH0_CLR_INTR__clr_eop__BITNR 1 +#define R_DMA_CH0_CLR_INTR__clr_eop__WIDTH 1 +#define R_DMA_CH0_CLR_INTR__clr_eop__do 1 +#define R_DMA_CH0_CLR_INTR__clr_eop__dont 0 +#define R_DMA_CH0_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH0_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH0_CLR_INTR__clr_descr__do 1 +#define R_DMA_CH0_CLR_INTR__clr_descr__dont 0 + +#define R_DMA_CH0_STATUS (IO_TYPECAST_RO_BYTE 0xb00001d2) +#define R_DMA_CH0_STATUS__avail__BITNR 0 +#define R_DMA_CH0_STATUS__avail__WIDTH 7 + +#define R_DMA_CH1_HWSW (IO_TYPECAST_UDWORD 0xb0000110) +#define R_DMA_CH1_HWSW__hw__BITNR 16 +#define R_DMA_CH1_HWSW__hw__WIDTH 16 +#define R_DMA_CH1_HWSW__sw__BITNR 0 +#define R_DMA_CH1_HWSW__sw__WIDTH 16 + +#define R_DMA_CH1_DESCR (IO_TYPECAST_UDWORD 0xb000011c) +#define R_DMA_CH1_DESCR__descr__BITNR 0 +#define R_DMA_CH1_DESCR__descr__WIDTH 32 + +#define R_DMA_CH1_NEXT (IO_TYPECAST_UDWORD 0xb0000114) +#define R_DMA_CH1_NEXT__next__BITNR 0 +#define R_DMA_CH1_NEXT__next__WIDTH 32 + +#define R_DMA_CH1_BUF (IO_TYPECAST_UDWORD 0xb0000118) +#define R_DMA_CH1_BUF__buf__BITNR 0 +#define R_DMA_CH1_BUF__buf__WIDTH 32 + +#define R_DMA_CH1_FIRST (IO_TYPECAST_UDWORD 0xb00001a4) +#define R_DMA_CH1_FIRST__first__BITNR 0 +#define R_DMA_CH1_FIRST__first__WIDTH 32 + +#define R_DMA_CH1_CMD (IO_TYPECAST_BYTE 0xb00001d4) +#define R_DMA_CH1_CMD__cmd__BITNR 0 +#define R_DMA_CH1_CMD__cmd__WIDTH 3 +#define R_DMA_CH1_CMD__cmd__hold 0 +#define R_DMA_CH1_CMD__cmd__start 1 +#define R_DMA_CH1_CMD__cmd__restart 3 +#define R_DMA_CH1_CMD__cmd__continue 3 +#define R_DMA_CH1_CMD__cmd__reset 4 + +#define R_DMA_CH1_CLR_INTR (IO_TYPECAST_BYTE 0xb00001d5) +#define R_DMA_CH1_CLR_INTR__clr_eop__BITNR 1 +#define R_DMA_CH1_CLR_INTR__clr_eop__WIDTH 1 +#define R_DMA_CH1_CLR_INTR__clr_eop__do 1 +#define R_DMA_CH1_CLR_INTR__clr_eop__dont 0 +#define R_DMA_CH1_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH1_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH1_CLR_INTR__clr_descr__do 1 +#define R_DMA_CH1_CLR_INTR__clr_descr__dont 0 + +#define R_DMA_CH1_STATUS (IO_TYPECAST_RO_BYTE 0xb00001d6) +#define R_DMA_CH1_STATUS__avail__BITNR 0 +#define R_DMA_CH1_STATUS__avail__WIDTH 7 + +#define R_DMA_CH2_HWSW (IO_TYPECAST_UDWORD 0xb0000120) +#define R_DMA_CH2_HWSW__hw__BITNR 16 +#define R_DMA_CH2_HWSW__hw__WIDTH 16 +#define R_DMA_CH2_HWSW__sw__BITNR 0 +#define R_DMA_CH2_HWSW__sw__WIDTH 16 + +#define R_DMA_CH2_DESCR (IO_TYPECAST_UDWORD 0xb000012c) +#define R_DMA_CH2_DESCR__descr__BITNR 0 +#define R_DMA_CH2_DESCR__descr__WIDTH 32 + +#define R_DMA_CH2_NEXT (IO_TYPECAST_UDWORD 0xb0000124) +#define R_DMA_CH2_NEXT__next__BITNR 0 +#define R_DMA_CH2_NEXT__next__WIDTH 32 + +#define R_DMA_CH2_BUF (IO_TYPECAST_UDWORD 0xb0000128) +#define R_DMA_CH2_BUF__buf__BITNR 0 +#define R_DMA_CH2_BUF__buf__WIDTH 32 + +#define R_DMA_CH2_FIRST (IO_TYPECAST_UDWORD 0xb00001a8) +#define R_DMA_CH2_FIRST__first__BITNR 0 +#define R_DMA_CH2_FIRST__first__WIDTH 32 + +#define R_DMA_CH2_CMD (IO_TYPECAST_BYTE 0xb00001d8) +#define R_DMA_CH2_CMD__cmd__BITNR 0 +#define R_DMA_CH2_CMD__cmd__WIDTH 3 +#define R_DMA_CH2_CMD__cmd__hold 0 +#define R_DMA_CH2_CMD__cmd__start 1 +#define R_DMA_CH2_CMD__cmd__restart 3 +#define R_DMA_CH2_CMD__cmd__continue 3 +#define R_DMA_CH2_CMD__cmd__reset 4 + +#define R_DMA_CH2_CLR_INTR (IO_TYPECAST_BYTE 0xb00001d9) +#define R_DMA_CH2_CLR_INTR__clr_eop__BITNR 1 +#define R_DMA_CH2_CLR_INTR__clr_eop__WIDTH 1 +#define R_DMA_CH2_CLR_INTR__clr_eop__do 1 +#define R_DMA_CH2_CLR_INTR__clr_eop__dont 0 +#define R_DMA_CH2_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH2_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH2_CLR_INTR__clr_descr__do 1 +#define R_DMA_CH2_CLR_INTR__clr_descr__dont 0 + +#define R_DMA_CH2_STATUS (IO_TYPECAST_RO_BYTE 0xb00001da) +#define R_DMA_CH2_STATUS__avail__BITNR 0 +#define R_DMA_CH2_STATUS__avail__WIDTH 7 + +#define R_DMA_CH3_HWSW (IO_TYPECAST_UDWORD 0xb0000130) +#define R_DMA_CH3_HWSW__hw__BITNR 16 +#define R_DMA_CH3_HWSW__hw__WIDTH 16 +#define R_DMA_CH3_HWSW__sw__BITNR 0 +#define R_DMA_CH3_HWSW__sw__WIDTH 16 + +#define R_DMA_CH3_DESCR (IO_TYPECAST_UDWORD 0xb000013c) +#define R_DMA_CH3_DESCR__descr__BITNR 0 +#define R_DMA_CH3_DESCR__descr__WIDTH 32 + +#define R_DMA_CH3_NEXT (IO_TYPECAST_UDWORD 0xb0000134) +#define R_DMA_CH3_NEXT__next__BITNR 0 +#define R_DMA_CH3_NEXT__next__WIDTH 32 + +#define R_DMA_CH3_BUF (IO_TYPECAST_UDWORD 0xb0000138) +#define R_DMA_CH3_BUF__buf__BITNR 0 +#define R_DMA_CH3_BUF__buf__WIDTH 32 + +#define R_DMA_CH3_FIRST (IO_TYPECAST_UDWORD 0xb00001ac) +#define R_DMA_CH3_FIRST__first__BITNR 0 +#define R_DMA_CH3_FIRST__first__WIDTH 32 + +#define R_DMA_CH3_CMD (IO_TYPECAST_BYTE 0xb00001dc) +#define R_DMA_CH3_CMD__cmd__BITNR 0 +#define R_DMA_CH3_CMD__cmd__WIDTH 3 +#define R_DMA_CH3_CMD__cmd__hold 0 +#define R_DMA_CH3_CMD__cmd__start 1 +#define R_DMA_CH3_CMD__cmd__restart 3 +#define R_DMA_CH3_CMD__cmd__continue 3 +#define R_DMA_CH3_CMD__cmd__reset 4 + +#define R_DMA_CH3_CLR_INTR (IO_TYPECAST_BYTE 0xb00001dd) +#define R_DMA_CH3_CLR_INTR__clr_eop__BITNR 1 +#define R_DMA_CH3_CLR_INTR__clr_eop__WIDTH 1 +#define R_DMA_CH3_CLR_INTR__clr_eop__do 1 +#define R_DMA_CH3_CLR_INTR__clr_eop__dont 0 +#define R_DMA_CH3_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH3_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH3_CLR_INTR__clr_descr__do 1 +#define R_DMA_CH3_CLR_INTR__clr_descr__dont 0 + +#define R_DMA_CH3_STATUS (IO_TYPECAST_RO_BYTE 0xb00001de) +#define R_DMA_CH3_STATUS__avail__BITNR 0 +#define R_DMA_CH3_STATUS__avail__WIDTH 7 + +#define R_DMA_CH4_HWSW (IO_TYPECAST_UDWORD 0xb0000140) +#define R_DMA_CH4_HWSW__hw__BITNR 16 +#define R_DMA_CH4_HWSW__hw__WIDTH 16 +#define R_DMA_CH4_HWSW__sw__BITNR 0 +#define R_DMA_CH4_HWSW__sw__WIDTH 16 + +#define R_DMA_CH4_DESCR (IO_TYPECAST_UDWORD 0xb000014c) +#define R_DMA_CH4_DESCR__descr__BITNR 0 +#define R_DMA_CH4_DESCR__descr__WIDTH 32 + +#define R_DMA_CH4_NEXT (IO_TYPECAST_UDWORD 0xb0000144) +#define R_DMA_CH4_NEXT__next__BITNR 0 +#define R_DMA_CH4_NEXT__next__WIDTH 32 + +#define R_DMA_CH4_BUF (IO_TYPECAST_UDWORD 0xb0000148) +#define R_DMA_CH4_BUF__buf__BITNR 0 +#define R_DMA_CH4_BUF__buf__WIDTH 32 + +#define R_DMA_CH4_FIRST (IO_TYPECAST_UDWORD 0xb00001b0) +#define R_DMA_CH4_FIRST__first__BITNR 0 +#define R_DMA_CH4_FIRST__first__WIDTH 32 + +#define R_DMA_CH4_CMD (IO_TYPECAST_BYTE 0xb00001e0) +#define R_DMA_CH4_CMD__cmd__BITNR 0 +#define R_DMA_CH4_CMD__cmd__WIDTH 3 +#define R_DMA_CH4_CMD__cmd__hold 0 +#define R_DMA_CH4_CMD__cmd__start 1 +#define R_DMA_CH4_CMD__cmd__restart 3 +#define R_DMA_CH4_CMD__cmd__continue 3 +#define R_DMA_CH4_CMD__cmd__reset 4 + +#define R_DMA_CH4_CLR_INTR (IO_TYPECAST_BYTE 0xb00001e1) +#define R_DMA_CH4_CLR_INTR__clr_eop__BITNR 1 +#define R_DMA_CH4_CLR_INTR__clr_eop__WIDTH 1 +#define R_DMA_CH4_CLR_INTR__clr_eop__do 1 +#define R_DMA_CH4_CLR_INTR__clr_eop__dont 0 +#define R_DMA_CH4_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH4_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH4_CLR_INTR__clr_descr__do 1 +#define R_DMA_CH4_CLR_INTR__clr_descr__dont 0 + +#define R_DMA_CH4_STATUS (IO_TYPECAST_RO_BYTE 0xb00001e2) +#define R_DMA_CH4_STATUS__avail__BITNR 0 +#define R_DMA_CH4_STATUS__avail__WIDTH 7 + +#define R_DMA_CH5_HWSW (IO_TYPECAST_UDWORD 0xb0000150) +#define R_DMA_CH5_HWSW__hw__BITNR 16 +#define R_DMA_CH5_HWSW__hw__WIDTH 16 +#define R_DMA_CH5_HWSW__sw__BITNR 0 +#define R_DMA_CH5_HWSW__sw__WIDTH 16 + +#define R_DMA_CH5_DESCR (IO_TYPECAST_UDWORD 0xb000015c) +#define R_DMA_CH5_DESCR__descr__BITNR 0 +#define R_DMA_CH5_DESCR__descr__WIDTH 32 + +#define R_DMA_CH5_NEXT (IO_TYPECAST_UDWORD 0xb0000154) +#define R_DMA_CH5_NEXT__next__BITNR 0 +#define R_DMA_CH5_NEXT__next__WIDTH 32 + +#define R_DMA_CH5_BUF (IO_TYPECAST_UDWORD 0xb0000158) +#define R_DMA_CH5_BUF__buf__BITNR 0 +#define R_DMA_CH5_BUF__buf__WIDTH 32 + +#define R_DMA_CH5_FIRST (IO_TYPECAST_UDWORD 0xb00001b4) +#define R_DMA_CH5_FIRST__first__BITNR 0 +#define R_DMA_CH5_FIRST__first__WIDTH 32 + +#define R_DMA_CH5_CMD (IO_TYPECAST_BYTE 0xb00001e4) +#define R_DMA_CH5_CMD__cmd__BITNR 0 +#define R_DMA_CH5_CMD__cmd__WIDTH 3 +#define R_DMA_CH5_CMD__cmd__hold 0 +#define R_DMA_CH5_CMD__cmd__start 1 +#define R_DMA_CH5_CMD__cmd__restart 3 +#define R_DMA_CH5_CMD__cmd__continue 3 +#define R_DMA_CH5_CMD__cmd__reset 4 + +#define R_DMA_CH5_CLR_INTR (IO_TYPECAST_BYTE 0xb00001e5) +#define R_DMA_CH5_CLR_INTR__clr_eop__BITNR 1 +#define R_DMA_CH5_CLR_INTR__clr_eop__WIDTH 1 +#define R_DMA_CH5_CLR_INTR__clr_eop__do 1 +#define R_DMA_CH5_CLR_INTR__clr_eop__dont 0 +#define R_DMA_CH5_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH5_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH5_CLR_INTR__clr_descr__do 1 +#define R_DMA_CH5_CLR_INTR__clr_descr__dont 0 + +#define R_DMA_CH5_STATUS (IO_TYPECAST_RO_BYTE 0xb00001e6) +#define R_DMA_CH5_STATUS__avail__BITNR 0 +#define R_DMA_CH5_STATUS__avail__WIDTH 7 + +#define R_DMA_CH6_HWSW (IO_TYPECAST_UDWORD 0xb0000160) +#define R_DMA_CH6_HWSW__hw__BITNR 16 +#define R_DMA_CH6_HWSW__hw__WIDTH 16 +#define R_DMA_CH6_HWSW__sw__BITNR 0 +#define R_DMA_CH6_HWSW__sw__WIDTH 16 + +#define R_DMA_CH6_DESCR (IO_TYPECAST_UDWORD 0xb000016c) +#define R_DMA_CH6_DESCR__descr__BITNR 0 +#define R_DMA_CH6_DESCR__descr__WIDTH 32 + +#define R_DMA_CH6_NEXT (IO_TYPECAST_UDWORD 0xb0000164) +#define R_DMA_CH6_NEXT__next__BITNR 0 +#define R_DMA_CH6_NEXT__next__WIDTH 32 + +#define R_DMA_CH6_BUF (IO_TYPECAST_UDWORD 0xb0000168) +#define R_DMA_CH6_BUF__buf__BITNR 0 +#define R_DMA_CH6_BUF__buf__WIDTH 32 + +#define R_DMA_CH6_FIRST (IO_TYPECAST_UDWORD 0xb00001b8) +#define R_DMA_CH6_FIRST__first__BITNR 0 +#define R_DMA_CH6_FIRST__first__WIDTH 32 + +#define R_DMA_CH6_CMD (IO_TYPECAST_BYTE 0xb00001e8) +#define R_DMA_CH6_CMD__cmd__BITNR 0 +#define R_DMA_CH6_CMD__cmd__WIDTH 3 +#define R_DMA_CH6_CMD__cmd__hold 0 +#define R_DMA_CH6_CMD__cmd__start 1 +#define R_DMA_CH6_CMD__cmd__restart 3 +#define R_DMA_CH6_CMD__cmd__continue 3 +#define R_DMA_CH6_CMD__cmd__reset 4 + +#define R_DMA_CH6_CLR_INTR (IO_TYPECAST_BYTE 0xb00001e9) +#define R_DMA_CH6_CLR_INTR__clr_eop__BITNR 1 +#define R_DMA_CH6_CLR_INTR__clr_eop__WIDTH 1 +#define R_DMA_CH6_CLR_INTR__clr_eop__do 1 +#define R_DMA_CH6_CLR_INTR__clr_eop__dont 0 +#define R_DMA_CH6_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH6_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH6_CLR_INTR__clr_descr__do 1 +#define R_DMA_CH6_CLR_INTR__clr_descr__dont 0 + +#define R_DMA_CH6_STATUS (IO_TYPECAST_RO_BYTE 0xb00001ea) +#define R_DMA_CH6_STATUS__avail__BITNR 0 +#define R_DMA_CH6_STATUS__avail__WIDTH 7 + +#define R_DMA_CH7_HWSW (IO_TYPECAST_UDWORD 0xb0000170) +#define R_DMA_CH7_HWSW__hw__BITNR 16 +#define R_DMA_CH7_HWSW__hw__WIDTH 16 +#define R_DMA_CH7_HWSW__sw__BITNR 0 +#define R_DMA_CH7_HWSW__sw__WIDTH 16 + +#define R_DMA_CH7_DESCR (IO_TYPECAST_UDWORD 0xb000017c) +#define R_DMA_CH7_DESCR__descr__BITNR 0 +#define R_DMA_CH7_DESCR__descr__WIDTH 32 + +#define R_DMA_CH7_NEXT (IO_TYPECAST_UDWORD 0xb0000174) +#define R_DMA_CH7_NEXT__next__BITNR 0 +#define R_DMA_CH7_NEXT__next__WIDTH 32 + +#define R_DMA_CH7_BUF (IO_TYPECAST_UDWORD 0xb0000178) +#define R_DMA_CH7_BUF__buf__BITNR 0 +#define R_DMA_CH7_BUF__buf__WIDTH 32 + +#define R_DMA_CH7_FIRST (IO_TYPECAST_UDWORD 0xb00001bc) +#define R_DMA_CH7_FIRST__first__BITNR 0 +#define R_DMA_CH7_FIRST__first__WIDTH 32 + +#define R_DMA_CH7_CMD (IO_TYPECAST_BYTE 0xb00001ec) +#define R_DMA_CH7_CMD__cmd__BITNR 0 +#define R_DMA_CH7_CMD__cmd__WIDTH 3 +#define R_DMA_CH7_CMD__cmd__hold 0 +#define R_DMA_CH7_CMD__cmd__start 1 +#define R_DMA_CH7_CMD__cmd__restart 3 +#define R_DMA_CH7_CMD__cmd__continue 3 +#define R_DMA_CH7_CMD__cmd__reset 4 + +#define R_DMA_CH7_CLR_INTR (IO_TYPECAST_BYTE 0xb00001ed) +#define R_DMA_CH7_CLR_INTR__clr_eop__BITNR 1 +#define R_DMA_CH7_CLR_INTR__clr_eop__WIDTH 1 +#define R_DMA_CH7_CLR_INTR__clr_eop__do 1 +#define R_DMA_CH7_CLR_INTR__clr_eop__dont 0 +#define R_DMA_CH7_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH7_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH7_CLR_INTR__clr_descr__do 1 +#define R_DMA_CH7_CLR_INTR__clr_descr__dont 0 + +#define R_DMA_CH7_STATUS (IO_TYPECAST_RO_BYTE 0xb00001ee) +#define R_DMA_CH7_STATUS__avail__BITNR 0 +#define R_DMA_CH7_STATUS__avail__WIDTH 7 + +#define R_DMA_CH8_HWSW (IO_TYPECAST_UDWORD 0xb0000180) +#define R_DMA_CH8_HWSW__hw__BITNR 16 +#define R_DMA_CH8_HWSW__hw__WIDTH 16 +#define R_DMA_CH8_HWSW__sw__BITNR 0 +#define R_DMA_CH8_HWSW__sw__WIDTH 16 + +#define R_DMA_CH8_DESCR (IO_TYPECAST_UDWORD 0xb000018c) +#define R_DMA_CH8_DESCR__descr__BITNR 0 +#define R_DMA_CH8_DESCR__descr__WIDTH 32 + +#define R_DMA_CH8_NEXT (IO_TYPECAST_UDWORD 0xb0000184) +#define R_DMA_CH8_NEXT__next__BITNR 0 +#define R_DMA_CH8_NEXT__next__WIDTH 32 + +#define R_DMA_CH8_BUF (IO_TYPECAST_UDWORD 0xb0000188) +#define R_DMA_CH8_BUF__buf__BITNR 0 +#define R_DMA_CH8_BUF__buf__WIDTH 32 + +#define R_DMA_CH8_FIRST (IO_TYPECAST_UDWORD 0xb00001c0) +#define R_DMA_CH8_FIRST__first__BITNR 0 +#define R_DMA_CH8_FIRST__first__WIDTH 32 + +#define R_DMA_CH8_CMD (IO_TYPECAST_BYTE 0xb00001f0) +#define R_DMA_CH8_CMD__cmd__BITNR 0 +#define R_DMA_CH8_CMD__cmd__WIDTH 3 +#define R_DMA_CH8_CMD__cmd__hold 0 +#define R_DMA_CH8_CMD__cmd__start 1 +#define R_DMA_CH8_CMD__cmd__restart 3 +#define R_DMA_CH8_CMD__cmd__continue 3 +#define R_DMA_CH8_CMD__cmd__reset 4 + +#define R_DMA_CH8_CLR_INTR (IO_TYPECAST_BYTE 0xb00001f1) +#define R_DMA_CH8_CLR_INTR__clr_eop__BITNR 1 +#define R_DMA_CH8_CLR_INTR__clr_eop__WIDTH 1 +#define R_DMA_CH8_CLR_INTR__clr_eop__do 1 +#define R_DMA_CH8_CLR_INTR__clr_eop__dont 0 +#define R_DMA_CH8_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH8_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH8_CLR_INTR__clr_descr__do 1 +#define R_DMA_CH8_CLR_INTR__clr_descr__dont 0 + +#define R_DMA_CH8_STATUS (IO_TYPECAST_RO_BYTE 0xb00001f2) +#define R_DMA_CH8_STATUS__avail__BITNR 0 +#define R_DMA_CH8_STATUS__avail__WIDTH 7 + +#define R_DMA_CH8_SUB (IO_TYPECAST_UDWORD 0xb000018c) +#define R_DMA_CH8_SUB__sub__BITNR 0 +#define R_DMA_CH8_SUB__sub__WIDTH 32 + +#define R_DMA_CH8_NEP (IO_TYPECAST_UDWORD 0xb00001c0) +#define R_DMA_CH8_NEP__nep__BITNR 0 +#define R_DMA_CH8_NEP__nep__WIDTH 32 + +#define R_DMA_CH8_SUB0_EP (IO_TYPECAST_UDWORD 0xb00001c8) +#define R_DMA_CH8_SUB0_EP__ep__BITNR 0 +#define R_DMA_CH8_SUB0_EP__ep__WIDTH 32 + +#define R_DMA_CH8_SUB0_CMD (IO_TYPECAST_BYTE 0xb00001d3) +#define R_DMA_CH8_SUB0_CMD__cmd__BITNR 0 +#define R_DMA_CH8_SUB0_CMD__cmd__WIDTH 1 +#define R_DMA_CH8_SUB0_CMD__cmd__stop 0 +#define R_DMA_CH8_SUB0_CMD__cmd__start 1 + +#define R_DMA_CH8_SUB0_CLR_INTR (IO_TYPECAST_BYTE 0xb00001e3) +#define R_DMA_CH8_SUB0_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH8_SUB0_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH8_SUB0_CLR_INTR__clr_descr__dont 0 +#define R_DMA_CH8_SUB0_CLR_INTR__clr_descr__do 1 + +#define R_DMA_CH8_SUB1_EP (IO_TYPECAST_UDWORD 0xb00001cc) +#define R_DMA_CH8_SUB1_EP__ep__BITNR 0 +#define R_DMA_CH8_SUB1_EP__ep__WIDTH 32 + +#define R_DMA_CH8_SUB1_CMD (IO_TYPECAST_BYTE 0xb00001d7) +#define R_DMA_CH8_SUB1_CMD__cmd__BITNR 0 +#define R_DMA_CH8_SUB1_CMD__cmd__WIDTH 1 +#define R_DMA_CH8_SUB1_CMD__cmd__stop 0 +#define R_DMA_CH8_SUB1_CMD__cmd__start 1 + +#define R_DMA_CH8_SUB1_CLR_INTR (IO_TYPECAST_BYTE 0xb00001e7) +#define R_DMA_CH8_SUB1_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH8_SUB1_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH8_SUB1_CLR_INTR__clr_descr__dont 0 +#define R_DMA_CH8_SUB1_CLR_INTR__clr_descr__do 1 + +#define R_DMA_CH8_SUB2_EP (IO_TYPECAST_UDWORD 0xb00001f8) +#define R_DMA_CH8_SUB2_EP__ep__BITNR 0 +#define R_DMA_CH8_SUB2_EP__ep__WIDTH 32 + +#define R_DMA_CH8_SUB2_CMD (IO_TYPECAST_BYTE 0xb00001db) +#define R_DMA_CH8_SUB2_CMD__cmd__BITNR 0 +#define R_DMA_CH8_SUB2_CMD__cmd__WIDTH 1 +#define R_DMA_CH8_SUB2_CMD__cmd__stop 0 +#define R_DMA_CH8_SUB2_CMD__cmd__start 1 + +#define R_DMA_CH8_SUB2_CLR_INTR (IO_TYPECAST_BYTE 0xb00001eb) +#define R_DMA_CH8_SUB2_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH8_SUB2_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH8_SUB2_CLR_INTR__clr_descr__dont 0 +#define R_DMA_CH8_SUB2_CLR_INTR__clr_descr__do 1 + +#define R_DMA_CH8_SUB3_EP (IO_TYPECAST_UDWORD 0xb00001fc) +#define R_DMA_CH8_SUB3_EP__ep__BITNR 0 +#define R_DMA_CH8_SUB3_EP__ep__WIDTH 32 + +#define R_DMA_CH8_SUB3_CMD (IO_TYPECAST_BYTE 0xb00001df) +#define R_DMA_CH8_SUB3_CMD__cmd__BITNR 0 +#define R_DMA_CH8_SUB3_CMD__cmd__WIDTH 1 +#define R_DMA_CH8_SUB3_CMD__cmd__stop 0 +#define R_DMA_CH8_SUB3_CMD__cmd__start 1 + +#define R_DMA_CH8_SUB3_CLR_INTR (IO_TYPECAST_BYTE 0xb00001ef) +#define R_DMA_CH8_SUB3_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH8_SUB3_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH8_SUB3_CLR_INTR__clr_descr__dont 0 +#define R_DMA_CH8_SUB3_CLR_INTR__clr_descr__do 1 + +#define R_DMA_CH9_HWSW (IO_TYPECAST_UDWORD 0xb0000190) +#define R_DMA_CH9_HWSW__hw__BITNR 16 +#define R_DMA_CH9_HWSW__hw__WIDTH 16 +#define R_DMA_CH9_HWSW__sw__BITNR 0 +#define R_DMA_CH9_HWSW__sw__WIDTH 16 + +#define R_DMA_CH9_DESCR (IO_TYPECAST_UDWORD 0xb000019c) +#define R_DMA_CH9_DESCR__descr__BITNR 0 +#define R_DMA_CH9_DESCR__descr__WIDTH 32 + +#define R_DMA_CH9_NEXT (IO_TYPECAST_UDWORD 0xb0000194) +#define R_DMA_CH9_NEXT__next__BITNR 0 +#define R_DMA_CH9_NEXT__next__WIDTH 32 + +#define R_DMA_CH9_BUF (IO_TYPECAST_UDWORD 0xb0000198) +#define R_DMA_CH9_BUF__buf__BITNR 0 +#define R_DMA_CH9_BUF__buf__WIDTH 32 + +#define R_DMA_CH9_FIRST (IO_TYPECAST_UDWORD 0xb00001c4) +#define R_DMA_CH9_FIRST__first__BITNR 0 +#define R_DMA_CH9_FIRST__first__WIDTH 32 + +#define R_DMA_CH9_CMD (IO_TYPECAST_BYTE 0xb00001f4) +#define R_DMA_CH9_CMD__cmd__BITNR 0 +#define R_DMA_CH9_CMD__cmd__WIDTH 3 +#define R_DMA_CH9_CMD__cmd__hold 0 +#define R_DMA_CH9_CMD__cmd__start 1 +#define R_DMA_CH9_CMD__cmd__restart 3 +#define R_DMA_CH9_CMD__cmd__continue 3 +#define R_DMA_CH9_CMD__cmd__reset 4 + +#define R_DMA_CH9_CLR_INTR (IO_TYPECAST_BYTE 0xb00001f5) +#define R_DMA_CH9_CLR_INTR__clr_eop__BITNR 1 +#define R_DMA_CH9_CLR_INTR__clr_eop__WIDTH 1 +#define R_DMA_CH9_CLR_INTR__clr_eop__do 1 +#define R_DMA_CH9_CLR_INTR__clr_eop__dont 0 +#define R_DMA_CH9_CLR_INTR__clr_descr__BITNR 0 +#define R_DMA_CH9_CLR_INTR__clr_descr__WIDTH 1 +#define R_DMA_CH9_CLR_INTR__clr_descr__do 1 +#define R_DMA_CH9_CLR_INTR__clr_descr__dont 0 + +#define R_DMA_CH9_STATUS (IO_TYPECAST_RO_BYTE 0xb00001f6) +#define R_DMA_CH9_STATUS__avail__BITNR 0 +#define R_DMA_CH9_STATUS__avail__WIDTH 7 + +/* +!* Test mode registers +!*/ + +#define R_TEST_MODE (IO_TYPECAST_UDWORD 0xb00000fc) +#define R_TEST_MODE__single_step__BITNR 19 +#define R_TEST_MODE__single_step__WIDTH 1 +#define R_TEST_MODE__single_step__on 1 +#define R_TEST_MODE__single_step__off 0 +#define R_TEST_MODE__step_wr__BITNR 18 +#define R_TEST_MODE__step_wr__WIDTH 1 +#define R_TEST_MODE__step_wr__on 1 +#define R_TEST_MODE__step_wr__off 0 +#define R_TEST_MODE__step_rd__BITNR 17 +#define R_TEST_MODE__step_rd__WIDTH 1 +#define R_TEST_MODE__step_rd__on 1 +#define R_TEST_MODE__step_rd__off 0 +#define R_TEST_MODE__step_fetch__BITNR 16 +#define R_TEST_MODE__step_fetch__WIDTH 1 +#define R_TEST_MODE__step_fetch__on 1 +#define R_TEST_MODE__step_fetch__off 0 +#define R_TEST_MODE__mmu_test__BITNR 12 +#define R_TEST_MODE__mmu_test__WIDTH 1 +#define R_TEST_MODE__mmu_test__on 1 +#define R_TEST_MODE__mmu_test__off 0 +#define R_TEST_MODE__usb_test__BITNR 11 +#define R_TEST_MODE__usb_test__WIDTH 1 +#define R_TEST_MODE__usb_test__on 1 +#define R_TEST_MODE__usb_test__off 0 +#define R_TEST_MODE__scsi_timer_test__BITNR 10 +#define R_TEST_MODE__scsi_timer_test__WIDTH 1 +#define R_TEST_MODE__scsi_timer_test__on 1 +#define R_TEST_MODE__scsi_timer_test__off 0 +#define R_TEST_MODE__backoff__BITNR 9 +#define R_TEST_MODE__backoff__WIDTH 1 +#define R_TEST_MODE__backoff__on 1 +#define R_TEST_MODE__backoff__off 0 +#define R_TEST_MODE__snmp_test__BITNR 8 +#define R_TEST_MODE__snmp_test__WIDTH 1 +#define R_TEST_MODE__snmp_test__on 1 +#define R_TEST_MODE__snmp_test__off 0 +#define R_TEST_MODE__snmp_inc__BITNR 7 +#define R_TEST_MODE__snmp_inc__WIDTH 1 +#define R_TEST_MODE__snmp_inc__do 1 +#define R_TEST_MODE__snmp_inc__dont 0 +#define R_TEST_MODE__ser_loop__BITNR 6 +#define R_TEST_MODE__ser_loop__WIDTH 1 +#define R_TEST_MODE__ser_loop__on 1 +#define R_TEST_MODE__ser_loop__off 0 +#define R_TEST_MODE__baudrate__BITNR 5 +#define R_TEST_MODE__baudrate__WIDTH 1 +#define R_TEST_MODE__baudrate__on 1 +#define R_TEST_MODE__baudrate__off 0 +#define R_TEST_MODE__timer__BITNR 3 +#define R_TEST_MODE__timer__WIDTH 2 +#define R_TEST_MODE__timer__off 0 +#define R_TEST_MODE__timer__even 1 +#define R_TEST_MODE__timer__odd 2 +#define R_TEST_MODE__timer__all 3 +#define R_TEST_MODE__cache_test__BITNR 2 +#define R_TEST_MODE__cache_test__WIDTH 1 +#define R_TEST_MODE__cache_test__normal 0 +#define R_TEST_MODE__cache_test__test 1 +#define R_TEST_MODE__tag_test__BITNR 1 +#define R_TEST_MODE__tag_test__WIDTH 1 +#define R_TEST_MODE__tag_test__normal 0 +#define R_TEST_MODE__tag_test__test 1 +#define R_TEST_MODE__cache_enable__BITNR 0 +#define R_TEST_MODE__cache_enable__WIDTH 1 +#define R_TEST_MODE__cache_enable__enable 1 +#define R_TEST_MODE__cache_enable__disable 0 + +#define R_SINGLE_STEP (IO_TYPECAST_BYTE 0xb00000fe) +#define R_SINGLE_STEP__single_step__BITNR 3 +#define R_SINGLE_STEP__single_step__WIDTH 1 +#define R_SINGLE_STEP__single_step__on 1 +#define R_SINGLE_STEP__single_step__off 0 +#define R_SINGLE_STEP__step_wr__BITNR 2 +#define R_SINGLE_STEP__step_wr__WIDTH 1 +#define R_SINGLE_STEP__step_wr__on 1 +#define R_SINGLE_STEP__step_wr__off 0 +#define R_SINGLE_STEP__step_rd__BITNR 1 +#define R_SINGLE_STEP__step_rd__WIDTH 1 +#define R_SINGLE_STEP__step_rd__on 1 +#define R_SINGLE_STEP__step_rd__off 0 +#define R_SINGLE_STEP__step_fetch__BITNR 0 +#define R_SINGLE_STEP__step_fetch__WIDTH 1 +#define R_SINGLE_STEP__step_fetch__on 1 +#define R_SINGLE_STEP__step_fetch__off 0 + +/* +!* USB interface control registers +!*/ + +#define R_USB_REVISION (IO_TYPECAST_RO_BYTE 0xb0000200) +#define R_USB_REVISION__major__BITNR 4 +#define R_USB_REVISION__major__WIDTH 4 +#define R_USB_REVISION__minor__BITNR 0 +#define R_USB_REVISION__minor__WIDTH 4 + +#define R_USB_COMMAND (IO_TYPECAST_BYTE 0xb0000201) +#define R_USB_COMMAND__port_sel__BITNR 6 +#define R_USB_COMMAND__port_sel__WIDTH 2 +#define R_USB_COMMAND__port_sel__nop 0 +#define R_USB_COMMAND__port_sel__port1 1 +#define R_USB_COMMAND__port_sel__port2 2 +#define R_USB_COMMAND__port_sel__both 3 +#define R_USB_COMMAND__port_cmd__BITNR 4 +#define R_USB_COMMAND__port_cmd__WIDTH 2 +#define R_USB_COMMAND__port_cmd__reset 0 +#define R_USB_COMMAND__port_cmd__disable 1 +#define R_USB_COMMAND__port_cmd__suspend 2 +#define R_USB_COMMAND__port_cmd__resume 3 +#define R_USB_COMMAND__busy__BITNR 3 +#define R_USB_COMMAND__busy__WIDTH 1 +#define R_USB_COMMAND__busy__no 0 +#define R_USB_COMMAND__busy__yes 1 +#define R_USB_COMMAND__ctrl_cmd__BITNR 0 +#define R_USB_COMMAND__ctrl_cmd__WIDTH 3 +#define R_USB_COMMAND__ctrl_cmd__nop 0 +#define R_USB_COMMAND__ctrl_cmd__reset 1 +#define R_USB_COMMAND__ctrl_cmd__deconfig 2 +#define R_USB_COMMAND__ctrl_cmd__host_config 3 +#define R_USB_COMMAND__ctrl_cmd__dev_config 4 +#define R_USB_COMMAND__ctrl_cmd__host_nop 5 +#define R_USB_COMMAND__ctrl_cmd__host_run 6 +#define R_USB_COMMAND__ctrl_cmd__host_stop 7 + +#define R_USB_COMMAND_DEV (IO_TYPECAST_BYTE 0xb0000201) +#define R_USB_COMMAND_DEV__port_sel__BITNR 6 +#define R_USB_COMMAND_DEV__port_sel__WIDTH 2 +#define R_USB_COMMAND_DEV__port_sel__nop 0 +#define R_USB_COMMAND_DEV__port_sel__dummy1 1 +#define R_USB_COMMAND_DEV__port_sel__dummy2 2 +#define R_USB_COMMAND_DEV__port_sel__any 3 +#define R_USB_COMMAND_DEV__port_cmd__BITNR 4 +#define R_USB_COMMAND_DEV__port_cmd__WIDTH 2 +#define R_USB_COMMAND_DEV__port_cmd__active 0 +#define R_USB_COMMAND_DEV__port_cmd__passive 1 +#define R_USB_COMMAND_DEV__port_cmd__nop 2 +#define R_USB_COMMAND_DEV__port_cmd__wakeup 3 +#define R_USB_COMMAND_DEV__busy__BITNR 3 +#define R_USB_COMMAND_DEV__busy__WIDTH 1 +#define R_USB_COMMAND_DEV__busy__no 0 +#define R_USB_COMMAND_DEV__busy__yes 1 +#define R_USB_COMMAND_DEV__ctrl_cmd__BITNR 0 +#define R_USB_COMMAND_DEV__ctrl_cmd__WIDTH 3 +#define R_USB_COMMAND_DEV__ctrl_cmd__nop 0 +#define R_USB_COMMAND_DEV__ctrl_cmd__reset 1 +#define R_USB_COMMAND_DEV__ctrl_cmd__deconfig 2 +#define R_USB_COMMAND_DEV__ctrl_cmd__host_config 3 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_config 4 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_active 5 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_passive 6 +#define R_USB_COMMAND_DEV__ctrl_cmd__dev_nop 7 + +#define R_USB_STATUS (IO_TYPECAST_RO_BYTE 0xb0000202) +#define R_USB_STATUS__ourun__BITNR 5 +#define R_USB_STATUS__ourun__WIDTH 1 +#define R_USB_STATUS__ourun__no 0 +#define R_USB_STATUS__ourun__yes 1 +#define R_USB_STATUS__perror__BITNR 4 +#define R_USB_STATUS__perror__WIDTH 1 +#define R_USB_STATUS__perror__no 0 +#define R_USB_STATUS__perror__yes 1 +#define R_USB_STATUS__device_mode__BITNR 3 +#define R_USB_STATUS__device_mode__WIDTH 1 +#define R_USB_STATUS__device_mode__no 0 +#define R_USB_STATUS__device_mode__yes 1 +#define R_USB_STATUS__host_mode__BITNR 2 +#define R_USB_STATUS__host_mode__WIDTH 1 +#define R_USB_STATUS__host_mode__no 0 +#define R_USB_STATUS__host_mode__yes 1 +#define R_USB_STATUS__started__BITNR 1 +#define R_USB_STATUS__started__WIDTH 1 +#define R_USB_STATUS__started__no 0 +#define R_USB_STATUS__started__yes 1 +#define R_USB_STATUS__running__BITNR 0 +#define R_USB_STATUS__running__WIDTH 1 +#define R_USB_STATUS__running__no 0 +#define R_USB_STATUS__running__yes 1 + +#define R_USB_IRQ_MASK_SET (IO_TYPECAST_UWORD 0xb0000204) +#define R_USB_IRQ_MASK_SET__iso_eof__BITNR 13 +#define R_USB_IRQ_MASK_SET__iso_eof__WIDTH 1 +#define R_USB_IRQ_MASK_SET__iso_eof__nop 0 +#define R_USB_IRQ_MASK_SET__iso_eof__set 1 +#define R_USB_IRQ_MASK_SET__intr_eof__BITNR 12 +#define R_USB_IRQ_MASK_SET__intr_eof__WIDTH 1 +#define R_USB_IRQ_MASK_SET__intr_eof__nop 0 +#define R_USB_IRQ_MASK_SET__intr_eof__set 1 +#define R_USB_IRQ_MASK_SET__iso_eot__BITNR 11 +#define R_USB_IRQ_MASK_SET__iso_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET__iso_eot__nop 0 +#define R_USB_IRQ_MASK_SET__iso_eot__set 1 +#define R_USB_IRQ_MASK_SET__intr_eot__BITNR 10 +#define R_USB_IRQ_MASK_SET__intr_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET__intr_eot__nop 0 +#define R_USB_IRQ_MASK_SET__intr_eot__set 1 +#define R_USB_IRQ_MASK_SET__ctl_eot__BITNR 9 +#define R_USB_IRQ_MASK_SET__ctl_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET__ctl_eot__nop 0 +#define R_USB_IRQ_MASK_SET__ctl_eot__set 1 +#define R_USB_IRQ_MASK_SET__bulk_eot__BITNR 8 +#define R_USB_IRQ_MASK_SET__bulk_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET__bulk_eot__nop 0 +#define R_USB_IRQ_MASK_SET__bulk_eot__set 1 +#define R_USB_IRQ_MASK_SET__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_SET__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_SET__epid_attn__nop 0 +#define R_USB_IRQ_MASK_SET__epid_attn__set 1 +#define R_USB_IRQ_MASK_SET__sof__BITNR 2 +#define R_USB_IRQ_MASK_SET__sof__WIDTH 1 +#define R_USB_IRQ_MASK_SET__sof__nop 0 +#define R_USB_IRQ_MASK_SET__sof__set 1 +#define R_USB_IRQ_MASK_SET__port_status__BITNR 1 +#define R_USB_IRQ_MASK_SET__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_SET__port_status__nop 0 +#define R_USB_IRQ_MASK_SET__port_status__set 1 +#define R_USB_IRQ_MASK_SET__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_SET__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_SET__ctl_status__nop 0 +#define R_USB_IRQ_MASK_SET__ctl_status__set 1 + +#define R_USB_IRQ_MASK_READ (IO_TYPECAST_RO_UWORD 0xb0000204) +#define R_USB_IRQ_MASK_READ__iso_eof__BITNR 13 +#define R_USB_IRQ_MASK_READ__iso_eof__WIDTH 1 +#define R_USB_IRQ_MASK_READ__iso_eof__no_pend 0 +#define R_USB_IRQ_MASK_READ__iso_eof__pend 1 +#define R_USB_IRQ_MASK_READ__intr_eof__BITNR 12 +#define R_USB_IRQ_MASK_READ__intr_eof__WIDTH 1 +#define R_USB_IRQ_MASK_READ__intr_eof__no_pend 0 +#define R_USB_IRQ_MASK_READ__intr_eof__pend 1 +#define R_USB_IRQ_MASK_READ__iso_eot__BITNR 11 +#define R_USB_IRQ_MASK_READ__iso_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ__iso_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ__iso_eot__pend 1 +#define R_USB_IRQ_MASK_READ__intr_eot__BITNR 10 +#define R_USB_IRQ_MASK_READ__intr_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ__intr_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ__intr_eot__pend 1 +#define R_USB_IRQ_MASK_READ__ctl_eot__BITNR 9 +#define R_USB_IRQ_MASK_READ__ctl_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ__ctl_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ__ctl_eot__pend 1 +#define R_USB_IRQ_MASK_READ__bulk_eot__BITNR 8 +#define R_USB_IRQ_MASK_READ__bulk_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ__bulk_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ__bulk_eot__pend 1 +#define R_USB_IRQ_MASK_READ__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_READ__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_READ__epid_attn__no_pend 0 +#define R_USB_IRQ_MASK_READ__epid_attn__pend 1 +#define R_USB_IRQ_MASK_READ__sof__BITNR 2 +#define R_USB_IRQ_MASK_READ__sof__WIDTH 1 +#define R_USB_IRQ_MASK_READ__sof__no_pend 0 +#define R_USB_IRQ_MASK_READ__sof__pend 1 +#define R_USB_IRQ_MASK_READ__port_status__BITNR 1 +#define R_USB_IRQ_MASK_READ__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_READ__port_status__no_pend 0 +#define R_USB_IRQ_MASK_READ__port_status__pend 1 +#define R_USB_IRQ_MASK_READ__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_READ__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_READ__ctl_status__no_pend 0 +#define R_USB_IRQ_MASK_READ__ctl_status__pend 1 + +#define R_USB_IRQ_MASK_CLR (IO_TYPECAST_UWORD 0xb0000206) +#define R_USB_IRQ_MASK_CLR__iso_eof__BITNR 13 +#define R_USB_IRQ_MASK_CLR__iso_eof__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__iso_eof__nop 0 +#define R_USB_IRQ_MASK_CLR__iso_eof__clr 1 +#define R_USB_IRQ_MASK_CLR__intr_eof__BITNR 12 +#define R_USB_IRQ_MASK_CLR__intr_eof__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__intr_eof__nop 0 +#define R_USB_IRQ_MASK_CLR__intr_eof__clr 1 +#define R_USB_IRQ_MASK_CLR__iso_eot__BITNR 11 +#define R_USB_IRQ_MASK_CLR__iso_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__iso_eot__nop 0 +#define R_USB_IRQ_MASK_CLR__iso_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__intr_eot__BITNR 10 +#define R_USB_IRQ_MASK_CLR__intr_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__intr_eot__nop 0 +#define R_USB_IRQ_MASK_CLR__intr_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__ctl_eot__BITNR 9 +#define R_USB_IRQ_MASK_CLR__ctl_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__ctl_eot__nop 0 +#define R_USB_IRQ_MASK_CLR__ctl_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__bulk_eot__BITNR 8 +#define R_USB_IRQ_MASK_CLR__bulk_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__bulk_eot__nop 0 +#define R_USB_IRQ_MASK_CLR__bulk_eot__clr 1 +#define R_USB_IRQ_MASK_CLR__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_CLR__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__epid_attn__nop 0 +#define R_USB_IRQ_MASK_CLR__epid_attn__clr 1 +#define R_USB_IRQ_MASK_CLR__sof__BITNR 2 +#define R_USB_IRQ_MASK_CLR__sof__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__sof__nop 0 +#define R_USB_IRQ_MASK_CLR__sof__clr 1 +#define R_USB_IRQ_MASK_CLR__port_status__BITNR 1 +#define R_USB_IRQ_MASK_CLR__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__port_status__nop 0 +#define R_USB_IRQ_MASK_CLR__port_status__clr 1 +#define R_USB_IRQ_MASK_CLR__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_CLR__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_CLR__ctl_status__nop 0 +#define R_USB_IRQ_MASK_CLR__ctl_status__clr 1 + +#define R_USB_IRQ_READ (IO_TYPECAST_RO_UWORD 0xb0000206) +#define R_USB_IRQ_READ__iso_eof__BITNR 13 +#define R_USB_IRQ_READ__iso_eof__WIDTH 1 +#define R_USB_IRQ_READ__iso_eof__no_pend 0 +#define R_USB_IRQ_READ__iso_eof__pend 1 +#define R_USB_IRQ_READ__intr_eof__BITNR 12 +#define R_USB_IRQ_READ__intr_eof__WIDTH 1 +#define R_USB_IRQ_READ__intr_eof__no_pend 0 +#define R_USB_IRQ_READ__intr_eof__pend 1 +#define R_USB_IRQ_READ__iso_eot__BITNR 11 +#define R_USB_IRQ_READ__iso_eot__WIDTH 1 +#define R_USB_IRQ_READ__iso_eot__no_pend 0 +#define R_USB_IRQ_READ__iso_eot__pend 1 +#define R_USB_IRQ_READ__intr_eot__BITNR 10 +#define R_USB_IRQ_READ__intr_eot__WIDTH 1 +#define R_USB_IRQ_READ__intr_eot__no_pend 0 +#define R_USB_IRQ_READ__intr_eot__pend 1 +#define R_USB_IRQ_READ__ctl_eot__BITNR 9 +#define R_USB_IRQ_READ__ctl_eot__WIDTH 1 +#define R_USB_IRQ_READ__ctl_eot__no_pend 0 +#define R_USB_IRQ_READ__ctl_eot__pend 1 +#define R_USB_IRQ_READ__bulk_eot__BITNR 8 +#define R_USB_IRQ_READ__bulk_eot__WIDTH 1 +#define R_USB_IRQ_READ__bulk_eot__no_pend 0 +#define R_USB_IRQ_READ__bulk_eot__pend 1 +#define R_USB_IRQ_READ__epid_attn__BITNR 3 +#define R_USB_IRQ_READ__epid_attn__WIDTH 1 +#define R_USB_IRQ_READ__epid_attn__no_pend 0 +#define R_USB_IRQ_READ__epid_attn__pend 1 +#define R_USB_IRQ_READ__sof__BITNR 2 +#define R_USB_IRQ_READ__sof__WIDTH 1 +#define R_USB_IRQ_READ__sof__no_pend 0 +#define R_USB_IRQ_READ__sof__pend 1 +#define R_USB_IRQ_READ__port_status__BITNR 1 +#define R_USB_IRQ_READ__port_status__WIDTH 1 +#define R_USB_IRQ_READ__port_status__no_pend 0 +#define R_USB_IRQ_READ__port_status__pend 1 +#define R_USB_IRQ_READ__ctl_status__BITNR 0 +#define R_USB_IRQ_READ__ctl_status__WIDTH 1 +#define R_USB_IRQ_READ__ctl_status__no_pend 0 +#define R_USB_IRQ_READ__ctl_status__pend 1 + +#define R_USB_IRQ_MASK_SET_DEV (IO_TYPECAST_UWORD 0xb0000204) +#define R_USB_IRQ_MASK_SET_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_MASK_SET_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__out_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__out_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep3_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep2_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep1_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ep0_in_eot__set 1 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__epid_attn__set 1 +#define R_USB_IRQ_MASK_SET_DEV__sof__BITNR 2 +#define R_USB_IRQ_MASK_SET_DEV__sof__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__sof__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__sof__set 1 +#define R_USB_IRQ_MASK_SET_DEV__port_status__BITNR 1 +#define R_USB_IRQ_MASK_SET_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__port_status__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__port_status__set 1 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__nop 0 +#define R_USB_IRQ_MASK_SET_DEV__ctl_status__set 1 + +#define R_USB_IRQ_MASK_READ_DEV (IO_TYPECAST_RO_UWORD 0xb0000204) +#define R_USB_IRQ_MASK_READ_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_MASK_READ_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__out_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__out_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep3_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep2_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep1_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ep0_in_eot__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__epid_attn__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__sof__BITNR 2 +#define R_USB_IRQ_MASK_READ_DEV__sof__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__sof__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__sof__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__port_status__BITNR 1 +#define R_USB_IRQ_MASK_READ_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__port_status__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__port_status__pend 1 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__no_pend 0 +#define R_USB_IRQ_MASK_READ_DEV__ctl_status__pend 1 + +#define R_USB_IRQ_MASK_CLR_DEV (IO_TYPECAST_UWORD 0xb0000206) +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__out_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep3_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep2_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep1_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ep0_in_eot__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__epid_attn__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__sof__BITNR 2 +#define R_USB_IRQ_MASK_CLR_DEV__sof__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__sof__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__sof__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__BITNR 1 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__port_status__clr 1 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__nop 0 +#define R_USB_IRQ_MASK_CLR_DEV__ctl_status__clr 1 + +#define R_USB_IRQ_READ_DEV (IO_TYPECAST_RO_UWORD 0xb0000206) +#define R_USB_IRQ_READ_DEV__out_eot__BITNR 12 +#define R_USB_IRQ_READ_DEV__out_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__out_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__out_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__BITNR 11 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep3_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__BITNR 10 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep2_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__BITNR 9 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep1_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__BITNR 8 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__no_pend 0 +#define R_USB_IRQ_READ_DEV__ep0_in_eot__pend 1 +#define R_USB_IRQ_READ_DEV__epid_attn__BITNR 3 +#define R_USB_IRQ_READ_DEV__epid_attn__WIDTH 1 +#define R_USB_IRQ_READ_DEV__epid_attn__no_pend 0 +#define R_USB_IRQ_READ_DEV__epid_attn__pend 1 +#define R_USB_IRQ_READ_DEV__sof__BITNR 2 +#define R_USB_IRQ_READ_DEV__sof__WIDTH 1 +#define R_USB_IRQ_READ_DEV__sof__no_pend 0 +#define R_USB_IRQ_READ_DEV__sof__pend 1 +#define R_USB_IRQ_READ_DEV__port_status__BITNR 1 +#define R_USB_IRQ_READ_DEV__port_status__WIDTH 1 +#define R_USB_IRQ_READ_DEV__port_status__no_pend 0 +#define R_USB_IRQ_READ_DEV__port_status__pend 1 +#define R_USB_IRQ_READ_DEV__ctl_status__BITNR 0 +#define R_USB_IRQ_READ_DEV__ctl_status__WIDTH 1 +#define R_USB_IRQ_READ_DEV__ctl_status__no_pend 0 +#define R_USB_IRQ_READ_DEV__ctl_status__pend 1 + +#define R_USB_FM_NUMBER (IO_TYPECAST_UDWORD 0xb000020c) +#define R_USB_FM_NUMBER__value__BITNR 0 +#define R_USB_FM_NUMBER__value__WIDTH 32 + +#define R_USB_FM_INTERVAL (IO_TYPECAST_UWORD 0xb0000210) +#define R_USB_FM_INTERVAL__fixed__BITNR 6 +#define R_USB_FM_INTERVAL__fixed__WIDTH 8 +#define R_USB_FM_INTERVAL__adj__BITNR 0 +#define R_USB_FM_INTERVAL__adj__WIDTH 6 + +#define R_USB_FM_REMAINING (IO_TYPECAST_RO_UWORD 0xb0000212) +#define R_USB_FM_REMAINING__value__BITNR 0 +#define R_USB_FM_REMAINING__value__WIDTH 14 + +#define R_USB_FM_PSTART (IO_TYPECAST_UWORD 0xb0000214) +#define R_USB_FM_PSTART__value__BITNR 0 +#define R_USB_FM_PSTART__value__WIDTH 14 + +#define R_USB_RH_STATUS (IO_TYPECAST_RO_BYTE 0xb0000203) +#define R_USB_RH_STATUS__babble2__BITNR 7 +#define R_USB_RH_STATUS__babble2__WIDTH 1 +#define R_USB_RH_STATUS__babble2__no 0 +#define R_USB_RH_STATUS__babble2__yes 1 +#define R_USB_RH_STATUS__babble1__BITNR 6 +#define R_USB_RH_STATUS__babble1__WIDTH 1 +#define R_USB_RH_STATUS__babble1__no 0 +#define R_USB_RH_STATUS__babble1__yes 1 +#define R_USB_RH_STATUS__bus1__BITNR 4 +#define R_USB_RH_STATUS__bus1__WIDTH 2 +#define R_USB_RH_STATUS__bus1__SE0 0 +#define R_USB_RH_STATUS__bus1__Diff0 1 +#define R_USB_RH_STATUS__bus1__Diff1 2 +#define R_USB_RH_STATUS__bus1__SE1 3 +#define R_USB_RH_STATUS__bus2__BITNR 2 +#define R_USB_RH_STATUS__bus2__WIDTH 2 +#define R_USB_RH_STATUS__bus2__SE0 0 +#define R_USB_RH_STATUS__bus2__Diff0 1 +#define R_USB_RH_STATUS__bus2__Diff1 2 +#define R_USB_RH_STATUS__bus2__SE1 3 +#define R_USB_RH_STATUS__nports__BITNR 0 +#define R_USB_RH_STATUS__nports__WIDTH 2 + +#define R_USB_RH_PORT_STATUS_1 (IO_TYPECAST_RO_UWORD 0xb0000218) +#define R_USB_RH_PORT_STATUS_1__speed__BITNR 9 +#define R_USB_RH_PORT_STATUS_1__speed__WIDTH 1 +#define R_USB_RH_PORT_STATUS_1__speed__full 0 +#define R_USB_RH_PORT_STATUS_1__speed__low 1 +#define R_USB_RH_PORT_STATUS_1__power__BITNR 8 +#define R_USB_RH_PORT_STATUS_1__power__WIDTH 1 +#define R_USB_RH_PORT_STATUS_1__reset__BITNR 4 +#define R_USB_RH_PORT_STATUS_1__reset__WIDTH 1 +#define R_USB_RH_PORT_STATUS_1__reset__no 0 +#define R_USB_RH_PORT_STATUS_1__reset__yes 1 +#define R_USB_RH_PORT_STATUS_1__overcurrent__BITNR 3 +#define R_USB_RH_PORT_STATUS_1__overcurrent__WIDTH 1 +#define R_USB_RH_PORT_STATUS_1__overcurrent__no 0 +#define R_USB_RH_PORT_STATUS_1__overcurrent__yes 1 +#define R_USB_RH_PORT_STATUS_1__suspended__BITNR 2 +#define R_USB_RH_PORT_STATUS_1__suspended__WIDTH 1 +#define R_USB_RH_PORT_STATUS_1__suspended__no 0 +#define R_USB_RH_PORT_STATUS_1__suspended__yes 1 +#define R_USB_RH_PORT_STATUS_1__enabled__BITNR 1 +#define R_USB_RH_PORT_STATUS_1__enabled__WIDTH 1 +#define R_USB_RH_PORT_STATUS_1__enabled__no 0 +#define R_USB_RH_PORT_STATUS_1__enabled__yes 1 +#define R_USB_RH_PORT_STATUS_1__connected__BITNR 0 +#define R_USB_RH_PORT_STATUS_1__connected__WIDTH 1 +#define R_USB_RH_PORT_STATUS_1__connected__no 0 +#define R_USB_RH_PORT_STATUS_1__connected__yes 1 + +#define R_USB_RH_PORT_STATUS_2 (IO_TYPECAST_RO_UWORD 0xb000021a) +#define R_USB_RH_PORT_STATUS_2__speed__BITNR 9 +#define R_USB_RH_PORT_STATUS_2__speed__WIDTH 1 +#define R_USB_RH_PORT_STATUS_2__speed__full 0 +#define R_USB_RH_PORT_STATUS_2__speed__low 1 +#define R_USB_RH_PORT_STATUS_2__power__BITNR 8 +#define R_USB_RH_PORT_STATUS_2__power__WIDTH 1 +#define R_USB_RH_PORT_STATUS_2__reset__BITNR 4 +#define R_USB_RH_PORT_STATUS_2__reset__WIDTH 1 +#define R_USB_RH_PORT_STATUS_2__reset__no 0 +#define R_USB_RH_PORT_STATUS_2__reset__yes 1 +#define R_USB_RH_PORT_STATUS_2__overcurrent__BITNR 3 +#define R_USB_RH_PORT_STATUS_2__overcurrent__WIDTH 1 +#define R_USB_RH_PORT_STATUS_2__overcurrent__no 0 +#define R_USB_RH_PORT_STATUS_2__overcurrent__yes 1 +#define R_USB_RH_PORT_STATUS_2__suspended__BITNR 2 +#define R_USB_RH_PORT_STATUS_2__suspended__WIDTH 1 +#define R_USB_RH_PORT_STATUS_2__suspended__no 0 +#define R_USB_RH_PORT_STATUS_2__suspended__yes 1 +#define R_USB_RH_PORT_STATUS_2__enabled__BITNR 1 +#define R_USB_RH_PORT_STATUS_2__enabled__WIDTH 1 +#define R_USB_RH_PORT_STATUS_2__enabled__no 0 +#define R_USB_RH_PORT_STATUS_2__enabled__yes 1 +#define R_USB_RH_PORT_STATUS_2__connected__BITNR 0 +#define R_USB_RH_PORT_STATUS_2__connected__WIDTH 1 +#define R_USB_RH_PORT_STATUS_2__connected__no 0 +#define R_USB_RH_PORT_STATUS_2__connected__yes 1 + +#define R_USB_EPT_INDEX (IO_TYPECAST_BYTE 0xb0000208) +#define R_USB_EPT_INDEX__value__BITNR 0 +#define R_USB_EPT_INDEX__value__WIDTH 5 + +#define R_USB_EPT_DATA (IO_TYPECAST_UDWORD 0xb000021c) +#define R_USB_EPT_DATA__valid__BITNR 31 +#define R_USB_EPT_DATA__valid__WIDTH 1 +#define R_USB_EPT_DATA__valid__no 0 +#define R_USB_EPT_DATA__valid__yes 1 +#define R_USB_EPT_DATA__hold__BITNR 30 +#define R_USB_EPT_DATA__hold__WIDTH 1 +#define R_USB_EPT_DATA__hold__no 0 +#define R_USB_EPT_DATA__hold__yes 1 +#define R_USB_EPT_DATA__error_count_in__BITNR 28 +#define R_USB_EPT_DATA__error_count_in__WIDTH 2 +#define R_USB_EPT_DATA__t_in__BITNR 27 +#define R_USB_EPT_DATA__t_in__WIDTH 1 +#define R_USB_EPT_DATA__low_speed__BITNR 26 +#define R_USB_EPT_DATA__low_speed__WIDTH 1 +#define R_USB_EPT_DATA__low_speed__no 0 +#define R_USB_EPT_DATA__low_speed__yes 1 +#define R_USB_EPT_DATA__port__BITNR 24 +#define R_USB_EPT_DATA__port__WIDTH 2 +#define R_USB_EPT_DATA__port__any 0 +#define R_USB_EPT_DATA__port__p1 1 +#define R_USB_EPT_DATA__port__p2 2 +#define R_USB_EPT_DATA__port__undef 3 +#define R_USB_EPT_DATA__error_code__BITNR 22 +#define R_USB_EPT_DATA__error_code__WIDTH 2 +#define R_USB_EPT_DATA__error_code__no_error 0 +#define R_USB_EPT_DATA__error_code__stall 1 +#define R_USB_EPT_DATA__error_code__bus_error 2 +#define R_USB_EPT_DATA__error_code__buffer_error 3 +#define R_USB_EPT_DATA__t_out__BITNR 21 +#define R_USB_EPT_DATA__t_out__WIDTH 1 +#define R_USB_EPT_DATA__error_count_out__BITNR 19 +#define R_USB_EPT_DATA__error_count_out__WIDTH 2 +#define R_USB_EPT_DATA__max_len__BITNR 11 +#define R_USB_EPT_DATA__max_len__WIDTH 7 +#define R_USB_EPT_DATA__ep__BITNR 7 +#define R_USB_EPT_DATA__ep__WIDTH 4 +#define R_USB_EPT_DATA__dev__BITNR 0 +#define R_USB_EPT_DATA__dev__WIDTH 7 + +#define R_USB_EPT_DATA_ISO (IO_TYPECAST_UDWORD 0xb000021c) +#define R_USB_EPT_DATA_ISO__valid__BITNR 31 +#define R_USB_EPT_DATA_ISO__valid__WIDTH 1 +#define R_USB_EPT_DATA_ISO__valid__no 0 +#define R_USB_EPT_DATA_ISO__valid__yes 1 +#define R_USB_EPT_DATA_ISO__port__BITNR 24 +#define R_USB_EPT_DATA_ISO__port__WIDTH 2 +#define R_USB_EPT_DATA_ISO__port__any 0 +#define R_USB_EPT_DATA_ISO__port__p1 1 +#define R_USB_EPT_DATA_ISO__port__p2 2 +#define R_USB_EPT_DATA_ISO__port__undef 3 +#define R_USB_EPT_DATA_ISO__error_code__BITNR 22 +#define R_USB_EPT_DATA_ISO__error_code__WIDTH 2 +#define R_USB_EPT_DATA_ISO__error_code__no_error 0 +#define R_USB_EPT_DATA_ISO__error_code__stall 1 +#define R_USB_EPT_DATA_ISO__error_code__bus_error 2 +#define R_USB_EPT_DATA_ISO__error_code__TBD3 3 +#define R_USB_EPT_DATA_ISO__max_len__BITNR 11 +#define R_USB_EPT_DATA_ISO__max_len__WIDTH 10 +#define R_USB_EPT_DATA_ISO__ep__BITNR 7 +#define R_USB_EPT_DATA_ISO__ep__WIDTH 4 +#define R_USB_EPT_DATA_ISO__dev__BITNR 0 +#define R_USB_EPT_DATA_ISO__dev__WIDTH 7 + +#define R_USB_EPT_DATA_DEV (IO_TYPECAST_UDWORD 0xb000021c) +#define R_USB_EPT_DATA_DEV__valid__BITNR 31 +#define R_USB_EPT_DATA_DEV__valid__WIDTH 1 +#define R_USB_EPT_DATA_DEV__valid__no 0 +#define R_USB_EPT_DATA_DEV__valid__yes 1 +#define R_USB_EPT_DATA_DEV__hold__BITNR 30 +#define R_USB_EPT_DATA_DEV__hold__WIDTH 1 +#define R_USB_EPT_DATA_DEV__hold__no 0 +#define R_USB_EPT_DATA_DEV__hold__yes 1 +#define R_USB_EPT_DATA_DEV__stall__BITNR 29 +#define R_USB_EPT_DATA_DEV__stall__WIDTH 1 +#define R_USB_EPT_DATA_DEV__stall__no 0 +#define R_USB_EPT_DATA_DEV__stall__yes 1 +#define R_USB_EPT_DATA_DEV__iso_resp__BITNR 28 +#define R_USB_EPT_DATA_DEV__iso_resp__WIDTH 1 +#define R_USB_EPT_DATA_DEV__iso_resp__quiet 0 +#define R_USB_EPT_DATA_DEV__iso_resp__yes 1 +#define R_USB_EPT_DATA_DEV__ctrl__BITNR 27 +#define R_USB_EPT_DATA_DEV__ctrl__WIDTH 1 +#define R_USB_EPT_DATA_DEV__ctrl__no 0 +#define R_USB_EPT_DATA_DEV__ctrl__yes 1 +#define R_USB_EPT_DATA_DEV__iso__BITNR 26 +#define R_USB_EPT_DATA_DEV__iso__WIDTH 1 +#define R_USB_EPT_DATA_DEV__iso__no 0 +#define R_USB_EPT_DATA_DEV__iso__yes 1 +#define R_USB_EPT_DATA_DEV__port__BITNR 24 +#define R_USB_EPT_DATA_DEV__port__WIDTH 2 +#define R_USB_EPT_DATA_DEV__control_phase__BITNR 22 +#define R_USB_EPT_DATA_DEV__control_phase__WIDTH 1 +#define R_USB_EPT_DATA_DEV__t__BITNR 21 +#define R_USB_EPT_DATA_DEV__t__WIDTH 1 +#define R_USB_EPT_DATA_DEV__max_len__BITNR 11 +#define R_USB_EPT_DATA_DEV__max_len__WIDTH 10 +#define R_USB_EPT_DATA_DEV__ep__BITNR 7 +#define R_USB_EPT_DATA_DEV__ep__WIDTH 4 +#define R_USB_EPT_DATA_DEV__dev__BITNR 0 +#define R_USB_EPT_DATA_DEV__dev__WIDTH 7 + +#define R_USB_SNMP_TERROR (IO_TYPECAST_UDWORD 0xb0000220) +#define R_USB_SNMP_TERROR__value__BITNR 0 +#define R_USB_SNMP_TERROR__value__WIDTH 32 + +#define R_USB_EPID_ATTN (IO_TYPECAST_RO_UDWORD 0xb0000224) +#define R_USB_EPID_ATTN__value__BITNR 0 +#define R_USB_EPID_ATTN__value__WIDTH 32 + +#define R_USB_PORT1_DISABLE (IO_TYPECAST_BYTE 0xb000006a) +#define R_USB_PORT1_DISABLE__disable__BITNR 0 +#define R_USB_PORT1_DISABLE__disable__WIDTH 1 +#define R_USB_PORT1_DISABLE__disable__yes 0 +#define R_USB_PORT1_DISABLE__disable__no 1 + +#define R_USB_PORT2_DISABLE (IO_TYPECAST_BYTE 0xb0000052) +#define R_USB_PORT2_DISABLE__disable__BITNR 0 +#define R_USB_PORT2_DISABLE__disable__WIDTH 1 +#define R_USB_PORT2_DISABLE__disable__yes 0 +#define R_USB_PORT2_DISABLE__disable__no 1 + +/* +!* MMU registers +!*/ + +#define R_MMU_CONFIG (IO_TYPECAST_UDWORD 0xb0000240) +#define R_MMU_CONFIG__mmu_enable__BITNR 31 +#define R_MMU_CONFIG__mmu_enable__WIDTH 1 +#define R_MMU_CONFIG__mmu_enable__enable 1 +#define R_MMU_CONFIG__mmu_enable__disable 0 +#define R_MMU_CONFIG__inv_excp__BITNR 18 +#define R_MMU_CONFIG__inv_excp__WIDTH 1 +#define R_MMU_CONFIG__inv_excp__enable 1 +#define R_MMU_CONFIG__inv_excp__disable 0 +#define R_MMU_CONFIG__acc_excp__BITNR 17 +#define R_MMU_CONFIG__acc_excp__WIDTH 1 +#define R_MMU_CONFIG__acc_excp__enable 1 +#define R_MMU_CONFIG__acc_excp__disable 0 +#define R_MMU_CONFIG__we_excp__BITNR 16 +#define R_MMU_CONFIG__we_excp__WIDTH 1 +#define R_MMU_CONFIG__we_excp__enable 1 +#define R_MMU_CONFIG__we_excp__disable 0 +#define R_MMU_CONFIG__seg_f__BITNR 15 +#define R_MMU_CONFIG__seg_f__WIDTH 1 +#define R_MMU_CONFIG__seg_f__seg 1 +#define R_MMU_CONFIG__seg_f__page 0 +#define R_MMU_CONFIG__seg_e__BITNR 14 +#define R_MMU_CONFIG__seg_e__WIDTH 1 +#define R_MMU_CONFIG__seg_e__seg 1 +#define R_MMU_CONFIG__seg_e__page 0 +#define R_MMU_CONFIG__seg_d__BITNR 13 +#define R_MMU_CONFIG__seg_d__WIDTH 1 +#define R_MMU_CONFIG__seg_d__seg 1 +#define R_MMU_CONFIG__seg_d__page 0 +#define R_MMU_CONFIG__seg_c__BITNR 12 +#define R_MMU_CONFIG__seg_c__WIDTH 1 +#define R_MMU_CONFIG__seg_c__seg 1 +#define R_MMU_CONFIG__seg_c__page 0 +#define R_MMU_CONFIG__seg_b__BITNR 11 +#define R_MMU_CONFIG__seg_b__WIDTH 1 +#define R_MMU_CONFIG__seg_b__seg 1 +#define R_MMU_CONFIG__seg_b__page 0 +#define R_MMU_CONFIG__seg_a__BITNR 10 +#define R_MMU_CONFIG__seg_a__WIDTH 1 +#define R_MMU_CONFIG__seg_a__seg 1 +#define R_MMU_CONFIG__seg_a__page 0 +#define R_MMU_CONFIG__seg_9__BITNR 9 +#define R_MMU_CONFIG__seg_9__WIDTH 1 +#define R_MMU_CONFIG__seg_9__seg 1 +#define R_MMU_CONFIG__seg_9__page 0 +#define R_MMU_CONFIG__seg_8__BITNR 8 +#define R_MMU_CONFIG__seg_8__WIDTH 1 +#define R_MMU_CONFIG__seg_8__seg 1 +#define R_MMU_CONFIG__seg_8__page 0 +#define R_MMU_CONFIG__seg_7__BITNR 7 +#define R_MMU_CONFIG__seg_7__WIDTH 1 +#define R_MMU_CONFIG__seg_7__seg 1 +#define R_MMU_CONFIG__seg_7__page 0 +#define R_MMU_CONFIG__seg_6__BITNR 6 +#define R_MMU_CONFIG__seg_6__WIDTH 1 +#define R_MMU_CONFIG__seg_6__seg 1 +#define R_MMU_CONFIG__seg_6__page 0 +#define R_MMU_CONFIG__seg_5__BITNR 5 +#define R_MMU_CONFIG__seg_5__WIDTH 1 +#define R_MMU_CONFIG__seg_5__seg 1 +#define R_MMU_CONFIG__seg_5__page 0 +#define R_MMU_CONFIG__seg_4__BITNR 4 +#define R_MMU_CONFIG__seg_4__WIDTH 1 +#define R_MMU_CONFIG__seg_4__seg 1 +#define R_MMU_CONFIG__seg_4__page 0 +#define R_MMU_CONFIG__seg_3__BITNR 3 +#define R_MMU_CONFIG__seg_3__WIDTH 1 +#define R_MMU_CONFIG__seg_3__seg 1 +#define R_MMU_CONFIG__seg_3__page 0 +#define R_MMU_CONFIG__seg_2__BITNR 2 +#define R_MMU_CONFIG__seg_2__WIDTH 1 +#define R_MMU_CONFIG__seg_2__seg 1 +#define R_MMU_CONFIG__seg_2__page 0 +#define R_MMU_CONFIG__seg_1__BITNR 1 +#define R_MMU_CONFIG__seg_1__WIDTH 1 +#define R_MMU_CONFIG__seg_1__seg 1 +#define R_MMU_CONFIG__seg_1__page 0 +#define R_MMU_CONFIG__seg_0__BITNR 0 +#define R_MMU_CONFIG__seg_0__WIDTH 1 +#define R_MMU_CONFIG__seg_0__seg 1 +#define R_MMU_CONFIG__seg_0__page 0 + +#define R_MMU_KSEG (IO_TYPECAST_UWORD 0xb0000240) +#define R_MMU_KSEG__seg_f__BITNR 15 +#define R_MMU_KSEG__seg_f__WIDTH 1 +#define R_MMU_KSEG__seg_f__seg 1 +#define R_MMU_KSEG__seg_f__page 0 +#define R_MMU_KSEG__seg_e__BITNR 14 +#define R_MMU_KSEG__seg_e__WIDTH 1 +#define R_MMU_KSEG__seg_e__seg 1 +#define R_MMU_KSEG__seg_e__page 0 +#define R_MMU_KSEG__seg_d__BITNR 13 +#define R_MMU_KSEG__seg_d__WIDTH 1 +#define R_MMU_KSEG__seg_d__seg 1 +#define R_MMU_KSEG__seg_d__page 0 +#define R_MMU_KSEG__seg_c__BITNR 12 +#define R_MMU_KSEG__seg_c__WIDTH 1 +#define R_MMU_KSEG__seg_c__seg 1 +#define R_MMU_KSEG__seg_c__page 0 +#define R_MMU_KSEG__seg_b__BITNR 11 +#define R_MMU_KSEG__seg_b__WIDTH 1 +#define R_MMU_KSEG__seg_b__seg 1 +#define R_MMU_KSEG__seg_b__page 0 +#define R_MMU_KSEG__seg_a__BITNR 10 +#define R_MMU_KSEG__seg_a__WIDTH 1 +#define R_MMU_KSEG__seg_a__seg 1 +#define R_MMU_KSEG__seg_a__page 0 +#define R_MMU_KSEG__seg_9__BITNR 9 +#define R_MMU_KSEG__seg_9__WIDTH 1 +#define R_MMU_KSEG__seg_9__seg 1 +#define R_MMU_KSEG__seg_9__page 0 +#define R_MMU_KSEG__seg_8__BITNR 8 +#define R_MMU_KSEG__seg_8__WIDTH 1 +#define R_MMU_KSEG__seg_8__seg 1 +#define R_MMU_KSEG__seg_8__page 0 +#define R_MMU_KSEG__seg_7__BITNR 7 +#define R_MMU_KSEG__seg_7__WIDTH 1 +#define R_MMU_KSEG__seg_7__seg 1 +#define R_MMU_KSEG__seg_7__page 0 +#define R_MMU_KSEG__seg_6__BITNR 6 +#define R_MMU_KSEG__seg_6__WIDTH 1 +#define R_MMU_KSEG__seg_6__seg 1 +#define R_MMU_KSEG__seg_6__page 0 +#define R_MMU_KSEG__seg_5__BITNR 5 +#define R_MMU_KSEG__seg_5__WIDTH 1 +#define R_MMU_KSEG__seg_5__seg 1 +#define R_MMU_KSEG__seg_5__page 0 +#define R_MMU_KSEG__seg_4__BITNR 4 +#define R_MMU_KSEG__seg_4__WIDTH 1 +#define R_MMU_KSEG__seg_4__seg 1 +#define R_MMU_KSEG__seg_4__page 0 +#define R_MMU_KSEG__seg_3__BITNR 3 +#define R_MMU_KSEG__seg_3__WIDTH 1 +#define R_MMU_KSEG__seg_3__seg 1 +#define R_MMU_KSEG__seg_3__page 0 +#define R_MMU_KSEG__seg_2__BITNR 2 +#define R_MMU_KSEG__seg_2__WIDTH 1 +#define R_MMU_KSEG__seg_2__seg 1 +#define R_MMU_KSEG__seg_2__page 0 +#define R_MMU_KSEG__seg_1__BITNR 1 +#define R_MMU_KSEG__seg_1__WIDTH 1 +#define R_MMU_KSEG__seg_1__seg 1 +#define R_MMU_KSEG__seg_1__page 0 +#define R_MMU_KSEG__seg_0__BITNR 0 +#define R_MMU_KSEG__seg_0__WIDTH 1 +#define R_MMU_KSEG__seg_0__seg 1 +#define R_MMU_KSEG__seg_0__page 0 + +#define R_MMU_CTRL (IO_TYPECAST_BYTE 0xb0000242) +#define R_MMU_CTRL__inv_excp__BITNR 2 +#define R_MMU_CTRL__inv_excp__WIDTH 1 +#define R_MMU_CTRL__inv_excp__enable 1 +#define R_MMU_CTRL__inv_excp__disable 0 +#define R_MMU_CTRL__acc_excp__BITNR 1 +#define R_MMU_CTRL__acc_excp__WIDTH 1 +#define R_MMU_CTRL__acc_excp__enable 1 +#define R_MMU_CTRL__acc_excp__disable 0 +#define R_MMU_CTRL__we_excp__BITNR 0 +#define R_MMU_CTRL__we_excp__WIDTH 1 +#define R_MMU_CTRL__we_excp__enable 1 +#define R_MMU_CTRL__we_excp__disable 0 + +#define R_MMU_ENABLE (IO_TYPECAST_BYTE 0xb0000243) +#define R_MMU_ENABLE__mmu_enable__BITNR 7 +#define R_MMU_ENABLE__mmu_enable__WIDTH 1 +#define R_MMU_ENABLE__mmu_enable__enable 1 +#define R_MMU_ENABLE__mmu_enable__disable 0 + +#define R_MMU_KBASE_LO (IO_TYPECAST_UDWORD 0xb0000244) +#define R_MMU_KBASE_LO__base_7__BITNR 28 +#define R_MMU_KBASE_LO__base_7__WIDTH 4 +#define R_MMU_KBASE_LO__base_6__BITNR 24 +#define R_MMU_KBASE_LO__base_6__WIDTH 4 +#define R_MMU_KBASE_LO__base_5__BITNR 20 +#define R_MMU_KBASE_LO__base_5__WIDTH 4 +#define R_MMU_KBASE_LO__base_4__BITNR 16 +#define R_MMU_KBASE_LO__base_4__WIDTH 4 +#define R_MMU_KBASE_LO__base_3__BITNR 12 +#define R_MMU_KBASE_LO__base_3__WIDTH 4 +#define R_MMU_KBASE_LO__base_2__BITNR 8 +#define R_MMU_KBASE_LO__base_2__WIDTH 4 +#define R_MMU_KBASE_LO__base_1__BITNR 4 +#define R_MMU_KBASE_LO__base_1__WIDTH 4 +#define R_MMU_KBASE_LO__base_0__BITNR 0 +#define R_MMU_KBASE_LO__base_0__WIDTH 4 + +#define R_MMU_KBASE_HI (IO_TYPECAST_UDWORD 0xb0000248) +#define R_MMU_KBASE_HI__base_f__BITNR 28 +#define R_MMU_KBASE_HI__base_f__WIDTH 4 +#define R_MMU_KBASE_HI__base_e__BITNR 24 +#define R_MMU_KBASE_HI__base_e__WIDTH 4 +#define R_MMU_KBASE_HI__base_d__BITNR 20 +#define R_MMU_KBASE_HI__base_d__WIDTH 4 +#define R_MMU_KBASE_HI__base_c__BITNR 16 +#define R_MMU_KBASE_HI__base_c__WIDTH 4 +#define R_MMU_KBASE_HI__base_b__BITNR 12 +#define R_MMU_KBASE_HI__base_b__WIDTH 4 +#define R_MMU_KBASE_HI__base_a__BITNR 8 +#define R_MMU_KBASE_HI__base_a__WIDTH 4 +#define R_MMU_KBASE_HI__base_9__BITNR 4 +#define R_MMU_KBASE_HI__base_9__WIDTH 4 +#define R_MMU_KBASE_HI__base_8__BITNR 0 +#define R_MMU_KBASE_HI__base_8__WIDTH 4 + +#define R_MMU_CONTEXT (IO_TYPECAST_BYTE 0xb000024c) +#define R_MMU_CONTEXT__page_id__BITNR 0 +#define R_MMU_CONTEXT__page_id__WIDTH 6 + +#define R_MMU_CAUSE (IO_TYPECAST_RO_UDWORD 0xb0000250) +#define R_MMU_CAUSE__vpn__BITNR 13 +#define R_MMU_CAUSE__vpn__WIDTH 19 +#define R_MMU_CAUSE__miss_excp__BITNR 12 +#define R_MMU_CAUSE__miss_excp__WIDTH 1 +#define R_MMU_CAUSE__miss_excp__yes 1 +#define R_MMU_CAUSE__miss_excp__no 0 +#define R_MMU_CAUSE__inv_excp__BITNR 11 +#define R_MMU_CAUSE__inv_excp__WIDTH 1 +#define R_MMU_CAUSE__inv_excp__yes 1 +#define R_MMU_CAUSE__inv_excp__no 0 +#define R_MMU_CAUSE__acc_excp__BITNR 10 +#define R_MMU_CAUSE__acc_excp__WIDTH 1 +#define R_MMU_CAUSE__acc_excp__yes 1 +#define R_MMU_CAUSE__acc_excp__no 0 +#define R_MMU_CAUSE__we_excp__BITNR 9 +#define R_MMU_CAUSE__we_excp__WIDTH 1 +#define R_MMU_CAUSE__we_excp__yes 1 +#define R_MMU_CAUSE__we_excp__no 0 +#define R_MMU_CAUSE__wr_rd__BITNR 8 +#define R_MMU_CAUSE__wr_rd__WIDTH 1 +#define R_MMU_CAUSE__wr_rd__write 1 +#define R_MMU_CAUSE__wr_rd__read 0 +#define R_MMU_CAUSE__page_id__BITNR 0 +#define R_MMU_CAUSE__page_id__WIDTH 6 + +#define R_TLB_SELECT (IO_TYPECAST_BYTE 0xb0000254) +#define R_TLB_SELECT__index__BITNR 0 +#define R_TLB_SELECT__index__WIDTH 6 + +#define R_TLB_LO (IO_TYPECAST_UDWORD 0xb0000258) +#define R_TLB_LO__pfn__BITNR 13 +#define R_TLB_LO__pfn__WIDTH 19 +#define R_TLB_LO__global__BITNR 3 +#define R_TLB_LO__global__WIDTH 1 +#define R_TLB_LO__global__yes 1 +#define R_TLB_LO__global__no 0 +#define R_TLB_LO__valid__BITNR 2 +#define R_TLB_LO__valid__WIDTH 1 +#define R_TLB_LO__valid__yes 1 +#define R_TLB_LO__valid__no 0 +#define R_TLB_LO__kernel__BITNR 1 +#define R_TLB_LO__kernel__WIDTH 1 +#define R_TLB_LO__kernel__yes 1 +#define R_TLB_LO__kernel__no 0 +#define R_TLB_LO__we__BITNR 0 +#define R_TLB_LO__we__WIDTH 1 +#define R_TLB_LO__we__yes 1 +#define R_TLB_LO__we__no 0 + +#define R_TLB_HI (IO_TYPECAST_UDWORD 0xb000025c) +#define R_TLB_HI__vpn__BITNR 13 +#define R_TLB_HI__vpn__WIDTH 19 +#define R_TLB_HI__page_id__BITNR 0 +#define R_TLB_HI__page_id__WIDTH 6 + +/* +!* Syncrounous serial port registers +!*/ + +#define R_SYNC_SERIAL1_REC_DATA (IO_TYPECAST_RO_UDWORD 0xb000006c) +#define R_SYNC_SERIAL1_REC_DATA__data_in__BITNR 0 +#define R_SYNC_SERIAL1_REC_DATA__data_in__WIDTH 32 + +#define R_SYNC_SERIAL1_REC_WORD (IO_TYPECAST_RO_UWORD 0xb000006c) +#define R_SYNC_SERIAL1_REC_WORD__data_in__BITNR 0 +#define R_SYNC_SERIAL1_REC_WORD__data_in__WIDTH 16 + +#define R_SYNC_SERIAL1_REC_BYTE (IO_TYPECAST_RO_BYTE 0xb000006c) +#define R_SYNC_SERIAL1_REC_BYTE__data_in__BITNR 0 +#define R_SYNC_SERIAL1_REC_BYTE__data_in__WIDTH 8 + +#define R_SYNC_SERIAL1_STATUS (IO_TYPECAST_RO_UDWORD 0xb0000068) +#define R_SYNC_SERIAL1_STATUS__rec_status__BITNR 15 +#define R_SYNC_SERIAL1_STATUS__rec_status__WIDTH 1 +#define R_SYNC_SERIAL1_STATUS__rec_status__running 0 +#define R_SYNC_SERIAL1_STATUS__rec_status__idle 1 +#define R_SYNC_SERIAL1_STATUS__tr_empty__BITNR 14 +#define R_SYNC_SERIAL1_STATUS__tr_empty__WIDTH 1 +#define R_SYNC_SERIAL1_STATUS__tr_empty__empty 1 +#define R_SYNC_SERIAL1_STATUS__tr_empty__not_empty 0 +#define R_SYNC_SERIAL1_STATUS__tr_ready__BITNR 13 +#define R_SYNC_SERIAL1_STATUS__tr_ready__WIDTH 1 +#define R_SYNC_SERIAL1_STATUS__tr_ready__full 0 +#define R_SYNC_SERIAL1_STATUS__tr_ready__ready 1 +#define R_SYNC_SERIAL1_STATUS__pin_1__BITNR 12 +#define R_SYNC_SERIAL1_STATUS__pin_1__WIDTH 1 +#define R_SYNC_SERIAL1_STATUS__pin_1__low 0 +#define R_SYNC_SERIAL1_STATUS__pin_1__high 1 +#define R_SYNC_SERIAL1_STATUS__pin_0__BITNR 11 +#define R_SYNC_SERIAL1_STATUS__pin_0__WIDTH 1 +#define R_SYNC_SERIAL1_STATUS__pin_0__low 0 +#define R_SYNC_SERIAL1_STATUS__pin_0__high 1 +#define R_SYNC_SERIAL1_STATUS__underflow__BITNR 10 +#define R_SYNC_SERIAL1_STATUS__underflow__WIDTH 1 +#define R_SYNC_SERIAL1_STATUS__underflow__no 0 +#define R_SYNC_SERIAL1_STATUS__underflow__yes 1 +#define R_SYNC_SERIAL1_STATUS__overrun__BITNR 9 +#define R_SYNC_SERIAL1_STATUS__overrun__WIDTH 1 +#define R_SYNC_SERIAL1_STATUS__overrun__no 0 +#define R_SYNC_SERIAL1_STATUS__overrun__yes 1 +#define R_SYNC_SERIAL1_STATUS__data_avail__BITNR 8 +#define R_SYNC_SERIAL1_STATUS__data_avail__WIDTH 1 +#define R_SYNC_SERIAL1_STATUS__data_avail__no 0 +#define R_SYNC_SERIAL1_STATUS__data_avail__yes 1 +#define R_SYNC_SERIAL1_STATUS__data__BITNR 0 +#define R_SYNC_SERIAL1_STATUS__data__WIDTH 8 + +#define R_SYNC_SERIAL1_TR_DATA (IO_TYPECAST_UDWORD 0xb000006c) +#define R_SYNC_SERIAL1_TR_DATA__data_out__BITNR 0 +#define R_SYNC_SERIAL1_TR_DATA__data_out__WIDTH 32 + +#define R_SYNC_SERIAL1_TR_WORD (IO_TYPECAST_UWORD 0xb000006c) +#define R_SYNC_SERIAL1_TR_WORD__data_out__BITNR 0 +#define R_SYNC_SERIAL1_TR_WORD__data_out__WIDTH 16 + +#define R_SYNC_SERIAL1_TR_BYTE (IO_TYPECAST_BYTE 0xb000006c) +#define R_SYNC_SERIAL1_TR_BYTE__data_out__BITNR 0 +#define R_SYNC_SERIAL1_TR_BYTE__data_out__WIDTH 8 + +#define R_SYNC_SERIAL1_CTRL (IO_TYPECAST_UDWORD 0xb0000068) +#define R_SYNC_SERIAL1_CTRL__tr_baud__BITNR 28 +#define R_SYNC_SERIAL1_CTRL__tr_baud__WIDTH 4 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c150Hz 0 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c300Hz 1 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c600Hz 2 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c1200Hz 3 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c2400Hz 4 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c4800Hz 5 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c9600Hz 6 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c19k2Hz 7 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c28k8Hz 8 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c57k6Hz 9 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c115k2Hz 10 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c230k4Hz 11 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c460k8Hz 12 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c921k6Hz 13 +#define R_SYNC_SERIAL1_CTRL__tr_baud__c3125kHz 14 +#define R_SYNC_SERIAL1_CTRL__tr_baud__reserved 15 +#define R_SYNC_SERIAL1_CTRL__dma_enable__BITNR 27 +#define R_SYNC_SERIAL1_CTRL__dma_enable__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__dma_enable__on 1 +#define R_SYNC_SERIAL1_CTRL__dma_enable__off 0 +#define R_SYNC_SERIAL1_CTRL__mode__BITNR 24 +#define R_SYNC_SERIAL1_CTRL__mode__WIDTH 3 +#define R_SYNC_SERIAL1_CTRL__mode__master_output 0 +#define R_SYNC_SERIAL1_CTRL__mode__slave_output 1 +#define R_SYNC_SERIAL1_CTRL__mode__master_input 2 +#define R_SYNC_SERIAL1_CTRL__mode__slave_input 3 +#define R_SYNC_SERIAL1_CTRL__mode__master_bidir 4 +#define R_SYNC_SERIAL1_CTRL__mode__slave_bidir 5 +#define R_SYNC_SERIAL1_CTRL__error__BITNR 23 +#define R_SYNC_SERIAL1_CTRL__error__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__error__normal 0 +#define R_SYNC_SERIAL1_CTRL__error__ignore 1 +#define R_SYNC_SERIAL1_CTRL__rec_enable__BITNR 22 +#define R_SYNC_SERIAL1_CTRL__rec_enable__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__rec_enable__disable 0 +#define R_SYNC_SERIAL1_CTRL__rec_enable__enable 1 +#define R_SYNC_SERIAL1_CTRL__f_synctype__BITNR 21 +#define R_SYNC_SERIAL1_CTRL__f_synctype__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__f_synctype__normal 0 +#define R_SYNC_SERIAL1_CTRL__f_synctype__early 1 +#define R_SYNC_SERIAL1_CTRL__f_syncsize__BITNR 19 +#define R_SYNC_SERIAL1_CTRL__f_syncsize__WIDTH 2 +#define R_SYNC_SERIAL1_CTRL__f_syncsize__bit 0 +#define R_SYNC_SERIAL1_CTRL__f_syncsize__word 1 +#define R_SYNC_SERIAL1_CTRL__f_syncsize__extended 2 +#define R_SYNC_SERIAL1_CTRL__f_syncsize__reserved 3 +#define R_SYNC_SERIAL1_CTRL__f_sync__BITNR 18 +#define R_SYNC_SERIAL1_CTRL__f_sync__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__f_sync__on 0 +#define R_SYNC_SERIAL1_CTRL__f_sync__off 1 +#define R_SYNC_SERIAL1_CTRL__clk_mode__BITNR 17 +#define R_SYNC_SERIAL1_CTRL__clk_mode__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__clk_mode__normal 0 +#define R_SYNC_SERIAL1_CTRL__clk_mode__gated 1 +#define R_SYNC_SERIAL1_CTRL__clk_halt__BITNR 16 +#define R_SYNC_SERIAL1_CTRL__clk_halt__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__clk_halt__running 0 +#define R_SYNC_SERIAL1_CTRL__clk_halt__stopped 1 +#define R_SYNC_SERIAL1_CTRL__bitorder__BITNR 15 +#define R_SYNC_SERIAL1_CTRL__bitorder__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__bitorder__lsb 0 +#define R_SYNC_SERIAL1_CTRL__bitorder__msb 1 +#define R_SYNC_SERIAL1_CTRL__tr_enable__BITNR 14 +#define R_SYNC_SERIAL1_CTRL__tr_enable__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__tr_enable__disable 0 +#define R_SYNC_SERIAL1_CTRL__tr_enable__enable 1 +#define R_SYNC_SERIAL1_CTRL__wordsize__BITNR 11 +#define R_SYNC_SERIAL1_CTRL__wordsize__WIDTH 3 +#define R_SYNC_SERIAL1_CTRL__wordsize__size8bit 0 +#define R_SYNC_SERIAL1_CTRL__wordsize__size12bit 1 +#define R_SYNC_SERIAL1_CTRL__wordsize__size16bit 2 +#define R_SYNC_SERIAL1_CTRL__wordsize__size24bit 3 +#define R_SYNC_SERIAL1_CTRL__wordsize__size32bit 4 +#define R_SYNC_SERIAL1_CTRL__buf_empty__BITNR 10 +#define R_SYNC_SERIAL1_CTRL__buf_empty__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__buf_empty__lmt_8 0 +#define R_SYNC_SERIAL1_CTRL__buf_empty__lmt_0 1 +#define R_SYNC_SERIAL1_CTRL__buf_full__BITNR 9 +#define R_SYNC_SERIAL1_CTRL__buf_full__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__buf_full__lmt_32 0 +#define R_SYNC_SERIAL1_CTRL__buf_full__lmt_8 1 +#define R_SYNC_SERIAL1_CTRL__flow_ctrl__BITNR 8 +#define R_SYNC_SERIAL1_CTRL__flow_ctrl__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__flow_ctrl__disabled 0 +#define R_SYNC_SERIAL1_CTRL__flow_ctrl__enabled 1 +#define R_SYNC_SERIAL1_CTRL__clk_polarity__BITNR 6 +#define R_SYNC_SERIAL1_CTRL__clk_polarity__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__clk_polarity__pos 0 +#define R_SYNC_SERIAL1_CTRL__clk_polarity__neg 1 +#define R_SYNC_SERIAL1_CTRL__frame_polarity__BITNR 5 +#define R_SYNC_SERIAL1_CTRL__frame_polarity__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__frame_polarity__normal 0 +#define R_SYNC_SERIAL1_CTRL__frame_polarity__inverted 1 +#define R_SYNC_SERIAL1_CTRL__status_polarity__BITNR 4 +#define R_SYNC_SERIAL1_CTRL__status_polarity__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__status_polarity__normal 0 +#define R_SYNC_SERIAL1_CTRL__status_polarity__inverted 1 +#define R_SYNC_SERIAL1_CTRL__clk_driver__BITNR 3 +#define R_SYNC_SERIAL1_CTRL__clk_driver__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__clk_driver__normal 0 +#define R_SYNC_SERIAL1_CTRL__clk_driver__inverted 1 +#define R_SYNC_SERIAL1_CTRL__frame_driver__BITNR 2 +#define R_SYNC_SERIAL1_CTRL__frame_driver__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__frame_driver__normal 0 +#define R_SYNC_SERIAL1_CTRL__frame_driver__inverted 1 +#define R_SYNC_SERIAL1_CTRL__status_driver__BITNR 1 +#define R_SYNC_SERIAL1_CTRL__status_driver__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__status_driver__normal 0 +#define R_SYNC_SERIAL1_CTRL__status_driver__inverted 1 +#define R_SYNC_SERIAL1_CTRL__def_out0__BITNR 0 +#define R_SYNC_SERIAL1_CTRL__def_out0__WIDTH 1 +#define R_SYNC_SERIAL1_CTRL__def_out0__high 1 +#define R_SYNC_SERIAL1_CTRL__def_out0__low 0 + +#define R_SYNC_SERIAL3_REC_DATA (IO_TYPECAST_RO_UDWORD 0xb000007c) +#define R_SYNC_SERIAL3_REC_DATA__data_in__BITNR 0 +#define R_SYNC_SERIAL3_REC_DATA__data_in__WIDTH 32 + +#define R_SYNC_SERIAL3_REC_WORD (IO_TYPECAST_RO_UWORD 0xb000007c) +#define R_SYNC_SERIAL3_REC_WORD__data_in__BITNR 0 +#define R_SYNC_SERIAL3_REC_WORD__data_in__WIDTH 16 + +#define R_SYNC_SERIAL3_REC_BYTE (IO_TYPECAST_RO_BYTE 0xb000007c) +#define R_SYNC_SERIAL3_REC_BYTE__data_in__BITNR 0 +#define R_SYNC_SERIAL3_REC_BYTE__data_in__WIDTH 8 + +#define R_SYNC_SERIAL3_STATUS (IO_TYPECAST_RO_UDWORD 0xb0000078) +#define R_SYNC_SERIAL3_STATUS__rec_status__BITNR 15 +#define R_SYNC_SERIAL3_STATUS__rec_status__WIDTH 1 +#define R_SYNC_SERIAL3_STATUS__rec_status__running 0 +#define R_SYNC_SERIAL3_STATUS__rec_status__idle 1 +#define R_SYNC_SERIAL3_STATUS__tr_empty__BITNR 14 +#define R_SYNC_SERIAL3_STATUS__tr_empty__WIDTH 1 +#define R_SYNC_SERIAL3_STATUS__tr_empty__empty 1 +#define R_SYNC_SERIAL3_STATUS__tr_empty__not_empty 0 +#define R_SYNC_SERIAL3_STATUS__tr_ready__BITNR 13 +#define R_SYNC_SERIAL3_STATUS__tr_ready__WIDTH 1 +#define R_SYNC_SERIAL3_STATUS__tr_ready__full 0 +#define R_SYNC_SERIAL3_STATUS__tr_ready__ready 1 +#define R_SYNC_SERIAL3_STATUS__pin_1__BITNR 12 +#define R_SYNC_SERIAL3_STATUS__pin_1__WIDTH 1 +#define R_SYNC_SERIAL3_STATUS__pin_1__low 0 +#define R_SYNC_SERIAL3_STATUS__pin_1__high 1 +#define R_SYNC_SERIAL3_STATUS__pin_0__BITNR 11 +#define R_SYNC_SERIAL3_STATUS__pin_0__WIDTH 1 +#define R_SYNC_SERIAL3_STATUS__pin_0__low 0 +#define R_SYNC_SERIAL3_STATUS__pin_0__high 1 +#define R_SYNC_SERIAL3_STATUS__underflow__BITNR 10 +#define R_SYNC_SERIAL3_STATUS__underflow__WIDTH 1 +#define R_SYNC_SERIAL3_STATUS__underflow__no 0 +#define R_SYNC_SERIAL3_STATUS__underflow__yes 1 +#define R_SYNC_SERIAL3_STATUS__overrun__BITNR 9 +#define R_SYNC_SERIAL3_STATUS__overrun__WIDTH 1 +#define R_SYNC_SERIAL3_STATUS__overrun__no 0 +#define R_SYNC_SERIAL3_STATUS__overrun__yes 1 +#define R_SYNC_SERIAL3_STATUS__data_avail__BITNR 8 +#define R_SYNC_SERIAL3_STATUS__data_avail__WIDTH 1 +#define R_SYNC_SERIAL3_STATUS__data_avail__no 0 +#define R_SYNC_SERIAL3_STATUS__data_avail__yes 1 +#define R_SYNC_SERIAL3_STATUS__data__BITNR 0 +#define R_SYNC_SERIAL3_STATUS__data__WIDTH 8 + +#define R_SYNC_SERIAL3_TR_DATA (IO_TYPECAST_UDWORD 0xb000007c) +#define R_SYNC_SERIAL3_TR_DATA__data_out__BITNR 0 +#define R_SYNC_SERIAL3_TR_DATA__data_out__WIDTH 32 + +#define R_SYNC_SERIAL3_TR_WORD (IO_TYPECAST_UWORD 0xb000007c) +#define R_SYNC_SERIAL3_TR_WORD__data_out__BITNR 0 +#define R_SYNC_SERIAL3_TR_WORD__data_out__WIDTH 16 + +#define R_SYNC_SERIAL3_TR_BYTE (IO_TYPECAST_BYTE 0xb000007c) +#define R_SYNC_SERIAL3_TR_BYTE__data_out__BITNR 0 +#define R_SYNC_SERIAL3_TR_BYTE__data_out__WIDTH 8 + +#define R_SYNC_SERIAL3_CTRL (IO_TYPECAST_UDWORD 0xb0000078) +#define R_SYNC_SERIAL3_CTRL__tr_baud__BITNR 28 +#define R_SYNC_SERIAL3_CTRL__tr_baud__WIDTH 4 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c150Hz 0 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c300Hz 1 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c600Hz 2 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c1200Hz 3 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c2400Hz 4 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c4800Hz 5 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c9600Hz 6 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c19k2Hz 7 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c28k8Hz 8 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c57k6Hz 9 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c115k2Hz 10 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c230k4Hz 11 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c460k8Hz 12 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c921k6Hz 13 +#define R_SYNC_SERIAL3_CTRL__tr_baud__c3125kHz 14 +#define R_SYNC_SERIAL3_CTRL__tr_baud__reserved 15 +#define R_SYNC_SERIAL3_CTRL__dma_enable__BITNR 27 +#define R_SYNC_SERIAL3_CTRL__dma_enable__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__dma_enable__on 1 +#define R_SYNC_SERIAL3_CTRL__dma_enable__off 0 +#define R_SYNC_SERIAL3_CTRL__mode__BITNR 24 +#define R_SYNC_SERIAL3_CTRL__mode__WIDTH 3 +#define R_SYNC_SERIAL3_CTRL__mode__master_output 0 +#define R_SYNC_SERIAL3_CTRL__mode__slave_output 1 +#define R_SYNC_SERIAL3_CTRL__mode__master_input 2 +#define R_SYNC_SERIAL3_CTRL__mode__slave_input 3 +#define R_SYNC_SERIAL3_CTRL__mode__master_bidir 4 +#define R_SYNC_SERIAL3_CTRL__mode__slave_bidir 5 +#define R_SYNC_SERIAL3_CTRL__error__BITNR 23 +#define R_SYNC_SERIAL3_CTRL__error__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__error__normal 0 +#define R_SYNC_SERIAL3_CTRL__error__ignore 1 +#define R_SYNC_SERIAL3_CTRL__rec_enable__BITNR 22 +#define R_SYNC_SERIAL3_CTRL__rec_enable__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__rec_enable__disable 0 +#define R_SYNC_SERIAL3_CTRL__rec_enable__enable 1 +#define R_SYNC_SERIAL3_CTRL__f_synctype__BITNR 21 +#define R_SYNC_SERIAL3_CTRL__f_synctype__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__f_synctype__normal 0 +#define R_SYNC_SERIAL3_CTRL__f_synctype__early 1 +#define R_SYNC_SERIAL3_CTRL__f_syncsize__BITNR 19 +#define R_SYNC_SERIAL3_CTRL__f_syncsize__WIDTH 2 +#define R_SYNC_SERIAL3_CTRL__f_syncsize__bit 0 +#define R_SYNC_SERIAL3_CTRL__f_syncsize__word 1 +#define R_SYNC_SERIAL3_CTRL__f_syncsize__extended 2 +#define R_SYNC_SERIAL3_CTRL__f_syncsize__reserved 3 +#define R_SYNC_SERIAL3_CTRL__f_sync__BITNR 18 +#define R_SYNC_SERIAL3_CTRL__f_sync__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__f_sync__on 0 +#define R_SYNC_SERIAL3_CTRL__f_sync__off 1 +#define R_SYNC_SERIAL3_CTRL__clk_mode__BITNR 17 +#define R_SYNC_SERIAL3_CTRL__clk_mode__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__clk_mode__normal 0 +#define R_SYNC_SERIAL3_CTRL__clk_mode__gated 1 +#define R_SYNC_SERIAL3_CTRL__clk_halt__BITNR 16 +#define R_SYNC_SERIAL3_CTRL__clk_halt__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__clk_halt__running 0 +#define R_SYNC_SERIAL3_CTRL__clk_halt__stopped 1 +#define R_SYNC_SERIAL3_CTRL__bitorder__BITNR 15 +#define R_SYNC_SERIAL3_CTRL__bitorder__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__bitorder__lsb 0 +#define R_SYNC_SERIAL3_CTRL__bitorder__msb 1 +#define R_SYNC_SERIAL3_CTRL__tr_enable__BITNR 14 +#define R_SYNC_SERIAL3_CTRL__tr_enable__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__tr_enable__disable 0 +#define R_SYNC_SERIAL3_CTRL__tr_enable__enable 1 +#define R_SYNC_SERIAL3_CTRL__wordsize__BITNR 11 +#define R_SYNC_SERIAL3_CTRL__wordsize__WIDTH 3 +#define R_SYNC_SERIAL3_CTRL__wordsize__size8bit 0 +#define R_SYNC_SERIAL3_CTRL__wordsize__size12bit 1 +#define R_SYNC_SERIAL3_CTRL__wordsize__size16bit 2 +#define R_SYNC_SERIAL3_CTRL__wordsize__size24bit 3 +#define R_SYNC_SERIAL3_CTRL__wordsize__size32bit 4 +#define R_SYNC_SERIAL3_CTRL__buf_empty__BITNR 10 +#define R_SYNC_SERIAL3_CTRL__buf_empty__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__buf_empty__lmt_8 0 +#define R_SYNC_SERIAL3_CTRL__buf_empty__lmt_0 1 +#define R_SYNC_SERIAL3_CTRL__buf_full__BITNR 9 +#define R_SYNC_SERIAL3_CTRL__buf_full__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__buf_full__lmt_32 0 +#define R_SYNC_SERIAL3_CTRL__buf_full__lmt_8 1 +#define R_SYNC_SERIAL3_CTRL__flow_ctrl__BITNR 8 +#define R_SYNC_SERIAL3_CTRL__flow_ctrl__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__flow_ctrl__disabled 0 +#define R_SYNC_SERIAL3_CTRL__flow_ctrl__enabled 1 +#define R_SYNC_SERIAL3_CTRL__clk_polarity__BITNR 6 +#define R_SYNC_SERIAL3_CTRL__clk_polarity__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__clk_polarity__pos 0 +#define R_SYNC_SERIAL3_CTRL__clk_polarity__neg 1 +#define R_SYNC_SERIAL3_CTRL__frame_polarity__BITNR 5 +#define R_SYNC_SERIAL3_CTRL__frame_polarity__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__frame_polarity__normal 0 +#define R_SYNC_SERIAL3_CTRL__frame_polarity__inverted 1 +#define R_SYNC_SERIAL3_CTRL__status_polarity__BITNR 4 +#define R_SYNC_SERIAL3_CTRL__status_polarity__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__status_polarity__normal 0 +#define R_SYNC_SERIAL3_CTRL__status_polarity__inverted 1 +#define R_SYNC_SERIAL3_CTRL__clk_driver__BITNR 3 +#define R_SYNC_SERIAL3_CTRL__clk_driver__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__clk_driver__normal 0 +#define R_SYNC_SERIAL3_CTRL__clk_driver__inverted 1 +#define R_SYNC_SERIAL3_CTRL__frame_driver__BITNR 2 +#define R_SYNC_SERIAL3_CTRL__frame_driver__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__frame_driver__normal 0 +#define R_SYNC_SERIAL3_CTRL__frame_driver__inverted 1 +#define R_SYNC_SERIAL3_CTRL__status_driver__BITNR 1 +#define R_SYNC_SERIAL3_CTRL__status_driver__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__status_driver__normal 0 +#define R_SYNC_SERIAL3_CTRL__status_driver__inverted 1 +#define R_SYNC_SERIAL3_CTRL__def_out0__BITNR 0 +#define R_SYNC_SERIAL3_CTRL__def_out0__WIDTH 1 +#define R_SYNC_SERIAL3_CTRL__def_out0__high 1 +#define R_SYNC_SERIAL3_CTRL__def_out0__low 0 + diff --git a/arch/cris/include/uapi/arch-v10/arch/sv_addr_ag.h b/arch/cris/include/uapi/arch-v10/arch/sv_addr_ag.h new file mode 100644 index 0000000..5517f04 --- /dev/null +++ b/arch/cris/include/uapi/arch-v10/arch/sv_addr_ag.h @@ -0,0 +1,139 @@ +/*!************************************************************************** +*! +*! MACROS: +*! IO_MASK(reg,field) +*! IO_STATE(reg,field,state) +*! IO_EXTRACT(reg,field,val) +*! IO_STATE_VALUE(reg,field,state) +*! IO_BITNR(reg,field) +*! IO_WIDTH(reg,field) +*! IO_FIELD(reg,field,val) +*! IO_RD(reg) +*! All moderegister addresses and fields of these. +*! +*!**************************************************************************/ + +#ifndef __sv_addr_ag_h__ +#define __sv_addr_ag_h__ + + +#define __test_sv_addr__ 0 + +/*------------------------------------------------------------ +!* General macros to manipulate moderegisters. +!*-----------------------------------------------------------*/ + +/* IO_MASK returns a mask for a specified bitfield in a register. + Note that this macro doesn't work when field width is 32 bits. */ +#define IO_MASK(reg, field) IO_MASK_ (reg##_, field##_) +#define IO_MASK_(reg_, field_) \ + ( ( ( 1 << reg_##_##field_##_WIDTH ) - 1 ) << reg_##_##field_##_BITNR ) + +/* IO_STATE returns a constant corresponding to a one of the symbolic + states that the bitfield can have. (Shifted to correct position) */ +#define IO_STATE(reg, field, state) IO_STATE_ (reg##_, field##_, _##state) +#define IO_STATE_(reg_, field_, _state) \ + ( reg_##_##field_##_state << reg_##_##field_##_BITNR ) + +/* IO_EXTRACT returns the masked and shifted value corresponding to the + bitfield can have. */ +#define IO_EXTRACT(reg, field, val) IO_EXTRACT_ (reg##_, field##_, val) +#define IO_EXTRACT_(reg_, field_, val) ( (( ( ( 1 << reg_##_##field_##_WIDTH ) \ + - 1 ) << reg_##_##field_##_BITNR ) & (val)) >> reg_##_##field_##_BITNR ) + +/* IO_STATE_VALUE returns a constant corresponding to a one of the symbolic + states that the bitfield can have. (Not shifted) */ +#define IO_STATE_VALUE(reg, field, state) \ + IO_STATE_VALUE_ (reg##_, field##_, _##state) +#define IO_STATE_VALUE_(reg_, field_, _state) ( reg_##_##field_##_state ) + +/* IO_FIELD shifts the val parameter to be aligned with the bitfield + specified. */ +#define IO_FIELD(reg, field, val) IO_FIELD_ (reg##_, field##_, val) +#define IO_FIELD_(reg_, field_, val) ((val) << reg_##_##field_##_BITNR) + +/* IO_BITNR returns the starting bitnumber of a bitfield. Bit 0 is + LSB and the returned bitnumber is LSB of the field. */ +#define IO_BITNR(reg, field) IO_BITNR_ (reg##_, field##_) +#define IO_BITNR_(reg_, field_) (reg_##_##field_##_BITNR) + +/* IO_WIDTH returns the width, in bits, of a bitfield. */ +#define IO_WIDTH(reg, field) IO_WIDTH_ (reg##_, field##_) +#define IO_WIDTH_(reg_, field_) (reg_##_##field_##_WIDTH) + +/*--- Obsolete. Kept for backw compatibility. ---*/ +/* Reads (or writes) a byte/uword/udword from the specified mode + register. */ +#define IO_RD(reg) (*(volatile u32*)(reg)) +#define IO_RD_B(reg) (*(volatile u8*)(reg)) +#define IO_RD_W(reg) (*(volatile u16*)(reg)) +#define IO_RD_D(reg) (*(volatile u32*)(reg)) + +/*------------------------------------------------------------ +!* Start addresses of the different memory areas. +!*-----------------------------------------------------------*/ + +#define MEM_CSE0_START (0x00000000) +#define MEM_CSE0_SIZE (0x04000000) +#define MEM_CSE1_START (0x04000000) +#define MEM_CSE1_SIZE (0x04000000) +#define MEM_CSR0_START (0x08000000) +#define MEM_CSR1_START (0x0c000000) +#define MEM_CSP0_START (0x10000000) +#define MEM_CSP1_START (0x14000000) +#define MEM_CSP2_START (0x18000000) +#define MEM_CSP3_START (0x1c000000) +#define MEM_CSP4_START (0x20000000) +#define MEM_CSP5_START (0x24000000) +#define MEM_CSP6_START (0x28000000) +#define MEM_CSP7_START (0x2c000000) +#define MEM_DRAM_START (0x40000000) + +#define MEM_NON_CACHEABLE (0x80000000) + +/*------------------------------------------------------------ +!* Type casts used in mode register macros, making pointer +!* dereferencing possible. Empty in assembler. +!*-----------------------------------------------------------*/ + +#ifndef __ASSEMBLER__ +# define IO_TYPECAST_UDWORD (volatile u32*) +# define IO_TYPECAST_RO_UDWORD (const volatile u32*) +# define IO_TYPECAST_UWORD (volatile u16*) +# define IO_TYPECAST_RO_UWORD (const volatile u16*) +# define IO_TYPECAST_BYTE (volatile u8*) +# define IO_TYPECAST_RO_BYTE (const volatile u8*) +#else +# define IO_TYPECAST_UDWORD +# define IO_TYPECAST_RO_UDWORD +# define IO_TYPECAST_UWORD +# define IO_TYPECAST_RO_UWORD +# define IO_TYPECAST_BYTE +# define IO_TYPECAST_RO_BYTE +#endif + +/*------------------------------------------------------------*/ + +#include + +#if __test_sv_addr__ +/* IO_MASK( R_BUS_CONFIG , CE ) */ +IO_MASK( R_WAITSTATES , SRAM_WS ) +IO_MASK( R_TEST , W32 ) + +IO_STATE( R_BUS_CONFIG, CE, DISABLE ) +IO_STATE( R_BUS_CONFIG, CE, ENABLE ) + +IO_STATE( R_DRAM_TIMING, REF, IVAL2 ) + +IO_MASK( R_DRAM_TIMING, REF ) + +IO_MASK( R_EXT_DMA_0_STAT, TFR_COUNT ) >> IO_BITNR( R_EXT_DMA_0_STAT, TFR_COUNT ) + +IO_RD(R_EXT_DMA_0_STAT) & IO_MASK( R_EXT_DMA_0_STAT, S ) + == IO_STATE( R_EXT_DMA_0_STAT, S, STARTED ) +#endif + + +#endif /* ifndef __sv_addr_ag_h__ */ + diff --git a/arch/cris/include/uapi/arch-v10/arch/svinto.h b/arch/cris/include/uapi/arch-v10/arch/svinto.h new file mode 100644 index 0000000..da5c152 --- /dev/null +++ b/arch/cris/include/uapi/arch-v10/arch/svinto.h @@ -0,0 +1,64 @@ +#ifndef _ASM_CRIS_SVINTO_H +#define _ASM_CRIS_SVINTO_H + +#include + +extern unsigned int genconfig_shadow; /* defined and set in head.S */ + +/* dma stuff */ + +enum { /* Available in: */ + d_eol = (1 << 0), /* flags */ + d_eop = (1 << 1), /* flags & status */ + d_wait = (1 << 2), /* flags */ + d_int = (1 << 3), /* flags */ + d_txerr = (1 << 4), /* flags */ + d_stop = (1 << 4), /* status */ + d_ecp = (1 << 4), /* flags & status */ + d_pri = (1 << 5), /* flags & status */ + d_alignerr = (1 << 6), /* status */ + d_crcerr = (1 << 7) /* status */ +}; + +/* Do remember that DMA does not go through the MMU and needs + * a real physical address, not an address virtually mapped or + * paged. Therefore the buf/next ptrs below are unsigned long instead + * of void * to give a warning if you try to put a pointer directly + * to them instead of going through virt_to_phys/phys_to_virt. + */ + +typedef struct etrax_dma_descr { + unsigned short sw_len; /* 0-1 */ + unsigned short ctrl; /* 2-3 */ + unsigned long next; /* 4-7 */ + unsigned long buf; /* 8-11 */ + unsigned short hw_len; /* 12-13 */ + unsigned char status; /* 14 */ + unsigned char fifo_len; /* 15 */ +} etrax_dma_descr; + + +/* Use this for constant numbers only */ +#define RESET_DMA_NUM( n ) \ + *R_DMA_CH##n##_CMD = IO_STATE( R_DMA_CH0_CMD, cmd, reset ) + +/* Use this for constant numbers or symbols, + * having two macros makes it possible to use constant expressions. + */ +#define RESET_DMA( n ) RESET_DMA_NUM( n ) + + +/* Use this for constant numbers only */ +#define WAIT_DMA_NUM( n ) \ + while( (*R_DMA_CH##n##_CMD & IO_MASK( R_DMA_CH0_CMD, cmd )) != \ + IO_STATE( R_DMA_CH0_CMD, cmd, hold ) ) + +/* Use this for constant numbers or symbols + * having two macros makes it possible to use constant expressions. + */ +#define WAIT_DMA( n ) WAIT_DMA_NUM( n ) + +extern void prepare_rx_descriptor(struct etrax_dma_descr *desc); +extern void flush_etrax_cache(void); + +#endif diff --git a/arch/cris/include/uapi/arch-v10/arch/user.h b/arch/cris/include/uapi/arch-v10/arch/user.h new file mode 100644 index 0000000..9303ea7 --- /dev/null +++ b/arch/cris/include/uapi/arch-v10/arch/user.h @@ -0,0 +1,46 @@ +#ifndef __ASM_CRIS_ARCH_USER_H +#define __ASM_CRIS_ARCH_USER_H + +/* User mode registers, used for core dumps. In order to keep ELF_NGREG + sensible we let all registers be 32 bits. The csr registers are included + for future use. */ +struct user_regs_struct { + unsigned long r0; /* General registers. */ + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + unsigned long r12; + unsigned long r13; + unsigned long sp; /* Stack pointer. */ + unsigned long pc; /* Program counter. */ + unsigned long p0; /* Constant zero (only 8 bits). */ + unsigned long vr; /* Version register (only 8 bits). */ + unsigned long p2; /* Reserved. */ + unsigned long p3; /* Reserved. */ + unsigned long p4; /* Constant zero (only 16 bits). */ + unsigned long ccr; /* Condition code register (only 16 bits). */ + unsigned long p6; /* Reserved. */ + unsigned long mof; /* Multiply overflow register. */ + unsigned long p8; /* Constant zero. */ + unsigned long ibr; /* Not accessible. */ + unsigned long irp; /* Not accessible. */ + unsigned long srp; /* Subroutine return pointer. */ + unsigned long bar; /* Not accessible. */ + unsigned long dccr; /* Dword condition code register. */ + unsigned long brp; /* Not accessible. */ + unsigned long usp; /* User-mode stack pointer. Same as sp when + in user mode. */ + unsigned long csrinstr; /* Internal status registers. */ + unsigned long csraddr; + unsigned long csrdata; +}; + +#endif -- cgit v0.10.2 From 98d848ea4c017101f7e4a85917d0e0991f388cd8 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Oct 2012 09:46:42 +0100 Subject: UAPI: (Scripted) Disintegrate arch/cris/include/arch-v32/arch Signed-off-by: David Howells Acked-by: Arnd Bergmann Acked-by: Thomas Gleixner Acked-by: Michael Kerrisk Acked-by: Paul E. McKenney Acked-by: Dave Jones diff --git a/arch/cris/include/arch-v32/arch/Kbuild b/arch/cris/include/arch-v32/arch/Kbuild index 35f2fc4..e69de29 100644 --- a/arch/cris/include/arch-v32/arch/Kbuild +++ b/arch/cris/include/arch-v32/arch/Kbuild @@ -1,2 +0,0 @@ -header-y += user.h -header-y += cryptocop.h diff --git a/arch/cris/include/arch-v32/arch/cryptocop.h b/arch/cris/include/arch-v32/arch/cryptocop.h index e1cd83d..716e434 100644 --- a/arch/cris/include/arch-v32/arch/cryptocop.h +++ b/arch/cris/include/arch-v32/arch/cryptocop.h @@ -2,124 +2,12 @@ * The device /dev/cryptocop is accessible using this driver using * CRYPTOCOP_MAJOR (254) and minor number 0. */ - #ifndef CRYPTOCOP_H #define CRYPTOCOP_H -#include - - -#define CRYPTOCOP_SESSION_ID_NONE (0) - -typedef unsigned long long int cryptocop_session_id; - -/* cryptocop ioctls */ -#define ETRAXCRYPTOCOP_IOCTYPE (250) - -#define CRYPTOCOP_IO_CREATE_SESSION _IOWR(ETRAXCRYPTOCOP_IOCTYPE, 1, struct strcop_session_op) -#define CRYPTOCOP_IO_CLOSE_SESSION _IOW(ETRAXCRYPTOCOP_IOCTYPE, 2, struct strcop_session_op) -#define CRYPTOCOP_IO_PROCESS_OP _IOWR(ETRAXCRYPTOCOP_IOCTYPE, 3, struct strcop_crypto_op) -#define CRYPTOCOP_IO_MAXNR (3) - -typedef enum { - cryptocop_cipher_des = 0, - cryptocop_cipher_3des = 1, - cryptocop_cipher_aes = 2, - cryptocop_cipher_m2m = 3, /* mem2mem is essentially a NULL cipher with blocklength=1 */ - cryptocop_cipher_none -} cryptocop_cipher_type; - -typedef enum { - cryptocop_digest_sha1 = 0, - cryptocop_digest_md5 = 1, - cryptocop_digest_none -} cryptocop_digest_type; - -typedef enum { - cryptocop_csum_le = 0, - cryptocop_csum_be = 1, - cryptocop_csum_none -} cryptocop_csum_type; - -typedef enum { - cryptocop_cipher_mode_ecb = 0, - cryptocop_cipher_mode_cbc, - cryptocop_cipher_mode_none -} cryptocop_cipher_mode; - -typedef enum { - cryptocop_3des_eee = 0, - cryptocop_3des_eed = 1, - cryptocop_3des_ede = 2, - cryptocop_3des_edd = 3, - cryptocop_3des_dee = 4, - cryptocop_3des_ded = 5, - cryptocop_3des_dde = 6, - cryptocop_3des_ddd = 7 -} cryptocop_3des_mode; - -/* Usermode accessible (ioctl) operations. */ -struct strcop_session_op{ - cryptocop_session_id ses_id; - - cryptocop_cipher_type cipher; /* AES, DES, 3DES, m2m, none */ - - cryptocop_cipher_mode cmode; /* ECB, CBC, none */ - cryptocop_3des_mode des3_mode; - - cryptocop_digest_type digest; /* MD5, SHA1, none */ - - cryptocop_csum_type csum; /* BE, LE, none */ - - unsigned char *key; - size_t keylen; -}; - -#define CRYPTOCOP_CSUM_LENGTH (2) -#define CRYPTOCOP_MAX_DIGEST_LENGTH (20) /* SHA-1 20, MD5 16 */ -#define CRYPTOCOP_MAX_IV_LENGTH (16) /* (3)DES==8, AES == 16 */ -#define CRYPTOCOP_MAX_KEY_LENGTH (32) - -struct strcop_crypto_op{ - cryptocop_session_id ses_id; - - /* Indata. */ - unsigned char *indata; - size_t inlen; /* Total indata length. */ - - /* Cipher configuration. */ - unsigned char do_cipher:1; - unsigned char decrypt:1; /* 1 == decrypt, 0 == encrypt */ - unsigned char cipher_explicit:1; - size_t cipher_start; - size_t cipher_len; - /* cipher_iv is used if do_cipher and cipher_explicit and the cipher - mode is CBC. The length is controlled by the type of cipher, - e.g. DES/3DES 8 octets and AES 16 octets. */ - unsigned char cipher_iv[CRYPTOCOP_MAX_IV_LENGTH]; - /* Outdata. */ - unsigned char *cipher_outdata; - size_t cipher_outlen; - - /* digest configuration. */ - unsigned char do_digest:1; - size_t digest_start; - size_t digest_len; - /* Outdata. The actual length is determined by the type of the digest. */ - unsigned char digest[CRYPTOCOP_MAX_DIGEST_LENGTH]; - - /* Checksum configuration. */ - unsigned char do_csum:1; - size_t csum_start; - size_t csum_len; - /* Outdata. */ - unsigned char csum[CRYPTOCOP_CSUM_LENGTH]; -}; +#include - -#ifdef __KERNEL__ - /********** The API to use from inside the kernel. ************/ #include @@ -267,6 +155,4 @@ int cryptocop_job_queue_insert_crypto(struct cryptocop_operation *operation); int cryptocop_job_queue_insert_user_job(struct cryptocop_operation *operation); -#endif /* __KERNEL__ */ - #endif /* CRYPTOCOP_H */ diff --git a/arch/cris/include/arch-v32/arch/user.h b/arch/cris/include/arch-v32/arch/user.h deleted file mode 100644 index 03fa1f3..0000000 --- a/arch/cris/include/arch-v32/arch/user.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _ASM_CRIS_ARCH_USER_H -#define _ASM_CRIS_ARCH_USER_H - -/* User-mode register used for core dumps. */ - -struct user_regs_struct { - unsigned long r0; /* General registers. */ - unsigned long r1; - unsigned long r2; - unsigned long r3; - unsigned long r4; - unsigned long r5; - unsigned long r6; - unsigned long r7; - unsigned long r8; - unsigned long r9; - unsigned long r10; - unsigned long r11; - unsigned long r12; - unsigned long r13; - unsigned long sp; /* R14, Stack pointer. */ - unsigned long acr; /* R15, Address calculation register. */ - unsigned long bz; /* P0, Constant zero (8-bits). */ - unsigned long vr; /* P1, Version register (8-bits). */ - unsigned long pid; /* P2, Process ID (8-bits). */ - unsigned long srs; /* P3, Support register select (8-bits). */ - unsigned long wz; /* P4, Constant zero (16-bits). */ - unsigned long exs; /* P5, Exception status. */ - unsigned long eda; /* P6, Exception data address. */ - unsigned long mof; /* P7, Multiply overflow regiter. */ - unsigned long dz; /* P8, Constant zero (32-bits). */ - unsigned long ebp; /* P9, Exception base pointer. */ - unsigned long erp; /* P10, Exception return pointer. */ - unsigned long srp; /* P11, Subroutine return pointer. */ - unsigned long nrp; /* P12, NMI return pointer. */ - unsigned long ccs; /* P13, Condition code stack. */ - unsigned long usp; /* P14, User mode stack pointer. */ - unsigned long spc; /* P15, Single step PC. */ -}; - -#endif /* _ASM_CRIS_ARCH_USER_H */ diff --git a/arch/cris/include/uapi/arch-v32/arch/Kbuild b/arch/cris/include/uapi/arch-v32/arch/Kbuild index aafaa5a..59efffd 100644 --- a/arch/cris/include/uapi/arch-v32/arch/Kbuild +++ b/arch/cris/include/uapi/arch-v32/arch/Kbuild @@ -1 +1,3 @@ # UAPI Header export list +header-y += cryptocop.h +header-y += user.h diff --git a/arch/cris/include/uapi/arch-v32/arch/cryptocop.h b/arch/cris/include/uapi/arch-v32/arch/cryptocop.h new file mode 100644 index 0000000..694fd13 --- /dev/null +++ b/arch/cris/include/uapi/arch-v32/arch/cryptocop.h @@ -0,0 +1,122 @@ +/* + * The device /dev/cryptocop is accessible using this driver using + * CRYPTOCOP_MAJOR (254) and minor number 0. + */ + +#ifndef _UAPICRYPTOCOP_H +#define _UAPICRYPTOCOP_H + +#include + + +#define CRYPTOCOP_SESSION_ID_NONE (0) + +typedef unsigned long long int cryptocop_session_id; + +/* cryptocop ioctls */ +#define ETRAXCRYPTOCOP_IOCTYPE (250) + +#define CRYPTOCOP_IO_CREATE_SESSION _IOWR(ETRAXCRYPTOCOP_IOCTYPE, 1, struct strcop_session_op) +#define CRYPTOCOP_IO_CLOSE_SESSION _IOW(ETRAXCRYPTOCOP_IOCTYPE, 2, struct strcop_session_op) +#define CRYPTOCOP_IO_PROCESS_OP _IOWR(ETRAXCRYPTOCOP_IOCTYPE, 3, struct strcop_crypto_op) +#define CRYPTOCOP_IO_MAXNR (3) + +typedef enum { + cryptocop_cipher_des = 0, + cryptocop_cipher_3des = 1, + cryptocop_cipher_aes = 2, + cryptocop_cipher_m2m = 3, /* mem2mem is essentially a NULL cipher with blocklength=1 */ + cryptocop_cipher_none +} cryptocop_cipher_type; + +typedef enum { + cryptocop_digest_sha1 = 0, + cryptocop_digest_md5 = 1, + cryptocop_digest_none +} cryptocop_digest_type; + +typedef enum { + cryptocop_csum_le = 0, + cryptocop_csum_be = 1, + cryptocop_csum_none +} cryptocop_csum_type; + +typedef enum { + cryptocop_cipher_mode_ecb = 0, + cryptocop_cipher_mode_cbc, + cryptocop_cipher_mode_none +} cryptocop_cipher_mode; + +typedef enum { + cryptocop_3des_eee = 0, + cryptocop_3des_eed = 1, + cryptocop_3des_ede = 2, + cryptocop_3des_edd = 3, + cryptocop_3des_dee = 4, + cryptocop_3des_ded = 5, + cryptocop_3des_dde = 6, + cryptocop_3des_ddd = 7 +} cryptocop_3des_mode; + +/* Usermode accessible (ioctl) operations. */ +struct strcop_session_op{ + cryptocop_session_id ses_id; + + cryptocop_cipher_type cipher; /* AES, DES, 3DES, m2m, none */ + + cryptocop_cipher_mode cmode; /* ECB, CBC, none */ + cryptocop_3des_mode des3_mode; + + cryptocop_digest_type digest; /* MD5, SHA1, none */ + + cryptocop_csum_type csum; /* BE, LE, none */ + + unsigned char *key; + size_t keylen; +}; + +#define CRYPTOCOP_CSUM_LENGTH (2) +#define CRYPTOCOP_MAX_DIGEST_LENGTH (20) /* SHA-1 20, MD5 16 */ +#define CRYPTOCOP_MAX_IV_LENGTH (16) /* (3)DES==8, AES == 16 */ +#define CRYPTOCOP_MAX_KEY_LENGTH (32) + +struct strcop_crypto_op{ + cryptocop_session_id ses_id; + + /* Indata. */ + unsigned char *indata; + size_t inlen; /* Total indata length. */ + + /* Cipher configuration. */ + unsigned char do_cipher:1; + unsigned char decrypt:1; /* 1 == decrypt, 0 == encrypt */ + unsigned char cipher_explicit:1; + size_t cipher_start; + size_t cipher_len; + /* cipher_iv is used if do_cipher and cipher_explicit and the cipher + mode is CBC. The length is controlled by the type of cipher, + e.g. DES/3DES 8 octets and AES 16 octets. */ + unsigned char cipher_iv[CRYPTOCOP_MAX_IV_LENGTH]; + /* Outdata. */ + unsigned char *cipher_outdata; + size_t cipher_outlen; + + /* digest configuration. */ + unsigned char do_digest:1; + size_t digest_start; + size_t digest_len; + /* Outdata. The actual length is determined by the type of the digest. */ + unsigned char digest[CRYPTOCOP_MAX_DIGEST_LENGTH]; + + /* Checksum configuration. */ + unsigned char do_csum:1; + size_t csum_start; + size_t csum_len; + /* Outdata. */ + unsigned char csum[CRYPTOCOP_CSUM_LENGTH]; +}; + + + + +#endif /* _UAPICRYPTOCOP_H */ diff --git a/arch/cris/include/uapi/arch-v32/arch/user.h b/arch/cris/include/uapi/arch-v32/arch/user.h new file mode 100644 index 0000000..03fa1f3 --- /dev/null +++ b/arch/cris/include/uapi/arch-v32/arch/user.h @@ -0,0 +1,41 @@ +#ifndef _ASM_CRIS_ARCH_USER_H +#define _ASM_CRIS_ARCH_USER_H + +/* User-mode register used for core dumps. */ + +struct user_regs_struct { + unsigned long r0; /* General registers. */ + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + unsigned long r12; + unsigned long r13; + unsigned long sp; /* R14, Stack pointer. */ + unsigned long acr; /* R15, Address calculation register. */ + unsigned long bz; /* P0, Constant zero (8-bits). */ + unsigned long vr; /* P1, Version register (8-bits). */ + unsigned long pid; /* P2, Process ID (8-bits). */ + unsigned long srs; /* P3, Support register select (8-bits). */ + unsigned long wz; /* P4, Constant zero (16-bits). */ + unsigned long exs; /* P5, Exception status. */ + unsigned long eda; /* P6, Exception data address. */ + unsigned long mof; /* P7, Multiply overflow regiter. */ + unsigned long dz; /* P8, Constant zero (32-bits). */ + unsigned long ebp; /* P9, Exception base pointer. */ + unsigned long erp; /* P10, Exception return pointer. */ + unsigned long srp; /* P11, Subroutine return pointer. */ + unsigned long nrp; /* P12, NMI return pointer. */ + unsigned long ccs; /* P13, Condition code stack. */ + unsigned long usp; /* P14, User mode stack pointer. */ + unsigned long spc; /* P15, Single step PC. */ +}; + +#endif /* _ASM_CRIS_ARCH_USER_H */ -- cgit v0.10.2 From e717abac8a9f65eee6de3bb37e10c6916bced483 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Oct 2012 09:46:45 +0100 Subject: UAPI: (Scripted) Disintegrate arch/cris/include/asm Signed-off-by: David Howells Acked-by: Arnd Bergmann Acked-by: Thomas Gleixner Acked-by: Michael Kerrisk Acked-by: Paul E. McKenney Acked-by: Dave Jones diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index a8eab26..9fa0059 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -1,11 +1,6 @@ -include include/asm-generic/Kbuild.asm header-y += arch-v10/ header-y += arch-v32/ -header-y += ethernet.h -header-y += etraxgpio.h -header-y += rs485.h -header-y += sync_serial.h generic-y += clkdev.h diff --git a/arch/cris/include/asm/auxvec.h b/arch/cris/include/asm/auxvec.h deleted file mode 100644 index cb30b01..0000000 --- a/arch/cris/include/asm/auxvec.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __ASMCRIS_AUXVEC_H -#define __ASMCRIS_AUXVEC_H - -#endif diff --git a/arch/cris/include/asm/bitsperlong.h b/arch/cris/include/asm/bitsperlong.h deleted file mode 100644 index 6dc0bb0..0000000 --- a/arch/cris/include/asm/bitsperlong.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/asm/byteorder.h b/arch/cris/include/asm/byteorder.h deleted file mode 100644 index bcd1897..0000000 --- a/arch/cris/include/asm/byteorder.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _CRIS_BYTEORDER_H -#define _CRIS_BYTEORDER_H - -#include - -#endif - - diff --git a/arch/cris/include/asm/errno.h b/arch/cris/include/asm/errno.h deleted file mode 100644 index 2bf5eb5..0000000 --- a/arch/cris/include/asm/errno.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRIS_ERRNO_H -#define _CRIS_ERRNO_H - -#include - -#endif diff --git a/arch/cris/include/asm/ethernet.h b/arch/cris/include/asm/ethernet.h deleted file mode 100644 index 4d58652..0000000 --- a/arch/cris/include/asm/ethernet.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ioctl defines for ethernet driver - * - * Copyright (c) 2001 Axis Communications AB - * - * Author: Mikael Starvik - * - */ - -#ifndef _CRIS_ETHERNET_H -#define _CRIS_ETHERNET_H -#define SET_ETH_SPEED_AUTO SIOCDEVPRIVATE /* Auto neg speed */ -#define SET_ETH_SPEED_10 SIOCDEVPRIVATE+1 /* 10 Mbps */ -#define SET_ETH_SPEED_100 SIOCDEVPRIVATE+2 /* 100 Mbps. */ -#define SET_ETH_DUPLEX_AUTO SIOCDEVPRIVATE+3 /* Auto neg duplex */ -#define SET_ETH_DUPLEX_HALF SIOCDEVPRIVATE+4 /* Full duplex */ -#define SET_ETH_DUPLEX_FULL SIOCDEVPRIVATE+5 /* Half duplex */ -#define SET_ETH_ENABLE_LEDS SIOCDEVPRIVATE+6 /* Enable net LEDs */ -#define SET_ETH_DISABLE_LEDS SIOCDEVPRIVATE+7 /* Disable net LEDs */ -#define SET_ETH_AUTONEG SIOCDEVPRIVATE+8 -#endif /* _CRIS_ETHERNET_H */ diff --git a/arch/cris/include/asm/etraxgpio.h b/arch/cris/include/asm/etraxgpio.h deleted file mode 100644 index 461c089..0000000 --- a/arch/cris/include/asm/etraxgpio.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * The following devices are accessible using this driver using - * GPIO_MAJOR (120) and a couple of minor numbers. - * - * For ETRAX 100LX (CONFIG_ETRAX_ARCH_V10): - * /dev/gpioa minor 0, 8 bit GPIO, each bit can change direction - * /dev/gpiob minor 1, 8 bit GPIO, each bit can change direction - * /dev/leds minor 2, Access to leds depending on kernelconfig - * /dev/gpiog minor 3 - * g0dir, g8_15dir, g16_23dir, g24 dir configurable in R_GEN_CONFIG - * g1-g7 and g25-g31 is both input and outputs but on different pins - * Also note that some bits change pins depending on what interfaces - * are enabled. - * - * For ETRAX FS (CONFIG_ETRAXFS): - * /dev/gpioa minor 0, 8 bit GPIO, each bit can change direction - * /dev/gpiob minor 1, 18 bit GPIO, each bit can change direction - * /dev/gpioc minor 3, 18 bit GPIO, each bit can change direction - * /dev/gpiod minor 4, 18 bit GPIO, each bit can change direction - * /dev/gpioe minor 5, 18 bit GPIO, each bit can change direction - * /dev/leds minor 2, Access to leds depending on kernelconfig - * - * For ARTPEC-3 (CONFIG_CRIS_MACH_ARTPEC3): - * /dev/gpioa minor 0, 32 bit GPIO, each bit can change direction - * /dev/gpiob minor 1, 32 bit GPIO, each bit can change direction - * /dev/gpioc minor 3, 16 bit GPIO, each bit can change direction - * /dev/gpiod minor 4, 32 bit GPIO, input only - * /dev/leds minor 2, Access to leds depending on kernelconfig - * /dev/pwm0 minor 16, PWM channel 0 on PA30 - * /dev/pwm1 minor 17, PWM channel 1 on PA31 - * /dev/pwm2 minor 18, PWM channel 2 on PB26 - * /dev/ppwm minor 19, PPWM channel - * - */ -#ifndef _ASM_ETRAXGPIO_H -#define _ASM_ETRAXGPIO_H - -#define GPIO_MINOR_FIRST 0 - -#define ETRAXGPIO_IOCTYPE 43 - -/* etraxgpio _IOC_TYPE, bits 8 to 15 in ioctl cmd */ -#ifdef CONFIG_ETRAX_ARCH_V10 -#define GPIO_MINOR_A 0 -#define GPIO_MINOR_B 1 -#define GPIO_MINOR_LEDS 2 -#define GPIO_MINOR_G 3 -#define GPIO_MINOR_LAST 3 -#define GPIO_MINOR_LAST_REAL GPIO_MINOR_LAST -#endif - -#ifdef CONFIG_ETRAXFS -#define GPIO_MINOR_A 0 -#define GPIO_MINOR_B 1 -#define GPIO_MINOR_LEDS 2 -#define GPIO_MINOR_C 3 -#define GPIO_MINOR_D 4 -#define GPIO_MINOR_E 5 -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -#define GPIO_MINOR_V 6 -#define GPIO_MINOR_LAST 6 -#else -#define GPIO_MINOR_LAST 5 -#endif -#define GPIO_MINOR_LAST_REAL GPIO_MINOR_LAST -#endif - -#ifdef CONFIG_CRIS_MACH_ARTPEC3 -#define GPIO_MINOR_A 0 -#define GPIO_MINOR_B 1 -#define GPIO_MINOR_LEDS 2 -#define GPIO_MINOR_C 3 -#define GPIO_MINOR_D 4 -#ifdef CONFIG_ETRAX_VIRTUAL_GPIO -#define GPIO_MINOR_V 6 -#define GPIO_MINOR_LAST 6 -#else -#define GPIO_MINOR_LAST 4 -#endif -#define GPIO_MINOR_FIRST_PWM 16 -#define GPIO_MINOR_PWM0 (GPIO_MINOR_FIRST_PWM+0) -#define GPIO_MINOR_PWM1 (GPIO_MINOR_FIRST_PWM+1) -#define GPIO_MINOR_PWM2 (GPIO_MINOR_FIRST_PWM+2) -#define GPIO_MINOR_PPWM (GPIO_MINOR_FIRST_PWM+3) -#define GPIO_MINOR_LAST_PWM GPIO_MINOR_PPWM -#define GPIO_MINOR_LAST_REAL GPIO_MINOR_LAST_PWM -#endif - - - -/* supported ioctl _IOC_NR's */ - -#define IO_READBITS 0x1 /* read and return current port bits (obsolete) */ -#define IO_SETBITS 0x2 /* set the bits marked by 1 in the argument */ -#define IO_CLRBITS 0x3 /* clear the bits marked by 1 in the argument */ - -/* the alarm is waited for by select() */ - -#define IO_HIGHALARM 0x4 /* set alarm on high for bits marked by 1 */ -#define IO_LOWALARM 0x5 /* set alarm on low for bits marked by 1 */ -#define IO_CLRALARM 0x6 /* clear alarm for bits marked by 1 */ - -/* LED ioctl */ -#define IO_LEDACTIVE_SET 0x7 /* set active led - * 0=off, 1=green, 2=red, 3=yellow */ - -/* GPIO direction ioctl's */ -#define IO_READDIR 0x8 /* Read direction 0=input 1=output (obsolete) */ -#define IO_SETINPUT 0x9 /* Set direction for bits set, 0=unchanged 1=input, - returns mask with current inputs (obsolete) */ -#define IO_SETOUTPUT 0xA /* Set direction for bits set, 0=unchanged 1=output, - returns mask with current outputs (obsolete)*/ - -/* LED ioctl extended */ -#define IO_LED_SETBIT 0xB -#define IO_LED_CLRBIT 0xC - -/* SHUTDOWN ioctl */ -#define IO_SHUTDOWN 0xD -#define IO_GET_PWR_BT 0xE - -/* Bit toggling in driver settings */ -/* bit set in low byte0 is CLK mask (0x00FF), - bit set in byte1 is DATA mask (0xFF00) - msb, data_mask[7:0] , clk_mask[7:0] - */ -#define IO_CFG_WRITE_MODE 0xF -#define IO_CFG_WRITE_MODE_VALUE(msb, data_mask, clk_mask) \ - ( (((msb)&1) << 16) | (((data_mask) &0xFF) << 8) | ((clk_mask) & 0xFF) ) - -/* The following 4 ioctl's take a pointer as argument and handles - * 32 bit ports (port G) properly. - * These replaces IO_READBITS,IO_SETINPUT AND IO_SETOUTPUT - */ -#define IO_READ_INBITS 0x10 /* *arg is result of reading the input pins */ -#define IO_READ_OUTBITS 0x11 /* *arg is result of reading the output shadow */ -#define IO_SETGET_INPUT 0x12 /* bits set in *arg is set to input, */ - /* *arg updated with current input pins. */ -#define IO_SETGET_OUTPUT 0x13 /* bits set in *arg is set to output, */ - /* *arg updated with current output pins. */ - -/* The following ioctl's are applicable to the PWM channels only */ - -#define IO_PWM_SET_MODE 0x20 - -enum io_pwm_mode { - PWM_OFF = 0, /* disabled, deallocated */ - PWM_STANDARD = 1, /* 390 kHz, duty cycle 0..255/256 */ - PWM_FAST = 2, /* variable freq, w/ 10ns active pulse len */ - PWM_VARFREQ = 3, /* individually configurable high/low periods */ - PWM_SOFT = 4 /* software generated */ -}; - -struct io_pwm_set_mode { - enum io_pwm_mode mode; -}; - -/* Only for mode PWM_VARFREQ. Period lo/high set in increments of 10ns - * from 10ns (value = 0) to 81920ns (value = 8191) - * (Resulting frequencies range from 50 MHz (10ns + 10ns) down to - * 6.1 kHz (81920ns + 81920ns) at 50% duty cycle, to 12.2 kHz at min/max duty - * cycle (81920 + 10ns or 10ns + 81920ns, respectively).) - */ -#define IO_PWM_SET_PERIOD 0x21 - -struct io_pwm_set_period { - unsigned int lo; /* 0..8191 */ - unsigned int hi; /* 0..8191 */ -}; - -/* Only for modes PWM_STANDARD and PWM_FAST. - * For PWM_STANDARD, set duty cycle of 390 kHz PWM output signal, from - * 0 (value = 0) to 255/256 (value = 255). - * For PWM_FAST, set duty cycle of PWM output signal from - * 0% (value = 0) to 100% (value = 255). Output signal in this mode - * is a 10ns pulse surrounded by a high or low level depending on duty - * cycle (except for 0% and 100% which result in a constant output). - * Resulting output frequency varies from 50 MHz at 50% duty cycle, - * down to 390 kHz at min/max duty cycle. - */ -#define IO_PWM_SET_DUTY 0x22 - -struct io_pwm_set_duty { - int duty; /* 0..255 */ -}; - -/* Returns information about the latest PWM pulse. - * lo: Length of the latest low period, in units of 10ns. - * hi: Length of the latest high period, in units of 10ns. - * cnt: Time since last detected edge, in units of 10ns. - * - * The input source to PWM is decied by IO_PWM_SET_INPUT_SRC. - * - * NOTE: All PWM devices is connected to the same input source. - */ -#define IO_PWM_GET_PERIOD 0x23 - -struct io_pwm_get_period { - unsigned int lo; - unsigned int hi; - unsigned int cnt; -}; - -/* Sets the input source for the PWM input. For the src value see the - * register description for gio:rw_pwm_in_cfg. - * - * NOTE: All PWM devices is connected to the same input source. - */ -#define IO_PWM_SET_INPUT_SRC 0x24 -struct io_pwm_set_input_src { - unsigned int src; /* 0..7 */ -}; - -/* Sets the duty cycles in steps of 1/256, 0 = 0%, 255 = 100% duty cycle */ -#define IO_PPWM_SET_DUTY 0x25 - -struct io_ppwm_set_duty { - int duty; /* 0..255 */ -}; - -/* Configuraton struct for the IO_PWMCLK_SET_CONFIG ioctl to configure - * PWM capable gpio pins: - */ -#define IO_PWMCLK_SETGET_CONFIG 0x26 -struct gpio_pwmclk_conf { - unsigned int gpiopin; /* The pin number based on the opened device */ - unsigned int baseclk; /* The base clock to use, or sw will select one close*/ - unsigned int low; /* The number of low periods of the baseclk */ - unsigned int high; /* The number of high periods of the baseclk */ -}; - -/* Examples: - * To get a symmetric 12 MHz clock without knowing anything about the hardware: - * baseclk = 12000000, low = 0, high = 0 - * To just get info of current setting: - * baseclk = 0, low = 0, high = 0, the values will be updated by driver. - */ - -#endif diff --git a/arch/cris/include/asm/fcntl.h b/arch/cris/include/asm/fcntl.h deleted file mode 100644 index 46ab12d..0000000 --- a/arch/cris/include/asm/fcntl.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/asm/ioctl.h b/arch/cris/include/asm/ioctl.h deleted file mode 100644 index b279fe0..0000000 --- a/arch/cris/include/asm/ioctl.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/asm/ioctls.h b/arch/cris/include/asm/ioctls.h deleted file mode 100644 index 488fbb3..0000000 --- a/arch/cris/include/asm/ioctls.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __ARCH_CRIS_IOCTLS_H__ -#define __ARCH_CRIS_IOCTLS_H__ - -#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TIOCSERSETRS485 0x5461 /* enable rs-485 (deprecated) */ -#define TIOCSERWRRS485 0x5462 /* write rs-485 */ -#define TIOCSRS485 0x5463 /* enable rs-485 */ - -#include - -#endif diff --git a/arch/cris/include/asm/ipcbuf.h b/arch/cris/include/asm/ipcbuf.h deleted file mode 100644 index 84c7e51..0000000 --- a/arch/cris/include/asm/ipcbuf.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/asm/mman.h b/arch/cris/include/asm/mman.h deleted file mode 100644 index 8eebf89..0000000 --- a/arch/cris/include/asm/mman.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/asm/msgbuf.h b/arch/cris/include/asm/msgbuf.h deleted file mode 100644 index ada63df..0000000 --- a/arch/cris/include/asm/msgbuf.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _CRIS_MSGBUF_H -#define _CRIS_MSGBUF_H - -/* verbatim copy of asm-i386 version */ - -/* - * The msqid64_ds structure for CRIS architecture. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct msqid64_ds { - struct ipc64_perm msg_perm; - __kernel_time_t msg_stime; /* last msgsnd time */ - unsigned long __unused1; - __kernel_time_t msg_rtime; /* last msgrcv time */ - unsigned long __unused2; - __kernel_time_t msg_ctime; /* last change time */ - unsigned long __unused3; - unsigned long msg_cbytes; /* current number of bytes on queue */ - unsigned long msg_qnum; /* number of messages in queue */ - unsigned long msg_qbytes; /* max number of bytes on queue */ - __kernel_pid_t msg_lspid; /* pid of last msgsnd */ - __kernel_pid_t msg_lrpid; /* last receive pid */ - unsigned long __unused4; - unsigned long __unused5; -}; - -#endif /* _CRIS_MSGBUF_H */ diff --git a/arch/cris/include/asm/param.h b/arch/cris/include/asm/param.h deleted file mode 100644 index 484fcf8..0000000 --- a/arch/cris/include/asm/param.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _ASMCRIS_PARAM_H -#define _ASMCRIS_PARAM_H - -/* Currently we assume that HZ=100 is good for CRIS. */ - -#define EXEC_PAGESIZE 8192 - -#include - -#endif /* _ASMCRIS_PARAM_H */ diff --git a/arch/cris/include/asm/poll.h b/arch/cris/include/asm/poll.h deleted file mode 100644 index c98509d..0000000 --- a/arch/cris/include/asm/poll.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/asm/posix_types.h b/arch/cris/include/asm/posix_types.h deleted file mode 100644 index ce4e517..0000000 --- a/arch/cris/include/asm/posix_types.h +++ /dev/null @@ -1,35 +0,0 @@ -/* $Id: posix_types.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ - -/* We cheat a bit and use our C-coded bitops functions from asm/bitops.h */ -/* I guess we should write these in assembler because they are used often. */ - -#ifndef __ARCH_CRIS_POSIX_TYPES_H -#define __ARCH_CRIS_POSIX_TYPES_H - -/* - * This file is generally used by user-level software, so you need to - * be a little careful about namespace pollution etc. Also, we cannot - * assume GCC is being used. - */ - -typedef unsigned short __kernel_mode_t; -#define __kernel_mode_t __kernel_mode_t - -typedef unsigned short __kernel_ipc_pid_t; -#define __kernel_ipc_pid_t __kernel_ipc_pid_t - -typedef unsigned short __kernel_uid_t; -typedef unsigned short __kernel_gid_t; -#define __kernel_uid_t __kernel_uid_t - -typedef __SIZE_TYPE__ __kernel_size_t; -typedef long __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -#define __kernel_size_t __kernel_size_t - -typedef unsigned short __kernel_old_dev_t; -#define __kernel_old_dev_t __kernel_old_dev_t - -#include - -#endif /* __ARCH_CRIS_POSIX_TYPES_H */ diff --git a/arch/cris/include/asm/ptrace.h b/arch/cris/include/asm/ptrace.h index 6618893..2de84d7 100644 --- a/arch/cris/include/asm/ptrace.h +++ b/arch/cris/include/asm/ptrace.h @@ -1,9 +1,8 @@ #ifndef _CRIS_PTRACE_H #define _CRIS_PTRACE_H -#include +#include -#ifdef __KERNEL__ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ #define PTRACE_GETREGS 12 @@ -11,6 +10,4 @@ #define profile_pc(regs) instruction_pointer(regs) -#endif /* __KERNEL__ */ - #endif /* _CRIS_PTRACE_H */ diff --git a/arch/cris/include/asm/resource.h b/arch/cris/include/asm/resource.h deleted file mode 100644 index b5d2944..0000000 --- a/arch/cris/include/asm/resource.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRIS_RESOURCE_H -#define _CRIS_RESOURCE_H - -#include - -#endif diff --git a/arch/cris/include/asm/rs485.h b/arch/cris/include/asm/rs485.h deleted file mode 100644 index ad40f9f..0000000 --- a/arch/cris/include/asm/rs485.h +++ /dev/null @@ -1,18 +0,0 @@ -/* RS-485 structures */ - -/* Used with ioctl() TIOCSERSETRS485 for backward compatibility! - * XXX: Do not use it for new code! - */ -struct rs485_control { - unsigned short rts_on_send; - unsigned short rts_after_sent; - unsigned long delay_rts_before_send; - unsigned short enabled; -}; - -/* Used with ioctl() TIOCSERWRRS485 */ -struct rs485_write { - unsigned short outc_size; - unsigned char *outc; -}; - diff --git a/arch/cris/include/asm/sembuf.h b/arch/cris/include/asm/sembuf.h deleted file mode 100644 index 7fed984..0000000 --- a/arch/cris/include/asm/sembuf.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _CRIS_SEMBUF_H -#define _CRIS_SEMBUF_H - -/* - * The semid64_ds structure for CRIS architecture. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct semid64_ds { - struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ - __kernel_time_t sem_otime; /* last semop time */ - unsigned long __unused1; - __kernel_time_t sem_ctime; /* last change time */ - unsigned long __unused2; - unsigned long sem_nsems; /* no. of semaphores in array */ - unsigned long __unused3; - unsigned long __unused4; -}; - -#endif /* _CRIS_SEMBUF_H */ diff --git a/arch/cris/include/asm/setup.h b/arch/cris/include/asm/setup.h deleted file mode 100644 index b907286..0000000 --- a/arch/cris/include/asm/setup.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRIS_SETUP_H -#define _CRIS_SETUP_H - -#define COMMAND_LINE_SIZE 256 - -#endif diff --git a/arch/cris/include/asm/shmbuf.h b/arch/cris/include/asm/shmbuf.h deleted file mode 100644 index 3239e3f..0000000 --- a/arch/cris/include/asm/shmbuf.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _CRIS_SHMBUF_H -#define _CRIS_SHMBUF_H - -/* - * The shmid64_ds structure for CRIS architecture (same as for i386) - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct shmid64_ds { - struct ipc64_perm shm_perm; /* operation perms */ - size_t shm_segsz; /* size of segment (bytes) */ - __kernel_time_t shm_atime; /* last attach time */ - unsigned long __unused1; - __kernel_time_t shm_dtime; /* last detach time */ - unsigned long __unused2; - __kernel_time_t shm_ctime; /* last change time */ - unsigned long __unused3; - __kernel_pid_t shm_cpid; /* pid of creator */ - __kernel_pid_t shm_lpid; /* pid of last operator */ - unsigned long shm_nattch; /* no. of current attaches */ - unsigned long __unused4; - unsigned long __unused5; -}; - -struct shminfo64 { - unsigned long shmmax; - unsigned long shmmin; - unsigned long shmmni; - unsigned long shmseg; - unsigned long shmall; - unsigned long __unused1; - unsigned long __unused2; - unsigned long __unused3; - unsigned long __unused4; -}; - -#endif /* _CRIS_SHMBUF_H */ diff --git a/arch/cris/include/asm/sigcontext.h b/arch/cris/include/asm/sigcontext.h deleted file mode 100644 index a1d634e..0000000 --- a/arch/cris/include/asm/sigcontext.h +++ /dev/null @@ -1,24 +0,0 @@ -/* $Id: sigcontext.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ - -#ifndef _ASM_CRIS_SIGCONTEXT_H -#define _ASM_CRIS_SIGCONTEXT_H - -#include - -/* This struct is saved by setup_frame in signal.c, to keep the current context while - a signal handler is executed. It's restored by sys_sigreturn. - - To keep things simple, we use pt_regs here even though normally you just specify - the list of regs to save. Then we can use copy_from_user on the entire regs instead - of a bunch of get_user's as well... - -*/ - -struct sigcontext { - struct pt_regs regs; /* needs to be first */ - unsigned long oldmask; - unsigned long usp; /* usp before stacking this gunk on it */ -}; - -#endif - diff --git a/arch/cris/include/asm/siginfo.h b/arch/cris/include/asm/siginfo.h deleted file mode 100644 index c1cd6d1..0000000 --- a/arch/cris/include/asm/siginfo.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRIS_SIGINFO_H -#define _CRIS_SIGINFO_H - -#include - -#endif diff --git a/arch/cris/include/asm/signal.h b/arch/cris/include/asm/signal.h index ea6af9a..b3c5ef0 100644 --- a/arch/cris/include/asm/signal.h +++ b/arch/cris/include/asm/signal.h @@ -1,12 +1,8 @@ #ifndef _ASM_CRIS_SIGNAL_H #define _ASM_CRIS_SIGNAL_H -#include +#include -/* Avoid too many header ordering problems. */ -struct siginfo; - -#ifdef __KERNEL__ /* Most things should be clean enough to redefine this at will, if care is taken to make libc match. */ @@ -20,95 +16,6 @@ typedef struct { unsigned long sig[_NSIG_WORDS]; } sigset_t; -#else -/* Here we must cater to libcs that poke about in kernel headers. */ - -#define NSIG 32 -typedef unsigned long sigset_t; - -#endif /* __KERNEL__ */ - -#define SIGHUP 1 -#define SIGINT 2 -#define SIGQUIT 3 -#define SIGILL 4 -#define SIGTRAP 5 -#define SIGABRT 6 -#define SIGIOT 6 -#define SIGBUS 7 -#define SIGFPE 8 -#define SIGKILL 9 -#define SIGUSR1 10 -#define SIGSEGV 11 -#define SIGUSR2 12 -#define SIGPIPE 13 -#define SIGALRM 14 -#define SIGTERM 15 -#define SIGSTKFLT 16 -#define SIGCHLD 17 -#define SIGCONT 18 -#define SIGSTOP 19 -#define SIGTSTP 20 -#define SIGTTIN 21 -#define SIGTTOU 22 -#define SIGURG 23 -#define SIGXCPU 24 -#define SIGXFSZ 25 -#define SIGVTALRM 26 -#define SIGPROF 27 -#define SIGWINCH 28 -#define SIGIO 29 -#define SIGPOLL SIGIO -/* -#define SIGLOST 29 -*/ -#define SIGPWR 30 -#define SIGSYS 31 -#define SIGUNUSED 31 - -/* These should not be considered constants from userland. */ -#define SIGRTMIN 32 -#define SIGRTMAX _NSIG - -/* - * SA_FLAGS values: - * - * SA_ONSTACK indicates that a registered stack_t will be used. - * SA_RESTART flag to get restarting signals (which were the default long ago) - * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. - * SA_RESETHAND clears the handler when the signal is delivered. - * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. - * SA_NODEFER prevents the current signal from being masked in the handler. - * - * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single - * Unix names RESETHAND and NODEFER respectively. - */ - -#define SA_NOCLDSTOP 0x00000001u -#define SA_NOCLDWAIT 0x00000002u -#define SA_SIGINFO 0x00000004u -#define SA_ONSTACK 0x08000000u -#define SA_RESTART 0x10000000u -#define SA_NODEFER 0x40000000u -#define SA_RESETHAND 0x80000000u - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND - -#define SA_RESTORER 0x04000000 - -/* - * sigaltstack controls - */ -#define SS_ONSTACK 1 -#define SS_DISABLE 2 - -#define MINSIGSTKSZ 2048 -#define SIGSTKSZ 8192 - -#include - -#ifdef __KERNEL__ struct old_sigaction { __sighandler_t sa_handler; old_sigset_t sa_mask; @@ -126,31 +33,6 @@ struct sigaction { struct k_sigaction { struct sigaction sa; }; -#else -/* Here we must cater to libcs that poke about in kernel headers. */ - -struct sigaction { - union { - __sighandler_t _sa_handler; - void (*_sa_sigaction)(int, struct siginfo *, void *); - } _u; - sigset_t sa_mask; - unsigned long sa_flags; - void (*sa_restorer)(void); -}; - -#define sa_handler _u._sa_handler -#define sa_sigaction _u._sa_sigaction - -#endif /* __KERNEL__ */ - -typedef struct sigaltstack { - void *ss_sp; - int ss_flags; - size_t ss_size; -} stack_t; - -#ifdef __KERNEL__ #include /* here we could define asm-optimized sigaddset, sigdelset etc. operations. @@ -158,6 +40,4 @@ typedef struct sigaltstack { */ #define ptrace_signal_deliver(regs, cookie) do { } while (0) -#endif /* __KERNEL__ */ - #endif diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h deleted file mode 100644 index ae52825..0000000 --- a/arch/cris/include/asm/socket.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef _ASM_SOCKET_H -#define _ASM_SOCKET_H - -/* almost the same as asm-i386/socket.h */ - -#include - -/* For setsockoptions(2) */ -#define SOL_SOCKET 1 - -#define SO_DEBUG 1 -#define SO_REUSEADDR 2 -#define SO_TYPE 3 -#define SO_ERROR 4 -#define SO_DONTROUTE 5 -#define SO_BROADCAST 6 -#define SO_SNDBUF 7 -#define SO_RCVBUF 8 -#define SO_SNDBUFFORCE 32 -#define SO_RCVBUFFORCE 33 -#define SO_KEEPALIVE 9 -#define SO_OOBINLINE 10 -#define SO_NO_CHECK 11 -#define SO_PRIORITY 12 -#define SO_LINGER 13 -#define SO_BSDCOMPAT 14 -/* To add :#define SO_REUSEPORT 15 */ -#define SO_PASSCRED 16 -#define SO_PEERCRED 17 -#define SO_RCVLOWAT 18 -#define SO_SNDLOWAT 19 -#define SO_RCVTIMEO 20 -#define SO_SNDTIMEO 21 - -/* Security levels - as per NRL IPv6 - don't actually do anything */ -#define SO_SECURITY_AUTHENTICATION 22 -#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 -#define SO_SECURITY_ENCRYPTION_NETWORK 24 - -#define SO_BINDTODEVICE 25 - -/* Socket filtering */ -#define SO_ATTACH_FILTER 26 -#define SO_DETACH_FILTER 27 - -#define SO_PEERNAME 28 -#define SO_TIMESTAMP 29 -#define SCM_TIMESTAMP SO_TIMESTAMP - -#define SO_ACCEPTCONN 30 - -#define SO_PEERSEC 31 -#define SO_PASSSEC 34 -#define SO_TIMESTAMPNS 35 -#define SCM_TIMESTAMPNS SO_TIMESTAMPNS - -#define SO_MARK 36 - -#define SO_TIMESTAMPING 37 -#define SCM_TIMESTAMPING SO_TIMESTAMPING - -#define SO_PROTOCOL 38 -#define SO_DOMAIN 39 - -#define SO_RXQ_OVFL 40 - -#define SO_WIFI_STATUS 41 -#define SCM_WIFI_STATUS SO_WIFI_STATUS -#define SO_PEEK_OFF 42 - -/* Instruct lower device to use last 4-bytes of skb data as FCS */ -#define SO_NOFCS 43 - -#endif /* _ASM_SOCKET_H */ - - diff --git a/arch/cris/include/asm/sockios.h b/arch/cris/include/asm/sockios.h deleted file mode 100644 index cfe7bfe..0000000 --- a/arch/cris/include/asm/sockios.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __ARCH_CRIS_SOCKIOS__ -#define __ARCH_CRIS_SOCKIOS__ - -/* Socket-level I/O control calls. */ -#define FIOSETOWN 0x8901 -#define SIOCSPGRP 0x8902 -#define FIOGETOWN 0x8903 -#define SIOCGPGRP 0x8904 -#define SIOCATMARK 0x8905 -#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ -#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ - -#endif diff --git a/arch/cris/include/asm/stat.h b/arch/cris/include/asm/stat.h deleted file mode 100644 index 9e558cc..0000000 --- a/arch/cris/include/asm/stat.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef _CRIS_STAT_H -#define _CRIS_STAT_H - -/* Keep this a verbatim copy of i386 version; tweak CRIS-specific bits in - the kernel if necessary. */ - -struct __old_kernel_stat { - unsigned short st_dev; - unsigned short st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - unsigned short st_rdev; - unsigned long st_size; - unsigned long st_atime; - unsigned long st_mtime; - unsigned long st_ctime; -}; - -#define STAT_HAVE_NSEC 1 - -struct stat { - unsigned long st_dev; - unsigned long st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - unsigned long st_rdev; - unsigned long st_size; - unsigned long st_blksize; - unsigned long st_blocks; - unsigned long st_atime; - unsigned long st_atime_nsec; - unsigned long st_mtime; - unsigned long st_mtime_nsec; - unsigned long st_ctime; - unsigned long st_ctime_nsec; - unsigned long __unused4; - unsigned long __unused5; -}; - -/* This matches struct stat64 in glibc2.1, hence the absolutely - * insane amounts of padding around dev_t's. - */ -struct stat64 { - unsigned long long st_dev; - unsigned char __pad0[4]; - -#define STAT64_HAS_BROKEN_ST_INO 1 - unsigned long __st_ino; - - unsigned int st_mode; - unsigned int st_nlink; - - unsigned long st_uid; - unsigned long st_gid; - - unsigned long long st_rdev; - unsigned char __pad3[4]; - - long long st_size; - unsigned long st_blksize; - - unsigned long st_blocks; /* Number 512-byte blocks allocated. */ - unsigned long __pad4; /* future possible st_blocks high bits */ - - unsigned long st_atime; - unsigned long st_atime_nsec; - - unsigned long st_mtime; - unsigned long st_mtime_nsec; - - unsigned long st_ctime; - unsigned long st_ctime_nsec; /* will be high 32 bits of ctime someday */ - - unsigned long long st_ino; -}; - -#endif diff --git a/arch/cris/include/asm/statfs.h b/arch/cris/include/asm/statfs.h deleted file mode 100644 index fdaf921..0000000 --- a/arch/cris/include/asm/statfs.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRIS_STATFS_H -#define _CRIS_STATFS_H - -#include - -#endif diff --git a/arch/cris/include/asm/swab.h b/arch/cris/include/asm/swab.h index 80668e8..991b6ac 100644 --- a/arch/cris/include/asm/swab.h +++ b/arch/cris/include/asm/swab.h @@ -1,8 +1,7 @@ #ifndef _CRIS_SWAB_H #define _CRIS_SWAB_H -#ifdef __KERNEL__ #include -#endif /* __KERNEL__ */ +#include #endif /* _CRIS_SWAB_H */ diff --git a/arch/cris/include/asm/sync_serial.h b/arch/cris/include/asm/sync_serial.h deleted file mode 100644 index 7f827fe..0000000 --- a/arch/cris/include/asm/sync_serial.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * ioctl defines for synchronous serial port driver - * - * Copyright (c) 2001-2003 Axis Communications AB - * - * Author: Mikael Starvik - * - */ - -#ifndef SYNC_SERIAL_H -#define SYNC_SERIAL_H - -#include - -#define SSP_SPEED _IOR('S', 0, unsigned int) -#define SSP_MODE _IOR('S', 1, unsigned int) -#define SSP_FRAME_SYNC _IOR('S', 2, unsigned int) -#define SSP_IPOLARITY _IOR('S', 3, unsigned int) -#define SSP_OPOLARITY _IOR('S', 4, unsigned int) -#define SSP_SPI _IOR('S', 5, unsigned int) -#define SSP_INBUFCHUNK _IOR('S', 6, unsigned int) -#define SSP_INPUT _IOR('S', 7, unsigned int) - -/* Values for SSP_SPEED */ -#define SSP150 0 -#define SSP300 1 -#define SSP600 2 -#define SSP1200 3 -#define SSP2400 4 -#define SSP4800 5 -#define SSP9600 6 -#define SSP19200 7 -#define SSP28800 8 -#define SSP57600 9 -#define SSP115200 10 -#define SSP230400 11 -#define SSP460800 12 -#define SSP921600 13 -#define SSP3125000 14 -#define CODEC 15 -#define CODEC_f32768 16 - -#define FREQ_4MHz 0 -#define FREQ_2MHz 1 -#define FREQ_1MHz 2 -#define FREQ_512kHz 3 -#define FREQ_256kHz 4 -#define FREQ_128kHz 5 -#define FREQ_64kHz 6 -#define FREQ_32kHz 7 -/* FREQ_* with values where bit (value & 0x10) is set are */ -/* used for CODEC_f32768 */ -#define FREQ_4096kHz 16 /* CODEC_f32768 */ - -/* Used by application to set CODEC divider, word rate and frame rate */ -#define CODEC_VAL(freq, clk_per_sync, sync_per_frame) \ - ((CODEC + ((freq & 0x10) >> 4)) | (freq << 8) | \ - (clk_per_sync << 16) | (sync_per_frame << 28)) - -/* Used by driver to extract speed */ -#define GET_SPEED(x) (x & 0xff) -#define GET_FREQ(x) ((x & 0xff00) >> 8) -#define GET_WORD_RATE(x) (((x & 0x0fff0000) >> 16) - 1) -#define GET_FRAME_RATE(x) (((x & 0xf0000000) >> 28) - 1) - -/* Values for SSP_MODE */ -#define MASTER_OUTPUT 0 -#define SLAVE_OUTPUT 1 -#define MASTER_INPUT 2 -#define SLAVE_INPUT 3 -#define MASTER_BIDIR 4 -#define SLAVE_BIDIR 5 - -/* Values for SSP_FRAME_SYNC */ -#define NORMAL_SYNC 1 -#define EARLY_SYNC 2 -#define SECOND_WORD_SYNC 0x40000 -#define LATE_SYNC 0x80000 - -#define BIT_SYNC 4 -#define WORD_SYNC 8 -#define EXTENDED_SYNC 0x10 - -#define SYNC_OFF 0x20 -#define SYNC_ON 0x40 -#define WORD_SIZE_8 0x80 -#define WORD_SIZE_12 0x100 -#define WORD_SIZE_16 0x200 -#define WORD_SIZE_24 0x400 -#define WORD_SIZE_32 0x800 -#define BIT_ORDER_LSB 0x1000 -#define BIT_ORDER_MSB 0x2000 -#define FLOW_CONTROL_ENABLE 0x4000 -#define FLOW_CONTROL_DISABLE 0x8000 -#define CLOCK_GATED 0x10000 -#define CLOCK_NOT_GATED 0x20000 - -/* Values for SSP_IPOLARITY and SSP_OPOLARITY */ -#define CLOCK_NORMAL 1 -#define CLOCK_INVERT 2 -#define CLOCK_INEGEDGE CLOCK_NORMAL -#define CLOCK_IPOSEDGE CLOCK_INVERT -#define FRAME_NORMAL 4 -#define FRAME_INVERT 8 -#define STATUS_NORMAL 0x10 -#define STATUS_INVERT 0x20 - -/* Values for SSP_SPI */ -#define SPI_MASTER 0 -#define SPI_SLAVE 1 - -/* Values for SSP_INBUFCHUNK */ -/* plain integer with the size of DMA chunks */ - -/* To ensure that the timestamps are aligned with the data being read - * the read length MUST be a multiple of the length of the DMA buffers. - * - * Use a multiple of SSP_INPUT_CHUNK_SIZE defined below. - */ -#define SSP_INPUT_CHUNK_SIZE 256 - -/* Request struct to pass through the ioctl interface to read - * data with timestamps. - */ -struct ssp_request { - char __user *buf; /* Where to put the data. */ - size_t len; /* Size of buf. MUST be a multiple of */ - /* SSP_INPUT_CHUNK_SIZE! */ - struct timespec ts; /* The time the data was sampled. */ -}; - -#endif diff --git a/arch/cris/include/asm/termbits.h b/arch/cris/include/asm/termbits.h deleted file mode 100644 index 1c43bc8..0000000 --- a/arch/cris/include/asm/termbits.h +++ /dev/null @@ -1,235 +0,0 @@ -/* $Id: termbits.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ - -#ifndef __ARCH_ETRAX100_TERMBITS_H__ -#define __ARCH_ETRAX100_TERMBITS_H__ - -#include - -typedef unsigned char cc_t; -typedef unsigned int speed_t; -typedef unsigned int tcflag_t; - -#define NCCS 19 -struct termios { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ - cc_t c_cc[NCCS]; /* control characters */ -}; - -struct termios2 { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ - cc_t c_cc[NCCS]; /* control characters */ - speed_t c_ispeed; /* input speed */ - speed_t c_ospeed; /* output speed */ -}; - -struct ktermios { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ - cc_t c_cc[NCCS]; /* control characters */ - speed_t c_ispeed; /* input speed */ - speed_t c_ospeed; /* output speed */ -}; - -/* c_cc characters */ -#define VINTR 0 -#define VQUIT 1 -#define VERASE 2 -#define VKILL 3 -#define VEOF 4 -#define VTIME 5 -#define VMIN 6 -#define VSWTC 7 -#define VSTART 8 -#define VSTOP 9 -#define VSUSP 10 -#define VEOL 11 -#define VREPRINT 12 -#define VDISCARD 13 -#define VWERASE 14 -#define VLNEXT 15 -#define VEOL2 16 - -/* c_iflag bits */ -#define IGNBRK 0000001 -#define BRKINT 0000002 -#define IGNPAR 0000004 -#define PARMRK 0000010 -#define INPCK 0000020 -#define ISTRIP 0000040 -#define INLCR 0000100 -#define IGNCR 0000200 -#define ICRNL 0000400 -#define IUCLC 0001000 -#define IXON 0002000 -#define IXANY 0004000 -#define IXOFF 0010000 -#define IMAXBEL 0020000 -#define IUTF8 0040000 - -/* c_oflag bits */ -#define OPOST 0000001 -#define OLCUC 0000002 -#define ONLCR 0000004 -#define OCRNL 0000010 -#define ONOCR 0000020 -#define ONLRET 0000040 -#define OFILL 0000100 -#define OFDEL 0000200 -#define NLDLY 0000400 -#define NL0 0000000 -#define NL1 0000400 -#define CRDLY 0003000 -#define CR0 0000000 -#define CR1 0001000 -#define CR2 0002000 -#define CR3 0003000 -#define TABDLY 0014000 -#define TAB0 0000000 -#define TAB1 0004000 -#define TAB2 0010000 -#define TAB3 0014000 -#define XTABS 0014000 -#define BSDLY 0020000 -#define BS0 0000000 -#define BS1 0020000 -#define VTDLY 0040000 -#define VT0 0000000 -#define VT1 0040000 -#define FFDLY 0100000 -#define FF0 0000000 -#define FF1 0100000 - -/* c_cflag bit meaning */ -/* - * 3 2 1 - * 10 987 654 321 098 765 432 109 876 543 210 - * | | ||| CBAUD - * obaud - * - * ||CSIZE - * - * |CSTOP - * |CREAD - * |CPARENB - * - * |CPARODD - * |HUPCL - * |CLOCAL - * |CBAUDEX - * 10 987 654 321 098 765 432 109 876 543 210 - * | || || CIBAUD, IBSHIFT=16 - * ibaud - * |CMSPAR - * | CRTSCTS - * x x xxx xxx x x xx Free bits - */ - -#define CBAUD 0010017 -#define B0 0000000 /* hang up */ -#define B50 0000001 -#define B75 0000002 -#define B110 0000003 -#define B134 0000004 -#define B150 0000005 -#define B200 0000006 -#define B300 0000007 -#define B600 0000010 -#define B1200 0000011 -#define B1800 0000012 -#define B2400 0000013 -#define B4800 0000014 -#define B9600 0000015 -#define B19200 0000016 -#define B38400 0000017 -#define EXTA B19200 -#define EXTB B38400 -#define CSIZE 0000060 -#define CS5 0000000 -#define CS6 0000020 -#define CS7 0000040 -#define CS8 0000060 -#define CSTOPB 0000100 -#define CREAD 0000200 -#define PARENB 0000400 -#define PARODD 0001000 -#define HUPCL 0002000 -#define CLOCAL 0004000 -#define CBAUDEX 0010000 -#define BOTHER 0010000 -#define B57600 0010001 -#define B115200 0010002 -#define B230400 0010003 -#define B460800 0010004 - -/* Unsupported rates, but needed to avoid compile error. */ -#define B500000 0010005 -#define B576000 0010006 -#define B1000000 0010010 -#define B1152000 0010011 -#define B1500000 0010012 -#define B2000000 0010013 -#define B2500000 0010014 -#define B3000000 0010015 -#define B3500000 0010016 -#define B4000000 0010017 - -/* etrax supports these additional three baud rates */ -#define B921600 0010005 -#define B1843200 0010006 -#define B6250000 0010007 -/* ETRAX FS supports this as well */ -#define B12500000 0010010 -#define CIBAUD 002003600000 /* input baud rate (used in v32) */ -/* The values for CIBAUD bits are the same as the values for CBAUD and CBAUDEX - * shifted left IBSHIFT bits. - */ -#define IBSHIFT 16 -#define CMSPAR 010000000000 /* mark or space (stick) parity - PARODD=space*/ -#define CRTSCTS 020000000000 /* flow control */ - -/* c_lflag bits */ -#define ISIG 0000001 -#define ICANON 0000002 -#define XCASE 0000004 -#define ECHO 0000010 -#define ECHOE 0000020 -#define ECHOK 0000040 -#define ECHONL 0000100 -#define NOFLSH 0000200 -#define TOSTOP 0000400 -#define ECHOCTL 0001000 -#define ECHOPRT 0002000 -#define ECHOKE 0004000 -#define FLUSHO 0010000 -#define PENDIN 0040000 -#define IEXTEN 0100000 -#define EXTPROC 0200000 - -/* tcflow() and TCXONC use these */ -#define TCOOFF 0 -#define TCOON 1 -#define TCIOFF 2 -#define TCION 3 - -/* tcflush() and TCFLSH use these */ -#define TCIFLUSH 0 -#define TCOFLUSH 1 -#define TCIOFLUSH 2 - -/* tcsetattr uses these */ -#define TCSANOW 0 -#define TCSADRAIN 1 -#define TCSAFLUSH 2 - -#endif diff --git a/arch/cris/include/asm/termios.h b/arch/cris/include/asm/termios.h index 1265109..1991cd9e 100644 --- a/arch/cris/include/asm/termios.h +++ b/arch/cris/include/asm/termios.h @@ -1,47 +1,8 @@ #ifndef _CRIS_TERMIOS_H #define _CRIS_TERMIOS_H -#include -#include -#include -#include +#include -struct winsize { - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; - unsigned short ws_ypixel; -}; - -#define NCC 8 -struct termio { - unsigned short c_iflag; /* input mode flags */ - unsigned short c_oflag; /* output mode flags */ - unsigned short c_cflag; /* control mode flags */ - unsigned short c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[NCC]; /* control characters */ -}; - -/* modem lines */ -#define TIOCM_LE 0x001 -#define TIOCM_DTR 0x002 -#define TIOCM_RTS 0x004 -#define TIOCM_ST 0x008 -#define TIOCM_SR 0x010 -#define TIOCM_CTS 0x020 -#define TIOCM_CAR 0x040 -#define TIOCM_RNG 0x080 -#define TIOCM_DSR 0x100 -#define TIOCM_CD TIOCM_CAR -#define TIOCM_RI TIOCM_RNG -#define TIOCM_OUT1 0x2000 -#define TIOCM_OUT2 0x4000 -#define TIOCM_LOOP 0x8000 - -/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ - -#ifdef __KERNEL__ /* intr=^C quit=^\ erase=del kill=^U eof=^D vtime=\0 vmin=\1 sxtc=\0 @@ -87,6 +48,4 @@ struct termio { #define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) #define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) -#endif /* __KERNEL__ */ - #endif /* _CRIS_TERMIOS_H */ diff --git a/arch/cris/include/asm/types.h b/arch/cris/include/asm/types.h index adaf827..a3cac77 100644 --- a/arch/cris/include/asm/types.h +++ b/arch/cris/include/asm/types.h @@ -1,15 +1,12 @@ #ifndef _ETRAX_TYPES_H #define _ETRAX_TYPES_H -#include +#include /* * These aren't exported outside the kernel to avoid name space clashes */ -#ifdef __KERNEL__ #define BITS_PER_LONG 32 -#endif /* __KERNEL__ */ - #endif diff --git a/arch/cris/include/asm/unistd.h b/arch/cris/include/asm/unistd.h index 51873a4..4fb59e1 100644 --- a/arch/cris/include/asm/unistd.h +++ b/arch/cris/include/asm/unistd.h @@ -1,347 +1,8 @@ #ifndef _ASM_CRIS_UNISTD_H_ #define _ASM_CRIS_UNISTD_H_ -/* - * This file contains the system call numbers, and stub macros for libc. - */ - -#define __NR_restart_syscall 0 -#define __NR_exit 1 -#define __NR_fork 2 -#define __NR_read 3 -#define __NR_write 4 -#define __NR_open 5 -#define __NR_close 6 -#define __NR_waitpid 7 -#define __NR_creat 8 -#define __NR_link 9 -#define __NR_unlink 10 -#define __NR_execve 11 -#define __NR_chdir 12 -#define __NR_time 13 -#define __NR_mknod 14 -#define __NR_chmod 15 -#define __NR_lchown 16 -#define __NR_break 17 -#define __NR_oldstat 18 -#define __NR_lseek 19 -#define __NR_getpid 20 -#define __NR_mount 21 -#define __NR_umount 22 -#define __NR_setuid 23 -#define __NR_getuid 24 -#define __NR_stime 25 -#define __NR_ptrace 26 -#define __NR_alarm 27 -#define __NR_oldfstat 28 -#define __NR_pause 29 -#define __NR_utime 30 -#define __NR_stty 31 -#define __NR_gtty 32 -#define __NR_access 33 -#define __NR_nice 34 -#define __NR_ftime 35 -#define __NR_sync 36 -#define __NR_kill 37 -#define __NR_rename 38 -#define __NR_mkdir 39 -#define __NR_rmdir 40 -#define __NR_dup 41 -#define __NR_pipe 42 -#define __NR_times 43 -#define __NR_prof 44 -#define __NR_brk 45 -#define __NR_setgid 46 -#define __NR_getgid 47 -#define __NR_signal 48 -#define __NR_geteuid 49 -#define __NR_getegid 50 -#define __NR_acct 51 -#define __NR_umount2 52 -#define __NR_lock 53 -#define __NR_ioctl 54 -#define __NR_fcntl 55 -#define __NR_mpx 56 -#define __NR_setpgid 57 -#define __NR_ulimit 58 -#define __NR_oldolduname 59 -#define __NR_umask 60 -#define __NR_chroot 61 -#define __NR_ustat 62 -#define __NR_dup2 63 -#define __NR_getppid 64 -#define __NR_getpgrp 65 -#define __NR_setsid 66 -#define __NR_sigaction 67 -#define __NR_sgetmask 68 -#define __NR_ssetmask 69 -#define __NR_setreuid 70 -#define __NR_setregid 71 -#define __NR_sigsuspend 72 -#define __NR_sigpending 73 -#define __NR_sethostname 74 -#define __NR_setrlimit 75 -#define __NR_getrlimit 76 -#define __NR_getrusage 77 -#define __NR_gettimeofday 78 -#define __NR_settimeofday 79 -#define __NR_getgroups 80 -#define __NR_setgroups 81 -#define __NR_select 82 -#define __NR_symlink 83 -#define __NR_oldlstat 84 -#define __NR_readlink 85 -#define __NR_uselib 86 -#define __NR_swapon 87 -#define __NR_reboot 88 -#define __NR_readdir 89 -#define __NR_mmap 90 -#define __NR_munmap 91 -#define __NR_truncate 92 -#define __NR_ftruncate 93 -#define __NR_fchmod 94 -#define __NR_fchown 95 -#define __NR_getpriority 96 -#define __NR_setpriority 97 -#define __NR_profil 98 -#define __NR_statfs 99 -#define __NR_fstatfs 100 -#define __NR_ioperm 101 -#define __NR_socketcall 102 -#define __NR_syslog 103 -#define __NR_setitimer 104 -#define __NR_getitimer 105 -#define __NR_stat 106 -#define __NR_lstat 107 -#define __NR_fstat 108 -#define __NR_olduname 109 -#define __NR_iopl 110 -#define __NR_vhangup 111 -#define __NR_idle 112 -#define __NR_vm86 113 -#define __NR_wait4 114 -#define __NR_swapoff 115 -#define __NR_sysinfo 116 -#define __NR_ipc 117 -#define __NR_fsync 118 -#define __NR_sigreturn 119 -#define __NR_clone 120 -#define __NR_setdomainname 121 -#define __NR_uname 122 -#define __NR_modify_ldt 123 -#define __NR_adjtimex 124 -#define __NR_mprotect 125 -#define __NR_sigprocmask 126 -#define __NR_create_module 127 -#define __NR_init_module 128 -#define __NR_delete_module 129 -#define __NR_get_kernel_syms 130 -#define __NR_quotactl 131 -#define __NR_getpgid 132 -#define __NR_fchdir 133 -#define __NR_bdflush 134 -#define __NR_sysfs 135 -#define __NR_personality 136 -#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ -#define __NR_setfsuid 138 -#define __NR_setfsgid 139 -#define __NR__llseek 140 -#define __NR_getdents 141 -#define __NR__newselect 142 -#define __NR_flock 143 -#define __NR_msync 144 -#define __NR_readv 145 -#define __NR_writev 146 -#define __NR_getsid 147 -#define __NR_fdatasync 148 -#define __NR__sysctl 149 -#define __NR_mlock 150 -#define __NR_munlock 151 -#define __NR_mlockall 152 -#define __NR_munlockall 153 -#define __NR_sched_setparam 154 -#define __NR_sched_getparam 155 -#define __NR_sched_setscheduler 156 -#define __NR_sched_getscheduler 157 -#define __NR_sched_yield 158 -#define __NR_sched_get_priority_max 159 -#define __NR_sched_get_priority_min 160 -#define __NR_sched_rr_get_interval 161 -#define __NR_nanosleep 162 -#define __NR_mremap 163 -#define __NR_setresuid 164 -#define __NR_getresuid 165 - -#define __NR_query_module 167 -#define __NR_poll 168 -#define __NR_nfsservctl 169 -#define __NR_setresgid 170 -#define __NR_getresgid 171 -#define __NR_prctl 172 -#define __NR_rt_sigreturn 173 -#define __NR_rt_sigaction 174 -#define __NR_rt_sigprocmask 175 -#define __NR_rt_sigpending 176 -#define __NR_rt_sigtimedwait 177 -#define __NR_rt_sigqueueinfo 178 -#define __NR_rt_sigsuspend 179 -#define __NR_pread64 180 -#define __NR_pwrite64 181 -#define __NR_chown 182 -#define __NR_getcwd 183 -#define __NR_capget 184 -#define __NR_capset 185 -#define __NR_sigaltstack 186 -#define __NR_sendfile 187 -#define __NR_getpmsg 188 /* some people actually want streams */ -#define __NR_putpmsg 189 /* some people actually want streams */ -#define __NR_vfork 190 -#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */ -#define __NR_mmap2 192 -#define __NR_truncate64 193 -#define __NR_ftruncate64 194 -#define __NR_stat64 195 -#define __NR_lstat64 196 -#define __NR_fstat64 197 -#define __NR_lchown32 198 -#define __NR_getuid32 199 -#define __NR_getgid32 200 -#define __NR_geteuid32 201 -#define __NR_getegid32 202 -#define __NR_setreuid32 203 -#define __NR_setregid32 204 -#define __NR_getgroups32 205 -#define __NR_setgroups32 206 -#define __NR_fchown32 207 -#define __NR_setresuid32 208 -#define __NR_getresuid32 209 -#define __NR_setresgid32 210 -#define __NR_getresgid32 211 -#define __NR_chown32 212 -#define __NR_setuid32 213 -#define __NR_setgid32 214 -#define __NR_setfsuid32 215 -#define __NR_setfsgid32 216 -#define __NR_pivot_root 217 -#define __NR_mincore 218 -#define __NR_madvise 219 -#define __NR_getdents64 220 -#define __NR_fcntl64 221 -/* 223 is unused */ -#define __NR_gettid 224 -#define __NR_readahead 225 -#define __NR_setxattr 226 -#define __NR_lsetxattr 227 -#define __NR_fsetxattr 228 -#define __NR_getxattr 229 -#define __NR_lgetxattr 230 -#define __NR_fgetxattr 231 -#define __NR_listxattr 232 -#define __NR_llistxattr 233 -#define __NR_flistxattr 234 -#define __NR_removexattr 235 -#define __NR_lremovexattr 236 -#define __NR_fremovexattr 237 -#define __NR_tkill 238 -#define __NR_sendfile64 239 -#define __NR_futex 240 -#define __NR_sched_setaffinity 241 -#define __NR_sched_getaffinity 242 -#define __NR_set_thread_area 243 -#define __NR_get_thread_area 244 -#define __NR_io_setup 245 -#define __NR_io_destroy 246 -#define __NR_io_getevents 247 -#define __NR_io_submit 248 -#define __NR_io_cancel 249 -#define __NR_fadvise64 250 -/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */ -#define __NR_exit_group 252 -#define __NR_lookup_dcookie 253 -#define __NR_epoll_create 254 -#define __NR_epoll_ctl 255 -#define __NR_epoll_wait 256 -#define __NR_remap_file_pages 257 -#define __NR_set_tid_address 258 -#define __NR_timer_create 259 -#define __NR_timer_settime (__NR_timer_create+1) -#define __NR_timer_gettime (__NR_timer_create+2) -#define __NR_timer_getoverrun (__NR_timer_create+3) -#define __NR_timer_delete (__NR_timer_create+4) -#define __NR_clock_settime (__NR_timer_create+5) -#define __NR_clock_gettime (__NR_timer_create+6) -#define __NR_clock_getres (__NR_timer_create+7) -#define __NR_clock_nanosleep (__NR_timer_create+8) -#define __NR_statfs64 268 -#define __NR_fstatfs64 269 -#define __NR_tgkill 270 -#define __NR_utimes 271 -#define __NR_fadvise64_64 272 -#define __NR_vserver 273 -#define __NR_mbind 274 -#define __NR_get_mempolicy 275 -#define __NR_set_mempolicy 276 -#define __NR_mq_open 277 -#define __NR_mq_unlink (__NR_mq_open+1) -#define __NR_mq_timedsend (__NR_mq_open+2) -#define __NR_mq_timedreceive (__NR_mq_open+3) -#define __NR_mq_notify (__NR_mq_open+4) -#define __NR_mq_getsetattr (__NR_mq_open+5) -#define __NR_kexec_load 283 -#define __NR_waitid 284 -/* #define __NR_sys_setaltroot 285 */ -#define __NR_add_key 286 -#define __NR_request_key 287 -#define __NR_keyctl 288 -#define __NR_ioprio_set 289 -#define __NR_ioprio_get 290 -#define __NR_inotify_init 291 -#define __NR_inotify_add_watch 292 -#define __NR_inotify_rm_watch 293 -#define __NR_migrate_pages 294 -#define __NR_openat 295 -#define __NR_mkdirat 296 -#define __NR_mknodat 297 -#define __NR_fchownat 298 -#define __NR_futimesat 299 -#define __NR_fstatat64 300 -#define __NR_unlinkat 301 -#define __NR_renameat 302 -#define __NR_linkat 303 -#define __NR_symlinkat 304 -#define __NR_readlinkat 305 -#define __NR_fchmodat 306 -#define __NR_faccessat 307 -#define __NR_pselect6 308 -#define __NR_ppoll 309 -#define __NR_unshare 310 -#define __NR_set_robust_list 311 -#define __NR_get_robust_list 312 -#define __NR_splice 313 -#define __NR_sync_file_range 314 -#define __NR_tee 315 -#define __NR_vmsplice 316 -#define __NR_move_pages 317 -#define __NR_getcpu 318 -#define __NR_epoll_pwait 319 -#define __NR_utimensat 320 -#define __NR_signalfd 321 -#define __NR_timerfd_create 322 -#define __NR_eventfd 323 -#define __NR_fallocate 324 -#define __NR_timerfd_settime 325 -#define __NR_timerfd_gettime 326 -#define __NR_signalfd4 327 -#define __NR_eventfd2 328 -#define __NR_epoll_create1 329 -#define __NR_dup3 330 -#define __NR_pipe2 331 -#define __NR_inotify_init1 332 -#define __NR_preadv 333 -#define __NR_pwritev 334 -#define __NR_setns 335 +#include -#ifdef __KERNEL__ #define NR_syscalls 336 @@ -380,5 +41,4 @@ */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") -#endif /* __KERNEL__ */ #endif /* _ASM_CRIS_UNISTD_H_ */ diff --git a/arch/cris/include/uapi/asm/Kbuild b/arch/cris/include/uapi/asm/Kbuild index f50236a..7d47b36 100644 --- a/arch/cris/include/uapi/asm/Kbuild +++ b/arch/cris/include/uapi/asm/Kbuild @@ -3,3 +3,37 @@ include include/uapi/asm-generic/Kbuild.asm header-y += arch-v10/ header-y += arch-v32/ +header-y += auxvec.h +header-y += bitsperlong.h +header-y += byteorder.h +header-y += errno.h +header-y += ethernet.h +header-y += etraxgpio.h +header-y += fcntl.h +header-y += ioctl.h +header-y += ioctls.h +header-y += ipcbuf.h +header-y += mman.h +header-y += msgbuf.h +header-y += param.h +header-y += poll.h +header-y += posix_types.h +header-y += ptrace.h +header-y += resource.h +header-y += rs485.h +header-y += sembuf.h +header-y += setup.h +header-y += shmbuf.h +header-y += sigcontext.h +header-y += siginfo.h +header-y += signal.h +header-y += socket.h +header-y += sockios.h +header-y += stat.h +header-y += statfs.h +header-y += swab.h +header-y += sync_serial.h +header-y += termbits.h +header-y += termios.h +header-y += types.h +header-y += unistd.h diff --git a/arch/cris/include/uapi/asm/auxvec.h b/arch/cris/include/uapi/asm/auxvec.h new file mode 100644 index 0000000..cb30b01 --- /dev/null +++ b/arch/cris/include/uapi/asm/auxvec.h @@ -0,0 +1,4 @@ +#ifndef __ASMCRIS_AUXVEC_H +#define __ASMCRIS_AUXVEC_H + +#endif diff --git a/arch/cris/include/uapi/asm/bitsperlong.h b/arch/cris/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..6dc0bb0 --- /dev/null +++ b/arch/cris/include/uapi/asm/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/arch/cris/include/uapi/asm/byteorder.h b/arch/cris/include/uapi/asm/byteorder.h new file mode 100644 index 0000000..bcd1897 --- /dev/null +++ b/arch/cris/include/uapi/asm/byteorder.h @@ -0,0 +1,8 @@ +#ifndef _CRIS_BYTEORDER_H +#define _CRIS_BYTEORDER_H + +#include + +#endif + + diff --git a/arch/cris/include/uapi/asm/errno.h b/arch/cris/include/uapi/asm/errno.h new file mode 100644 index 0000000..2bf5eb5 --- /dev/null +++ b/arch/cris/include/uapi/asm/errno.h @@ -0,0 +1,6 @@ +#ifndef _CRIS_ERRNO_H +#define _CRIS_ERRNO_H + +#include + +#endif diff --git a/arch/cris/include/uapi/asm/ethernet.h b/arch/cris/include/uapi/asm/ethernet.h new file mode 100644 index 0000000..4d58652 --- /dev/null +++ b/arch/cris/include/uapi/asm/ethernet.h @@ -0,0 +1,21 @@ +/* + * ioctl defines for ethernet driver + * + * Copyright (c) 2001 Axis Communications AB + * + * Author: Mikael Starvik + * + */ + +#ifndef _CRIS_ETHERNET_H +#define _CRIS_ETHERNET_H +#define SET_ETH_SPEED_AUTO SIOCDEVPRIVATE /* Auto neg speed */ +#define SET_ETH_SPEED_10 SIOCDEVPRIVATE+1 /* 10 Mbps */ +#define SET_ETH_SPEED_100 SIOCDEVPRIVATE+2 /* 100 Mbps. */ +#define SET_ETH_DUPLEX_AUTO SIOCDEVPRIVATE+3 /* Auto neg duplex */ +#define SET_ETH_DUPLEX_HALF SIOCDEVPRIVATE+4 /* Full duplex */ +#define SET_ETH_DUPLEX_FULL SIOCDEVPRIVATE+5 /* Half duplex */ +#define SET_ETH_ENABLE_LEDS SIOCDEVPRIVATE+6 /* Enable net LEDs */ +#define SET_ETH_DISABLE_LEDS SIOCDEVPRIVATE+7 /* Disable net LEDs */ +#define SET_ETH_AUTONEG SIOCDEVPRIVATE+8 +#endif /* _CRIS_ETHERNET_H */ diff --git a/arch/cris/include/uapi/asm/etraxgpio.h b/arch/cris/include/uapi/asm/etraxgpio.h new file mode 100644 index 0000000..461c089 --- /dev/null +++ b/arch/cris/include/uapi/asm/etraxgpio.h @@ -0,0 +1,239 @@ +/* + * The following devices are accessible using this driver using + * GPIO_MAJOR (120) and a couple of minor numbers. + * + * For ETRAX 100LX (CONFIG_ETRAX_ARCH_V10): + * /dev/gpioa minor 0, 8 bit GPIO, each bit can change direction + * /dev/gpiob minor 1, 8 bit GPIO, each bit can change direction + * /dev/leds minor 2, Access to leds depending on kernelconfig + * /dev/gpiog minor 3 + * g0dir, g8_15dir, g16_23dir, g24 dir configurable in R_GEN_CONFIG + * g1-g7 and g25-g31 is both input and outputs but on different pins + * Also note that some bits change pins depending on what interfaces + * are enabled. + * + * For ETRAX FS (CONFIG_ETRAXFS): + * /dev/gpioa minor 0, 8 bit GPIO, each bit can change direction + * /dev/gpiob minor 1, 18 bit GPIO, each bit can change direction + * /dev/gpioc minor 3, 18 bit GPIO, each bit can change direction + * /dev/gpiod minor 4, 18 bit GPIO, each bit can change direction + * /dev/gpioe minor 5, 18 bit GPIO, each bit can change direction + * /dev/leds minor 2, Access to leds depending on kernelconfig + * + * For ARTPEC-3 (CONFIG_CRIS_MACH_ARTPEC3): + * /dev/gpioa minor 0, 32 bit GPIO, each bit can change direction + * /dev/gpiob minor 1, 32 bit GPIO, each bit can change direction + * /dev/gpioc minor 3, 16 bit GPIO, each bit can change direction + * /dev/gpiod minor 4, 32 bit GPIO, input only + * /dev/leds minor 2, Access to leds depending on kernelconfig + * /dev/pwm0 minor 16, PWM channel 0 on PA30 + * /dev/pwm1 minor 17, PWM channel 1 on PA31 + * /dev/pwm2 minor 18, PWM channel 2 on PB26 + * /dev/ppwm minor 19, PPWM channel + * + */ +#ifndef _ASM_ETRAXGPIO_H +#define _ASM_ETRAXGPIO_H + +#define GPIO_MINOR_FIRST 0 + +#define ETRAXGPIO_IOCTYPE 43 + +/* etraxgpio _IOC_TYPE, bits 8 to 15 in ioctl cmd */ +#ifdef CONFIG_ETRAX_ARCH_V10 +#define GPIO_MINOR_A 0 +#define GPIO_MINOR_B 1 +#define GPIO_MINOR_LEDS 2 +#define GPIO_MINOR_G 3 +#define GPIO_MINOR_LAST 3 +#define GPIO_MINOR_LAST_REAL GPIO_MINOR_LAST +#endif + +#ifdef CONFIG_ETRAXFS +#define GPIO_MINOR_A 0 +#define GPIO_MINOR_B 1 +#define GPIO_MINOR_LEDS 2 +#define GPIO_MINOR_C 3 +#define GPIO_MINOR_D 4 +#define GPIO_MINOR_E 5 +#ifdef CONFIG_ETRAX_VIRTUAL_GPIO +#define GPIO_MINOR_V 6 +#define GPIO_MINOR_LAST 6 +#else +#define GPIO_MINOR_LAST 5 +#endif +#define GPIO_MINOR_LAST_REAL GPIO_MINOR_LAST +#endif + +#ifdef CONFIG_CRIS_MACH_ARTPEC3 +#define GPIO_MINOR_A 0 +#define GPIO_MINOR_B 1 +#define GPIO_MINOR_LEDS 2 +#define GPIO_MINOR_C 3 +#define GPIO_MINOR_D 4 +#ifdef CONFIG_ETRAX_VIRTUAL_GPIO +#define GPIO_MINOR_V 6 +#define GPIO_MINOR_LAST 6 +#else +#define GPIO_MINOR_LAST 4 +#endif +#define GPIO_MINOR_FIRST_PWM 16 +#define GPIO_MINOR_PWM0 (GPIO_MINOR_FIRST_PWM+0) +#define GPIO_MINOR_PWM1 (GPIO_MINOR_FIRST_PWM+1) +#define GPIO_MINOR_PWM2 (GPIO_MINOR_FIRST_PWM+2) +#define GPIO_MINOR_PPWM (GPIO_MINOR_FIRST_PWM+3) +#define GPIO_MINOR_LAST_PWM GPIO_MINOR_PPWM +#define GPIO_MINOR_LAST_REAL GPIO_MINOR_LAST_PWM +#endif + + + +/* supported ioctl _IOC_NR's */ + +#define IO_READBITS 0x1 /* read and return current port bits (obsolete) */ +#define IO_SETBITS 0x2 /* set the bits marked by 1 in the argument */ +#define IO_CLRBITS 0x3 /* clear the bits marked by 1 in the argument */ + +/* the alarm is waited for by select() */ + +#define IO_HIGHALARM 0x4 /* set alarm on high for bits marked by 1 */ +#define IO_LOWALARM 0x5 /* set alarm on low for bits marked by 1 */ +#define IO_CLRALARM 0x6 /* clear alarm for bits marked by 1 */ + +/* LED ioctl */ +#define IO_LEDACTIVE_SET 0x7 /* set active led + * 0=off, 1=green, 2=red, 3=yellow */ + +/* GPIO direction ioctl's */ +#define IO_READDIR 0x8 /* Read direction 0=input 1=output (obsolete) */ +#define IO_SETINPUT 0x9 /* Set direction for bits set, 0=unchanged 1=input, + returns mask with current inputs (obsolete) */ +#define IO_SETOUTPUT 0xA /* Set direction for bits set, 0=unchanged 1=output, + returns mask with current outputs (obsolete)*/ + +/* LED ioctl extended */ +#define IO_LED_SETBIT 0xB +#define IO_LED_CLRBIT 0xC + +/* SHUTDOWN ioctl */ +#define IO_SHUTDOWN 0xD +#define IO_GET_PWR_BT 0xE + +/* Bit toggling in driver settings */ +/* bit set in low byte0 is CLK mask (0x00FF), + bit set in byte1 is DATA mask (0xFF00) + msb, data_mask[7:0] , clk_mask[7:0] + */ +#define IO_CFG_WRITE_MODE 0xF +#define IO_CFG_WRITE_MODE_VALUE(msb, data_mask, clk_mask) \ + ( (((msb)&1) << 16) | (((data_mask) &0xFF) << 8) | ((clk_mask) & 0xFF) ) + +/* The following 4 ioctl's take a pointer as argument and handles + * 32 bit ports (port G) properly. + * These replaces IO_READBITS,IO_SETINPUT AND IO_SETOUTPUT + */ +#define IO_READ_INBITS 0x10 /* *arg is result of reading the input pins */ +#define IO_READ_OUTBITS 0x11 /* *arg is result of reading the output shadow */ +#define IO_SETGET_INPUT 0x12 /* bits set in *arg is set to input, */ + /* *arg updated with current input pins. */ +#define IO_SETGET_OUTPUT 0x13 /* bits set in *arg is set to output, */ + /* *arg updated with current output pins. */ + +/* The following ioctl's are applicable to the PWM channels only */ + +#define IO_PWM_SET_MODE 0x20 + +enum io_pwm_mode { + PWM_OFF = 0, /* disabled, deallocated */ + PWM_STANDARD = 1, /* 390 kHz, duty cycle 0..255/256 */ + PWM_FAST = 2, /* variable freq, w/ 10ns active pulse len */ + PWM_VARFREQ = 3, /* individually configurable high/low periods */ + PWM_SOFT = 4 /* software generated */ +}; + +struct io_pwm_set_mode { + enum io_pwm_mode mode; +}; + +/* Only for mode PWM_VARFREQ. Period lo/high set in increments of 10ns + * from 10ns (value = 0) to 81920ns (value = 8191) + * (Resulting frequencies range from 50 MHz (10ns + 10ns) down to + * 6.1 kHz (81920ns + 81920ns) at 50% duty cycle, to 12.2 kHz at min/max duty + * cycle (81920 + 10ns or 10ns + 81920ns, respectively).) + */ +#define IO_PWM_SET_PERIOD 0x21 + +struct io_pwm_set_period { + unsigned int lo; /* 0..8191 */ + unsigned int hi; /* 0..8191 */ +}; + +/* Only for modes PWM_STANDARD and PWM_FAST. + * For PWM_STANDARD, set duty cycle of 390 kHz PWM output signal, from + * 0 (value = 0) to 255/256 (value = 255). + * For PWM_FAST, set duty cycle of PWM output signal from + * 0% (value = 0) to 100% (value = 255). Output signal in this mode + * is a 10ns pulse surrounded by a high or low level depending on duty + * cycle (except for 0% and 100% which result in a constant output). + * Resulting output frequency varies from 50 MHz at 50% duty cycle, + * down to 390 kHz at min/max duty cycle. + */ +#define IO_PWM_SET_DUTY 0x22 + +struct io_pwm_set_duty { + int duty; /* 0..255 */ +}; + +/* Returns information about the latest PWM pulse. + * lo: Length of the latest low period, in units of 10ns. + * hi: Length of the latest high period, in units of 10ns. + * cnt: Time since last detected edge, in units of 10ns. + * + * The input source to PWM is decied by IO_PWM_SET_INPUT_SRC. + * + * NOTE: All PWM devices is connected to the same input source. + */ +#define IO_PWM_GET_PERIOD 0x23 + +struct io_pwm_get_period { + unsigned int lo; + unsigned int hi; + unsigned int cnt; +}; + +/* Sets the input source for the PWM input. For the src value see the + * register description for gio:rw_pwm_in_cfg. + * + * NOTE: All PWM devices is connected to the same input source. + */ +#define IO_PWM_SET_INPUT_SRC 0x24 +struct io_pwm_set_input_src { + unsigned int src; /* 0..7 */ +}; + +/* Sets the duty cycles in steps of 1/256, 0 = 0%, 255 = 100% duty cycle */ +#define IO_PPWM_SET_DUTY 0x25 + +struct io_ppwm_set_duty { + int duty; /* 0..255 */ +}; + +/* Configuraton struct for the IO_PWMCLK_SET_CONFIG ioctl to configure + * PWM capable gpio pins: + */ +#define IO_PWMCLK_SETGET_CONFIG 0x26 +struct gpio_pwmclk_conf { + unsigned int gpiopin; /* The pin number based on the opened device */ + unsigned int baseclk; /* The base clock to use, or sw will select one close*/ + unsigned int low; /* The number of low periods of the baseclk */ + unsigned int high; /* The number of high periods of the baseclk */ +}; + +/* Examples: + * To get a symmetric 12 MHz clock without knowing anything about the hardware: + * baseclk = 12000000, low = 0, high = 0 + * To just get info of current setting: + * baseclk = 0, low = 0, high = 0, the values will be updated by driver. + */ + +#endif diff --git a/arch/cris/include/uapi/asm/fcntl.h b/arch/cris/include/uapi/asm/fcntl.h new file mode 100644 index 0000000..46ab12d --- /dev/null +++ b/arch/cris/include/uapi/asm/fcntl.h @@ -0,0 +1 @@ +#include diff --git a/arch/cris/include/uapi/asm/ioctl.h b/arch/cris/include/uapi/asm/ioctl.h new file mode 100644 index 0000000..b279fe0 --- /dev/null +++ b/arch/cris/include/uapi/asm/ioctl.h @@ -0,0 +1 @@ +#include diff --git a/arch/cris/include/uapi/asm/ioctls.h b/arch/cris/include/uapi/asm/ioctls.h new file mode 100644 index 0000000..488fbb3 --- /dev/null +++ b/arch/cris/include/uapi/asm/ioctls.h @@ -0,0 +1,11 @@ +#ifndef __ARCH_CRIS_IOCTLS_H__ +#define __ARCH_CRIS_IOCTLS_H__ + +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERSETRS485 0x5461 /* enable rs-485 (deprecated) */ +#define TIOCSERWRRS485 0x5462 /* write rs-485 */ +#define TIOCSRS485 0x5463 /* enable rs-485 */ + +#include + +#endif diff --git a/arch/cris/include/uapi/asm/ipcbuf.h b/arch/cris/include/uapi/asm/ipcbuf.h new file mode 100644 index 0000000..84c7e51 --- /dev/null +++ b/arch/cris/include/uapi/asm/ipcbuf.h @@ -0,0 +1 @@ +#include diff --git a/arch/cris/include/uapi/asm/mman.h b/arch/cris/include/uapi/asm/mman.h new file mode 100644 index 0000000..8eebf89 --- /dev/null +++ b/arch/cris/include/uapi/asm/mman.h @@ -0,0 +1 @@ +#include diff --git a/arch/cris/include/uapi/asm/msgbuf.h b/arch/cris/include/uapi/asm/msgbuf.h new file mode 100644 index 0000000..ada63df --- /dev/null +++ b/arch/cris/include/uapi/asm/msgbuf.h @@ -0,0 +1,33 @@ +#ifndef _CRIS_MSGBUF_H +#define _CRIS_MSGBUF_H + +/* verbatim copy of asm-i386 version */ + +/* + * The msqid64_ds structure for CRIS architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + __kernel_time_t msg_stime; /* last msgsnd time */ + unsigned long __unused1; + __kernel_time_t msg_rtime; /* last msgrcv time */ + unsigned long __unused2; + __kernel_time_t msg_ctime; /* last change time */ + unsigned long __unused3; + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* _CRIS_MSGBUF_H */ diff --git a/arch/cris/include/uapi/asm/param.h b/arch/cris/include/uapi/asm/param.h new file mode 100644 index 0000000..484fcf8 --- /dev/null +++ b/arch/cris/include/uapi/asm/param.h @@ -0,0 +1,10 @@ +#ifndef _ASMCRIS_PARAM_H +#define _ASMCRIS_PARAM_H + +/* Currently we assume that HZ=100 is good for CRIS. */ + +#define EXEC_PAGESIZE 8192 + +#include + +#endif /* _ASMCRIS_PARAM_H */ diff --git a/arch/cris/include/uapi/asm/poll.h b/arch/cris/include/uapi/asm/poll.h new file mode 100644 index 0000000..c98509d --- /dev/null +++ b/arch/cris/include/uapi/asm/poll.h @@ -0,0 +1 @@ +#include diff --git a/arch/cris/include/uapi/asm/posix_types.h b/arch/cris/include/uapi/asm/posix_types.h new file mode 100644 index 0000000..ce4e517 --- /dev/null +++ b/arch/cris/include/uapi/asm/posix_types.h @@ -0,0 +1,35 @@ +/* $Id: posix_types.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ + +/* We cheat a bit and use our C-coded bitops functions from asm/bitops.h */ +/* I guess we should write these in assembler because they are used often. */ + +#ifndef __ARCH_CRIS_POSIX_TYPES_H +#define __ARCH_CRIS_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned short __kernel_mode_t; +#define __kernel_mode_t __kernel_mode_t + +typedef unsigned short __kernel_ipc_pid_t; +#define __kernel_ipc_pid_t __kernel_ipc_pid_t + +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +#define __kernel_uid_t __kernel_uid_t + +typedef __SIZE_TYPE__ __kernel_size_t; +typedef long __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +#define __kernel_size_t __kernel_size_t + +typedef unsigned short __kernel_old_dev_t; +#define __kernel_old_dev_t __kernel_old_dev_t + +#include + +#endif /* __ARCH_CRIS_POSIX_TYPES_H */ diff --git a/arch/cris/include/uapi/asm/ptrace.h b/arch/cris/include/uapi/asm/ptrace.h new file mode 100644 index 0000000..c689c9b --- /dev/null +++ b/arch/cris/include/uapi/asm/ptrace.h @@ -0,0 +1 @@ +#include diff --git a/arch/cris/include/uapi/asm/resource.h b/arch/cris/include/uapi/asm/resource.h new file mode 100644 index 0000000..b5d2944 --- /dev/null +++ b/arch/cris/include/uapi/asm/resource.h @@ -0,0 +1,6 @@ +#ifndef _CRIS_RESOURCE_H +#define _CRIS_RESOURCE_H + +#include + +#endif diff --git a/arch/cris/include/uapi/asm/rs485.h b/arch/cris/include/uapi/asm/rs485.h new file mode 100644 index 0000000..ad40f9f --- /dev/null +++ b/arch/cris/include/uapi/asm/rs485.h @@ -0,0 +1,18 @@ +/* RS-485 structures */ + +/* Used with ioctl() TIOCSERSETRS485 for backward compatibility! + * XXX: Do not use it for new code! + */ +struct rs485_control { + unsigned short rts_on_send; + unsigned short rts_after_sent; + unsigned long delay_rts_before_send; + unsigned short enabled; +}; + +/* Used with ioctl() TIOCSERWRRS485 */ +struct rs485_write { + unsigned short outc_size; + unsigned char *outc; +}; + diff --git a/arch/cris/include/uapi/asm/sembuf.h b/arch/cris/include/uapi/asm/sembuf.h new file mode 100644 index 0000000..7fed984 --- /dev/null +++ b/arch/cris/include/uapi/asm/sembuf.h @@ -0,0 +1,25 @@ +#ifndef _CRIS_SEMBUF_H +#define _CRIS_SEMBUF_H + +/* + * The semid64_ds structure for CRIS architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t sem_otime; /* last semop time */ + unsigned long __unused1; + __kernel_time_t sem_ctime; /* last change time */ + unsigned long __unused2; + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* _CRIS_SEMBUF_H */ diff --git a/arch/cris/include/uapi/asm/setup.h b/arch/cris/include/uapi/asm/setup.h new file mode 100644 index 0000000..b907286 --- /dev/null +++ b/arch/cris/include/uapi/asm/setup.h @@ -0,0 +1,6 @@ +#ifndef _CRIS_SETUP_H +#define _CRIS_SETUP_H + +#define COMMAND_LINE_SIZE 256 + +#endif diff --git a/arch/cris/include/uapi/asm/shmbuf.h b/arch/cris/include/uapi/asm/shmbuf.h new file mode 100644 index 0000000..3239e3f --- /dev/null +++ b/arch/cris/include/uapi/asm/shmbuf.h @@ -0,0 +1,42 @@ +#ifndef _CRIS_SHMBUF_H +#define _CRIS_SHMBUF_H + +/* + * The shmid64_ds structure for CRIS architecture (same as for i386) + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + unsigned long __unused1; + __kernel_time_t shm_dtime; /* last detach time */ + unsigned long __unused2; + __kernel_time_t shm_ctime; /* last change time */ + unsigned long __unused3; + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused4; + unsigned long __unused5; +}; + +struct shminfo64 { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused1; + unsigned long __unused2; + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* _CRIS_SHMBUF_H */ diff --git a/arch/cris/include/uapi/asm/sigcontext.h b/arch/cris/include/uapi/asm/sigcontext.h new file mode 100644 index 0000000..a1d634e --- /dev/null +++ b/arch/cris/include/uapi/asm/sigcontext.h @@ -0,0 +1,24 @@ +/* $Id: sigcontext.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ + +#ifndef _ASM_CRIS_SIGCONTEXT_H +#define _ASM_CRIS_SIGCONTEXT_H + +#include + +/* This struct is saved by setup_frame in signal.c, to keep the current context while + a signal handler is executed. It's restored by sys_sigreturn. + + To keep things simple, we use pt_regs here even though normally you just specify + the list of regs to save. Then we can use copy_from_user on the entire regs instead + of a bunch of get_user's as well... + +*/ + +struct sigcontext { + struct pt_regs regs; /* needs to be first */ + unsigned long oldmask; + unsigned long usp; /* usp before stacking this gunk on it */ +}; + +#endif + diff --git a/arch/cris/include/uapi/asm/siginfo.h b/arch/cris/include/uapi/asm/siginfo.h new file mode 100644 index 0000000..c1cd6d1 --- /dev/null +++ b/arch/cris/include/uapi/asm/siginfo.h @@ -0,0 +1,6 @@ +#ifndef _CRIS_SIGINFO_H +#define _CRIS_SIGINFO_H + +#include + +#endif diff --git a/arch/cris/include/uapi/asm/signal.h b/arch/cris/include/uapi/asm/signal.h new file mode 100644 index 0000000..2162494 --- /dev/null +++ b/arch/cris/include/uapi/asm/signal.h @@ -0,0 +1,122 @@ +#ifndef _UAPI_ASM_CRIS_SIGNAL_H +#define _UAPI_ASM_CRIS_SIGNAL_H + +#include + +/* Avoid too many header ordering problems. */ +struct siginfo; + +#ifndef __KERNEL__ +/* Here we must cater to libcs that poke about in kernel headers. */ + +#define NSIG 32 +typedef unsigned long sigset_t; + +#endif /* __KERNEL__ */ + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX _NSIG + +/* + * SA_FLAGS values: + * + * SA_ONSTACK indicates that a registered stack_t will be used. + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. + */ + +#define SA_NOCLDSTOP 0x00000001u +#define SA_NOCLDWAIT 0x00000002u +#define SA_SIGINFO 0x00000004u +#define SA_ONSTACK 0x08000000u +#define SA_RESTART 0x10000000u +#define SA_NODEFER 0x40000000u +#define SA_RESETHAND 0x80000000u + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND + +#define SA_RESTORER 0x04000000 + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 + +#include + +#ifndef __KERNEL__ +/* Here we must cater to libcs that poke about in kernel headers. */ + +struct sigaction { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, struct siginfo *, void *); + } _u; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +#define sa_handler _u._sa_handler +#define sa_sigaction _u._sa_sigaction + +#endif /* __KERNEL__ */ + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + + +#endif /* _UAPI_ASM_CRIS_SIGNAL_H */ diff --git a/arch/cris/include/uapi/asm/socket.h b/arch/cris/include/uapi/asm/socket.h new file mode 100644 index 0000000..ae52825 --- /dev/null +++ b/arch/cris/include/uapi/asm/socket.h @@ -0,0 +1,76 @@ +#ifndef _ASM_SOCKET_H +#define _ASM_SOCKET_H + +/* almost the same as asm-i386/socket.h */ + +#include + +/* For setsockoptions(2) */ +#define SOL_SOCKET 1 + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_SNDBUFFORCE 32 +#define SO_RCVBUFFORCE 33 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +/* To add :#define SO_REUSEPORT 15 */ +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + +/* Security levels - as per NRL IPv6 - don't actually do anything */ +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +/* Socket filtering */ +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 + +#define SO_PEERNAME 28 +#define SO_TIMESTAMP 29 +#define SCM_TIMESTAMP SO_TIMESTAMP + +#define SO_ACCEPTCONN 30 + +#define SO_PEERSEC 31 +#define SO_PASSSEC 34 +#define SO_TIMESTAMPNS 35 +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS + +#define SO_MARK 36 + +#define SO_TIMESTAMPING 37 +#define SCM_TIMESTAMPING SO_TIMESTAMPING + +#define SO_PROTOCOL 38 +#define SO_DOMAIN 39 + +#define SO_RXQ_OVFL 40 + +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 + +#endif /* _ASM_SOCKET_H */ + + diff --git a/arch/cris/include/uapi/asm/sockios.h b/arch/cris/include/uapi/asm/sockios.h new file mode 100644 index 0000000..cfe7bfe --- /dev/null +++ b/arch/cris/include/uapi/asm/sockios.h @@ -0,0 +1,13 @@ +#ifndef __ARCH_CRIS_SOCKIOS__ +#define __ARCH_CRIS_SOCKIOS__ + +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ +#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ + +#endif diff --git a/arch/cris/include/uapi/asm/stat.h b/arch/cris/include/uapi/asm/stat.h new file mode 100644 index 0000000..9e558cc --- /dev/null +++ b/arch/cris/include/uapi/asm/stat.h @@ -0,0 +1,81 @@ +#ifndef _CRIS_STAT_H +#define _CRIS_STAT_H + +/* Keep this a verbatim copy of i386 version; tweak CRIS-specific bits in + the kernel if necessary. */ + +struct __old_kernel_stat { + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned long st_size; + unsigned long st_atime; + unsigned long st_mtime; + unsigned long st_ctime; +}; + +#define STAT_HAVE_NSEC 1 + +struct stat { + unsigned long st_dev; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned long st_rdev; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned long st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + unsigned long __unused4; + unsigned long __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct stat64 { + unsigned long long st_dev; + unsigned char __pad0[4]; + +#define STAT64_HAS_BROKEN_ST_INO 1 + unsigned long __st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + unsigned long long st_rdev; + unsigned char __pad3[4]; + + long long st_size; + unsigned long st_blksize; + + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ + unsigned long __pad4; /* future possible st_blocks high bits */ + + unsigned long st_atime; + unsigned long st_atime_nsec; + + unsigned long st_mtime; + unsigned long st_mtime_nsec; + + unsigned long st_ctime; + unsigned long st_ctime_nsec; /* will be high 32 bits of ctime someday */ + + unsigned long long st_ino; +}; + +#endif diff --git a/arch/cris/include/uapi/asm/statfs.h b/arch/cris/include/uapi/asm/statfs.h new file mode 100644 index 0000000..fdaf921 --- /dev/null +++ b/arch/cris/include/uapi/asm/statfs.h @@ -0,0 +1,6 @@ +#ifndef _CRIS_STATFS_H +#define _CRIS_STATFS_H + +#include + +#endif diff --git a/arch/cris/include/uapi/asm/swab.h b/arch/cris/include/uapi/asm/swab.h new file mode 100644 index 0000000..e69de29 diff --git a/arch/cris/include/uapi/asm/sync_serial.h b/arch/cris/include/uapi/asm/sync_serial.h new file mode 100644 index 0000000..7f827fe --- /dev/null +++ b/arch/cris/include/uapi/asm/sync_serial.h @@ -0,0 +1,132 @@ +/* + * ioctl defines for synchronous serial port driver + * + * Copyright (c) 2001-2003 Axis Communications AB + * + * Author: Mikael Starvik + * + */ + +#ifndef SYNC_SERIAL_H +#define SYNC_SERIAL_H + +#include + +#define SSP_SPEED _IOR('S', 0, unsigned int) +#define SSP_MODE _IOR('S', 1, unsigned int) +#define SSP_FRAME_SYNC _IOR('S', 2, unsigned int) +#define SSP_IPOLARITY _IOR('S', 3, unsigned int) +#define SSP_OPOLARITY _IOR('S', 4, unsigned int) +#define SSP_SPI _IOR('S', 5, unsigned int) +#define SSP_INBUFCHUNK _IOR('S', 6, unsigned int) +#define SSP_INPUT _IOR('S', 7, unsigned int) + +/* Values for SSP_SPEED */ +#define SSP150 0 +#define SSP300 1 +#define SSP600 2 +#define SSP1200 3 +#define SSP2400 4 +#define SSP4800 5 +#define SSP9600 6 +#define SSP19200 7 +#define SSP28800 8 +#define SSP57600 9 +#define SSP115200 10 +#define SSP230400 11 +#define SSP460800 12 +#define SSP921600 13 +#define SSP3125000 14 +#define CODEC 15 +#define CODEC_f32768 16 + +#define FREQ_4MHz 0 +#define FREQ_2MHz 1 +#define FREQ_1MHz 2 +#define FREQ_512kHz 3 +#define FREQ_256kHz 4 +#define FREQ_128kHz 5 +#define FREQ_64kHz 6 +#define FREQ_32kHz 7 +/* FREQ_* with values where bit (value & 0x10) is set are */ +/* used for CODEC_f32768 */ +#define FREQ_4096kHz 16 /* CODEC_f32768 */ + +/* Used by application to set CODEC divider, word rate and frame rate */ +#define CODEC_VAL(freq, clk_per_sync, sync_per_frame) \ + ((CODEC + ((freq & 0x10) >> 4)) | (freq << 8) | \ + (clk_per_sync << 16) | (sync_per_frame << 28)) + +/* Used by driver to extract speed */ +#define GET_SPEED(x) (x & 0xff) +#define GET_FREQ(x) ((x & 0xff00) >> 8) +#define GET_WORD_RATE(x) (((x & 0x0fff0000) >> 16) - 1) +#define GET_FRAME_RATE(x) (((x & 0xf0000000) >> 28) - 1) + +/* Values for SSP_MODE */ +#define MASTER_OUTPUT 0 +#define SLAVE_OUTPUT 1 +#define MASTER_INPUT 2 +#define SLAVE_INPUT 3 +#define MASTER_BIDIR 4 +#define SLAVE_BIDIR 5 + +/* Values for SSP_FRAME_SYNC */ +#define NORMAL_SYNC 1 +#define EARLY_SYNC 2 +#define SECOND_WORD_SYNC 0x40000 +#define LATE_SYNC 0x80000 + +#define BIT_SYNC 4 +#define WORD_SYNC 8 +#define EXTENDED_SYNC 0x10 + +#define SYNC_OFF 0x20 +#define SYNC_ON 0x40 +#define WORD_SIZE_8 0x80 +#define WORD_SIZE_12 0x100 +#define WORD_SIZE_16 0x200 +#define WORD_SIZE_24 0x400 +#define WORD_SIZE_32 0x800 +#define BIT_ORDER_LSB 0x1000 +#define BIT_ORDER_MSB 0x2000 +#define FLOW_CONTROL_ENABLE 0x4000 +#define FLOW_CONTROL_DISABLE 0x8000 +#define CLOCK_GATED 0x10000 +#define CLOCK_NOT_GATED 0x20000 + +/* Values for SSP_IPOLARITY and SSP_OPOLARITY */ +#define CLOCK_NORMAL 1 +#define CLOCK_INVERT 2 +#define CLOCK_INEGEDGE CLOCK_NORMAL +#define CLOCK_IPOSEDGE CLOCK_INVERT +#define FRAME_NORMAL 4 +#define FRAME_INVERT 8 +#define STATUS_NORMAL 0x10 +#define STATUS_INVERT 0x20 + +/* Values for SSP_SPI */ +#define SPI_MASTER 0 +#define SPI_SLAVE 1 + +/* Values for SSP_INBUFCHUNK */ +/* plain integer with the size of DMA chunks */ + +/* To ensure that the timestamps are aligned with the data being read + * the read length MUST be a multiple of the length of the DMA buffers. + * + * Use a multiple of SSP_INPUT_CHUNK_SIZE defined below. + */ +#define SSP_INPUT_CHUNK_SIZE 256 + +/* Request struct to pass through the ioctl interface to read + * data with timestamps. + */ +struct ssp_request { + char __user *buf; /* Where to put the data. */ + size_t len; /* Size of buf. MUST be a multiple of */ + /* SSP_INPUT_CHUNK_SIZE! */ + struct timespec ts; /* The time the data was sampled. */ +}; + +#endif diff --git a/arch/cris/include/uapi/asm/termbits.h b/arch/cris/include/uapi/asm/termbits.h new file mode 100644 index 0000000..1c43bc8 --- /dev/null +++ b/arch/cris/include/uapi/asm/termbits.h @@ -0,0 +1,235 @@ +/* $Id: termbits.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ + +#ifndef __ARCH_ETRAX100_TERMBITS_H__ +#define __ARCH_ETRAX100_TERMBITS_H__ + +#include + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +struct termios2 { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +}; + +struct ktermios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +/* c_cflag bit meaning */ +/* + * 3 2 1 + * 10 987 654 321 098 765 432 109 876 543 210 + * | | ||| CBAUD + * obaud + * + * ||CSIZE + * + * |CSTOP + * |CREAD + * |CPARENB + * + * |CPARODD + * |HUPCL + * |CLOCAL + * |CBAUDEX + * 10 987 654 321 098 765 432 109 876 543 210 + * | || || CIBAUD, IBSHIFT=16 + * ibaud + * |CMSPAR + * | CRTSCTS + * x x xxx xxx x x xx Free bits + */ + +#define CBAUD 0010017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CBAUDEX 0010000 +#define BOTHER 0010000 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 + +/* Unsupported rates, but needed to avoid compile error. */ +#define B500000 0010005 +#define B576000 0010006 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 + +/* etrax supports these additional three baud rates */ +#define B921600 0010005 +#define B1843200 0010006 +#define B6250000 0010007 +/* ETRAX FS supports this as well */ +#define B12500000 0010010 +#define CIBAUD 002003600000 /* input baud rate (used in v32) */ +/* The values for CIBAUD bits are the same as the values for CBAUD and CBAUDEX + * shifted left IBSHIFT bits. + */ +#define IBSHIFT 16 +#define CMSPAR 010000000000 /* mark or space (stick) parity - PARODD=space*/ +#define CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 +#define EXTPROC 0200000 + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#endif diff --git a/arch/cris/include/uapi/asm/termios.h b/arch/cris/include/uapi/asm/termios.h new file mode 100644 index 0000000..0a0386a --- /dev/null +++ b/arch/cris/include/uapi/asm/termios.h @@ -0,0 +1,45 @@ +#ifndef _UAPI_CRIS_TERMIOS_H +#define _UAPI_CRIS_TERMIOS_H + +#include +#include +#include +#include + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ + + +#endif /* _UAPI_CRIS_TERMIOS_H */ diff --git a/arch/cris/include/uapi/asm/types.h b/arch/cris/include/uapi/asm/types.h new file mode 100644 index 0000000..9ec9d4c --- /dev/null +++ b/arch/cris/include/uapi/asm/types.h @@ -0,0 +1 @@ +#include diff --git a/arch/cris/include/uapi/asm/unistd.h b/arch/cris/include/uapi/asm/unistd.h new file mode 100644 index 0000000..4884289 --- /dev/null +++ b/arch/cris/include/uapi/asm/unistd.h @@ -0,0 +1,344 @@ +#ifndef _UAPI_ASM_CRIS_UNISTD_H_ +#define _UAPI_ASM_CRIS_UNISTD_H_ + +/* + * This file contains the system call numbers, and stub macros for libc. + */ + +#define __NR_restart_syscall 0 +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_lchown 16 +#define __NR_break 17 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_profil 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl 110 +#define __NR_vhangup 111 +#define __NR_idle 112 +#define __NR_vm86 113 +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_modify_ldt 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 + +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread64 180 +#define __NR_pwrite64 181 +#define __NR_chown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_getpmsg 188 /* some people actually want streams */ +#define __NR_putpmsg 189 /* some people actually want streams */ +#define __NR_vfork 190 +#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */ +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_lchown32 198 +#define __NR_getuid32 199 +#define __NR_getgid32 200 +#define __NR_geteuid32 201 +#define __NR_getegid32 202 +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#define __NR_chown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#define __NR_pivot_root 217 +#define __NR_mincore 218 +#define __NR_madvise 219 +#define __NR_getdents64 220 +#define __NR_fcntl64 221 +/* 223 is unused */ +#define __NR_gettid 224 +#define __NR_readahead 225 +#define __NR_setxattr 226 +#define __NR_lsetxattr 227 +#define __NR_fsetxattr 228 +#define __NR_getxattr 229 +#define __NR_lgetxattr 230 +#define __NR_fgetxattr 231 +#define __NR_listxattr 232 +#define __NR_llistxattr 233 +#define __NR_flistxattr 234 +#define __NR_removexattr 235 +#define __NR_lremovexattr 236 +#define __NR_fremovexattr 237 +#define __NR_tkill 238 +#define __NR_sendfile64 239 +#define __NR_futex 240 +#define __NR_sched_setaffinity 241 +#define __NR_sched_getaffinity 242 +#define __NR_set_thread_area 243 +#define __NR_get_thread_area 244 +#define __NR_io_setup 245 +#define __NR_io_destroy 246 +#define __NR_io_getevents 247 +#define __NR_io_submit 248 +#define __NR_io_cancel 249 +#define __NR_fadvise64 250 +/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */ +#define __NR_exit_group 252 +#define __NR_lookup_dcookie 253 +#define __NR_epoll_create 254 +#define __NR_epoll_ctl 255 +#define __NR_epoll_wait 256 +#define __NR_remap_file_pages 257 +#define __NR_set_tid_address 258 +#define __NR_timer_create 259 +#define __NR_timer_settime (__NR_timer_create+1) +#define __NR_timer_gettime (__NR_timer_create+2) +#define __NR_timer_getoverrun (__NR_timer_create+3) +#define __NR_timer_delete (__NR_timer_create+4) +#define __NR_clock_settime (__NR_timer_create+5) +#define __NR_clock_gettime (__NR_timer_create+6) +#define __NR_clock_getres (__NR_timer_create+7) +#define __NR_clock_nanosleep (__NR_timer_create+8) +#define __NR_statfs64 268 +#define __NR_fstatfs64 269 +#define __NR_tgkill 270 +#define __NR_utimes 271 +#define __NR_fadvise64_64 272 +#define __NR_vserver 273 +#define __NR_mbind 274 +#define __NR_get_mempolicy 275 +#define __NR_set_mempolicy 276 +#define __NR_mq_open 277 +#define __NR_mq_unlink (__NR_mq_open+1) +#define __NR_mq_timedsend (__NR_mq_open+2) +#define __NR_mq_timedreceive (__NR_mq_open+3) +#define __NR_mq_notify (__NR_mq_open+4) +#define __NR_mq_getsetattr (__NR_mq_open+5) +#define __NR_kexec_load 283 +#define __NR_waitid 284 +/* #define __NR_sys_setaltroot 285 */ +#define __NR_add_key 286 +#define __NR_request_key 287 +#define __NR_keyctl 288 +#define __NR_ioprio_set 289 +#define __NR_ioprio_get 290 +#define __NR_inotify_init 291 +#define __NR_inotify_add_watch 292 +#define __NR_inotify_rm_watch 293 +#define __NR_migrate_pages 294 +#define __NR_openat 295 +#define __NR_mkdirat 296 +#define __NR_mknodat 297 +#define __NR_fchownat 298 +#define __NR_futimesat 299 +#define __NR_fstatat64 300 +#define __NR_unlinkat 301 +#define __NR_renameat 302 +#define __NR_linkat 303 +#define __NR_symlinkat 304 +#define __NR_readlinkat 305 +#define __NR_fchmodat 306 +#define __NR_faccessat 307 +#define __NR_pselect6 308 +#define __NR_ppoll 309 +#define __NR_unshare 310 +#define __NR_set_robust_list 311 +#define __NR_get_robust_list 312 +#define __NR_splice 313 +#define __NR_sync_file_range 314 +#define __NR_tee 315 +#define __NR_vmsplice 316 +#define __NR_move_pages 317 +#define __NR_getcpu 318 +#define __NR_epoll_pwait 319 +#define __NR_utimensat 320 +#define __NR_signalfd 321 +#define __NR_timerfd_create 322 +#define __NR_eventfd 323 +#define __NR_fallocate 324 +#define __NR_timerfd_settime 325 +#define __NR_timerfd_gettime 326 +#define __NR_signalfd4 327 +#define __NR_eventfd2 328 +#define __NR_epoll_create1 329 +#define __NR_dup3 330 +#define __NR_pipe2 331 +#define __NR_inotify_init1 332 +#define __NR_preadv 333 +#define __NR_pwritev 334 +#define __NR_setns 335 + +#endif /* _UAPI_ASM_CRIS_UNISTD_H_ */ -- cgit v0.10.2 From 8618e30bc14b06bfafa0f164cca7b0e06451f88a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 8 Oct 2012 20:37:30 -0700 Subject: rbd: let con_work() handle backoff Both ceph_fault() and con_work() include handling for imposing a delay before doing further processing on a faulted connection. The latter is used only if ceph_fault() is unable to. Instead, just let con_work() always be responsible for implementing the delay. After setting up the delay value, set the BACKOFF flag on the connection unconditionally and call queue_con() to ensure con_work() will get called to handle it. Signed-off-by: Alex Elder Reviewed-by: Sage Weil diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index cad0d17..973c16c 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2398,24 +2398,8 @@ static void ceph_fault(struct ceph_connection *con) con->delay = BASE_DELAY_INTERVAL; else if (con->delay < MAX_DELAY_INTERVAL) con->delay *= 2; - con->ops->get(con); - if (queue_delayed_work(ceph_msgr_wq, &con->work, - round_jiffies_relative(con->delay))) { - dout("fault queued %p delay %lu\n", con, con->delay); - } else { - con->ops->put(con); - dout("fault failed to queue %p delay %lu, backoff\n", - con, con->delay); - /* - * In many cases we see a socket state change - * while con_work is running and end up - * queuing (non-delayed) work, such that we - * can't backoff with a delay. Set a flag so - * that when con_work restarts we schedule the - * delay then. - */ - set_bit(CON_FLAG_BACKOFF, &con->flags); - } + set_bit(CON_FLAG_BACKOFF, &con->flags); + queue_con(con); } out_unlock: -- cgit v0.10.2 From 802c6d967fbdcd2cbc91b917425661bb8bbfaade Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 8 Oct 2012 20:37:30 -0700 Subject: rbd: define common queue_con_delay() This patch defines a single function, queue_con_delay() to call queue_delayed_work() for a connection. It basically generalizes what was previously queue_con() by adding the delay argument. queue_con() is now a simple helper that passes 0 for its delay. queue_con_delay() returns 0 if it queued work or an errno if it did not for some reason. If con_work() finds the BACKOFF flag set for a connection, it now calls queue_con_delay() to handle arranging to start again after a delay. Note about connection reference counts: con_work() only ever gets called as a work item function. At the time that work is scheduled, a reference to the connection is acquired, and the corresponding con_work() call is then responsible for dropping that reference before it returns. Previously, the backoff handling inside con_work() silently handed off its reference to delayed work it scheduled. Now that queue_con_delay() is used, a new reference is acquired for the newly-scheduled work, and the original reference is dropped by the con->ops->put() call at the end of the function. Signed-off-by: Alex Elder Reviewed-by: Sage Weil diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 973c16c..66f6f56 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2244,22 +2244,33 @@ bad_tag: /* - * Atomically queue work on a connection. Bump @con reference to - * avoid races with connection teardown. + * Atomically queue work on a connection after the specified delay. + * Bump @con reference to avoid races with connection teardown. + * Returns 0 if work was queued, or an error code otherwise. */ -static void queue_con(struct ceph_connection *con) +static int queue_con_delay(struct ceph_connection *con, unsigned long delay) { if (!con->ops->get(con)) { - dout("queue_con %p ref count 0\n", con); - return; + dout("%s %p ref count 0\n", __func__, con); + + return -ENOENT; } - if (!queue_delayed_work(ceph_msgr_wq, &con->work, 0)) { - dout("queue_con %p - already queued\n", con); + if (!queue_delayed_work(ceph_msgr_wq, &con->work, delay)) { + dout("%s %p - already queued\n", __func__, con); con->ops->put(con); - } else { - dout("queue_con %p\n", con); + + return -EBUSY; } + + dout("%s %p %lu\n", __func__, con, delay); + + return 0; +} + +static void queue_con(struct ceph_connection *con) +{ + (void) queue_con_delay(con, 0); } /* @@ -2294,14 +2305,11 @@ restart: if (test_and_clear_bit(CON_FLAG_BACKOFF, &con->flags)) { dout("con_work %p backing off\n", con); - if (queue_delayed_work(ceph_msgr_wq, &con->work, - round_jiffies_relative(con->delay))) { - dout("con_work %p backoff %lu\n", con, con->delay); - mutex_unlock(&con->mutex); - return; - } else { + ret = queue_con_delay(con, round_jiffies_relative(con->delay)); + if (ret) { dout("con_work %p FAILED to back off %lu\n", con, con->delay); + BUG_ON(ret == -ENOENT); set_bit(CON_FLAG_BACKOFF, &con->flags); } goto done; -- cgit v0.10.2 From 9478554ae5d21d65e948a3eff4ee2a8ad30d70e9 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 9 Oct 2012 13:50:17 -0700 Subject: rbd: define rbd_update_mapping_size() Encapsulate the code that handles updating the size of a mapping after an rbd image has been refreshed. This is done in anticipation of the next patch, which will make this common code for format 1 and 2 images. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index bb3d9be..b64125d 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1716,6 +1716,19 @@ static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev) __rbd_remove_snap_dev(snap); } +static void rbd_update_mapping_size(struct rbd_device *rbd_dev) +{ + sector_t size; + + if (rbd_dev->mapping.snap_id != CEPH_NOSNAP) + return; + + size = (sector_t) rbd_dev->header.image_size / SECTOR_SIZE; + dout("setting size to %llu sectors", (unsigned long long) size); + rbd_dev->mapping.size = (u64) size; + set_capacity(rbd_dev->disk, size); +} + /* * only read the first part of the ondisk header, without the snaps info */ @@ -1730,17 +1743,9 @@ static int __rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver) down_write(&rbd_dev->header_rwsem); - /* resized? */ - if (rbd_dev->mapping.snap_id == CEPH_NOSNAP) { - sector_t size = (sector_t) h.image_size / SECTOR_SIZE; - - if (size != (sector_t) rbd_dev->mapping.size) { - dout("setting size to %llu sectors", - (unsigned long long) size); - rbd_dev->mapping.size = (u64) size; - set_capacity(rbd_dev->disk, size); - } - } + /* Update image size, and check for resize of mapped image */ + rbd_dev->header.image_size = h.image_size; + rbd_update_mapping_size(rbd_dev); /* rbd_dev->header.object_prefix shouldn't change */ kfree(rbd_dev->header.snap_sizes); -- cgit v0.10.2 From 117973fb4c91f3fd913127577e9f71b3aa6cb556 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 31 Aug 2012 17:29:55 -0500 Subject: rbd: define rbd_dev_v2_refresh() Define a new function rbd_dev_v2_refresh() to update/refresh the snapshot context for a format version 2 rbd image. This function will update anything that is not fixed for the life of an rbd image--at the moment this is mainly the snapshot context and (for a base mapping) the size. Update rbd_refresh_header() so it selects which function to use based on the image format. Rename __rbd_refresh_header() to be rbd_dev_v1_refresh() to be consistent with the naming of its version 2 counterpart. Similarly rename rbd_refresh_header() to be rbd_dev_refresh(). Unrelated--we use rbd_image_format_valid() here. Delete the other use of it, which was primarily put in place to ensure that function was referenced at the time it was defined. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index b64125d..f11b839 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -268,7 +268,8 @@ static void rbd_put_dev(struct rbd_device *rbd_dev) put_device(&rbd_dev->dev); } -static int rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver); +static int rbd_dev_refresh(struct rbd_device *rbd_dev, u64 *hver); +static int rbd_dev_v2_refresh(struct rbd_device *rbd_dev, u64 *hver); static int rbd_open(struct block_device *bdev, fmode_t mode) { @@ -1304,7 +1305,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data) dout("rbd_watch_cb %s notify_id=%llu opcode=%u\n", rbd_dev->header_name, (unsigned long long) notify_id, (unsigned int) opcode); - rc = rbd_refresh_header(rbd_dev, &hver); + rc = rbd_dev_refresh(rbd_dev, &hver); if (rc) pr_warning(RBD_DRV_NAME "%d got notification but failed to " " update snaps: %d\n", rbd_dev->major, rc); @@ -1732,7 +1733,7 @@ static void rbd_update_mapping_size(struct rbd_device *rbd_dev) /* * only read the first part of the ondisk header, without the snaps info */ -static int __rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver) +static int rbd_dev_v1_refresh(struct rbd_device *rbd_dev, u64 *hver) { int ret; struct rbd_image_header h; @@ -1773,12 +1774,16 @@ static int __rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver) return ret; } -static int rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver) +static int rbd_dev_refresh(struct rbd_device *rbd_dev, u64 *hver) { int ret; + rbd_assert(rbd_image_format_valid(rbd_dev->image_format)); mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - ret = __rbd_refresh_header(rbd_dev, hver); + if (rbd_dev->image_format == 1) + ret = rbd_dev_v1_refresh(rbd_dev, hver); + else + ret = rbd_dev_v2_refresh(rbd_dev, hver); mutex_unlock(&ctl_mutex); return ret; @@ -1938,7 +1943,7 @@ static ssize_t rbd_image_refresh(struct device *dev, struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); int ret; - ret = rbd_refresh_header(rbd_dev, NULL); + ret = rbd_dev_refresh(rbd_dev, NULL); return ret < 0 ? ret : size; } @@ -2402,6 +2407,41 @@ static char *rbd_dev_snap_info(struct rbd_device *rbd_dev, u32 which, return ERR_PTR(-EINVAL); } +static int rbd_dev_v2_refresh(struct rbd_device *rbd_dev, u64 *hver) +{ + int ret; + __u8 obj_order; + + down_write(&rbd_dev->header_rwsem); + + /* Grab old order first, to see if it changes */ + + obj_order = rbd_dev->header.obj_order, + ret = rbd_dev_v2_image_size(rbd_dev); + if (ret) + goto out; + if (rbd_dev->header.obj_order != obj_order) { + ret = -EIO; + goto out; + } + rbd_update_mapping_size(rbd_dev); + + ret = rbd_dev_v2_snap_context(rbd_dev, hver); + dout("rbd_dev_v2_snap_context returned %d\n", ret); + if (ret) + goto out; + ret = rbd_dev_snaps_update(rbd_dev); + dout("rbd_dev_snaps_update returned %d\n", ret); + if (ret) + goto out; + ret = rbd_dev_snaps_register(rbd_dev); + dout("rbd_dev_snaps_register returned %d\n", ret); +out: + up_write(&rbd_dev->header_rwsem); + + return ret; +} + /* * Scan the rbd device's current snapshot list and compare it to the * newly-received snapshot context. Remove any existing snapshots @@ -2564,7 +2604,7 @@ static int rbd_init_watch_dev(struct rbd_device *rbd_dev) do { ret = rbd_req_sync_watch(rbd_dev); if (ret == -ERANGE) { - rc = rbd_refresh_header(rbd_dev, NULL); + rc = rbd_dev_refresh(rbd_dev, NULL); if (rc < 0) return rc; } @@ -3045,7 +3085,6 @@ static ssize_t rbd_add(struct bus_type *bus, rc = rbd_dev_probe(rbd_dev); if (rc < 0) goto err_out_client; - rbd_assert(rbd_image_format_valid(rbd_dev->image_format)); /* no need to lock here, as rbd_dev is not registered yet */ rc = rbd_dev_snaps_update(rbd_dev); -- cgit v0.10.2 From d889140c4a1c5edb6a7bd90392b9d878bfaccfb6 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 9 Oct 2012 13:50:17 -0700 Subject: rbd: implement feature checks Version 2 images have two sets of feature bit fields. The first indicates features possibly used by the image. The second indicates features that the client *must* support in order to use the image. When an image (or snapshot) is first examined, we need to make sure that the local implementation supports the image's required features. If not, fail the probe for the image. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index f11b839..0f260a6 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -70,6 +70,14 @@ #define RBD_IMAGE_ID_LEN_MAX 64 #define RBD_OBJ_PREFIX_LEN_MAX 64 +/* Feature bits */ + +#define RBD_FEATURE_LAYERING 1 + +/* Features supported by this (client software) implementation. */ + +#define RBD_FEATURES_ALL (0) + /* * An RBD device name will be "rbd#", where the "rbd" comes from * RBD_DRV_NAME above, and # is a unique integer identifier. @@ -2226,6 +2234,7 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id, __le64 features; __le64 incompat; } features_buf = { 0 }; + u64 incompat; int ret; ret = rbd_req_sync_exec(rbd_dev, rbd_dev->header_name, @@ -2236,6 +2245,11 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id, dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret); if (ret < 0) return ret; + + incompat = le64_to_cpu(features_buf.incompat); + if (incompat & ~RBD_FEATURES_ALL) + return -ENOTSUPP; + *snap_features = le64_to_cpu(features_buf.features); dout(" snap_id 0x%016llx features = 0x%016llx incompat = 0x%016llx\n", @@ -2977,7 +2991,7 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev) if (ret < 0) goto out_err; - /* Get the features for the image */ + /* Get the and check features for the image */ ret = rbd_dev_v2_features(rbd_dev); if (ret < 0) -- cgit v0.10.2 From 35152979e6181b1fbb4b61c3ff641c14df53ad66 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 31 Aug 2012 17:29:55 -0500 Subject: rbd: activate v2 image support Now that v2 images support is fully implemented, have rbd_dev_v2_probe() return 0 to indicate a successful probe. (Note that an image that implements layering will fail the probe early because of the feature chekc.) Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 0f260a6..8f56d37 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3014,7 +3014,7 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev) dout("discovered version 2 image, header name is %s\n", rbd_dev->header_name); - return -ENOTSUPP; + return 0; out_err: kfree(rbd_dev->header_name); rbd_dev->header_name = NULL; -- cgit v0.10.2 From 9493d974b0f1f34903adfb529a510d4d768493dc Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Wed, 10 Oct 2012 09:34:00 -0700 Subject: Input: cy8ctmg110_ts - use C99-style structure initializators Convert the struct i2c_msg initialization to C99 format. This makes maintaining and editing the code simpler. Also helps once other fields like transferred are added in future. Thanks to Julia Lawall for automating the conversion. Signed-off-by: Shubhrajyoti D Acked-by: Jean Delvare Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 464f1bf..ad6a664 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -99,9 +99,18 @@ static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc, int ret; struct i2c_msg msg[2] = { /* first write slave position to i2c devices */ - { client->addr, 0, 1, &cmd }, + { + .addr = client->addr, + .len = 1, + .buf = &cmd + }, /* Second read data from position */ - { client->addr, I2C_M_RD, len, data } + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data + } }; ret = i2c_transfer(client->adapter, msg, 2); -- cgit v0.10.2 From 24e491c21b4e214a980a5daf2a5bc80e8c410ce6 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Wed, 10 Oct 2012 09:35:38 -0700 Subject: Input: as5011 - use C99-style structure initializators Convert the struct i2c_msg initialization to C99 format. This makes maintaining and editing the code simpler. Also helps once other fields like transferred are added in future. Thanks to Julia Lawall for automating the conversion. Signed-off-by: Shubhrajyoti D Acked-by: Jean Delvare Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index c96653b..9d869e2 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -85,7 +85,10 @@ static int as5011_i2c_write(struct i2c_client *client, { uint8_t data[2] = { aregaddr, avalue }; struct i2c_msg msg = { - client->addr, I2C_M_IGNORE_NAK, 2, (uint8_t *)data + .addr = client->addr, + .flags = I2C_M_IGNORE_NAK, + .len = 2, + .buf = (uint8_t *)data }; int error; @@ -98,8 +101,18 @@ static int as5011_i2c_read(struct i2c_client *client, { uint8_t data[2] = { aregaddr }; struct i2c_msg msg_set[2] = { - { client->addr, I2C_M_REV_DIR_ADDR, 1, (uint8_t *)data }, - { client->addr, I2C_M_RD | I2C_M_NOSTART, 1, (uint8_t *)data } + { + .addr = client->addr, + .flags = I2C_M_REV_DIR_ADDR, + .len = 1, + .buf = (uint8_t *)data + }, + { + .addr = client->addr, + .flags = I2C_M_RD | I2C_M_NOSTART, + .len = 1, + .buf = (uint8_t *)data + } }; int error; -- cgit v0.10.2 From 2f7badb9742f88e7307d9e823f40c8621ceaa1c4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Oct 2012 00:42:24 -0700 Subject: Input: wm831x-ts - remove unneeded clearing of driver data This is unneeded, only a bound driver can use driver data and a driver relying on the state prior to probe() is buggy. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index e834107..ac667e4 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -390,7 +390,6 @@ static __devexit int wm831x_ts_remove(struct platform_device *pdev) input_unregister_device(wm831x_ts->input_dev); kfree(wm831x_ts); - platform_set_drvdata(pdev, NULL); return 0; } -- cgit v0.10.2 From ef8dee5cfe4df1091419e7d58b902e7e3d90b00e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Oct 2012 00:42:34 -0700 Subject: Input: wm831x-ts - convert to devm_kzalloc() Saves a little code and eliminates the possibility of introducing some leaks. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index ac667e4..362f78d 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -245,7 +245,8 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) if (core_pdata) pdata = core_pdata->touch; - wm831x_ts = kzalloc(sizeof(struct wm831x_ts), GFP_KERNEL); + wm831x_ts = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ts), + GFP_KERNEL); input_dev = input_allocate_device(); if (!wm831x_ts || !input_dev) { error = -ENOMEM; @@ -376,7 +377,6 @@ err_data_irq: free_irq(wm831x_ts->data_irq, wm831x_ts); err_alloc: input_free_device(input_dev); - kfree(wm831x_ts); return error; } @@ -388,7 +388,6 @@ static __devexit int wm831x_ts_remove(struct platform_device *pdev) free_irq(wm831x_ts->pd_irq, wm831x_ts); free_irq(wm831x_ts->data_irq, wm831x_ts); input_unregister_device(wm831x_ts->input_dev); - kfree(wm831x_ts); return 0; } -- cgit v0.10.2 From dae6ba4ab797ed411fbde60ef5b5f6fbf13f0090 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Oct 2012 00:42:34 -0700 Subject: Input: wm831x-on - convert to devm_kzalloc() Saves a small amount of code and reduces the potential for leaks. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c index 6790a81..fa8b390 100644 --- a/drivers/input/misc/wm831x-on.c +++ b/drivers/input/misc/wm831x-on.c @@ -76,7 +76,8 @@ static int __devinit wm831x_on_probe(struct platform_device *pdev) int irq = wm831x_irq(wm831x, platform_get_irq(pdev, 0)); int ret; - wm831x_on = kzalloc(sizeof(struct wm831x_on), GFP_KERNEL); + wm831x_on = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_on), + GFP_KERNEL); if (!wm831x_on) { dev_err(&pdev->dev, "Can't allocate data\n"); return -ENOMEM; @@ -120,7 +121,6 @@ err_irq: err_input_dev: input_free_device(wm831x_on->dev); err: - kfree(wm831x_on); return ret; } @@ -132,7 +132,6 @@ static int __devexit wm831x_on_remove(struct platform_device *pdev) free_irq(irq, wm831x_on); cancel_delayed_work_sync(&wm831x_on->work); input_unregister_device(wm831x_on->dev); - kfree(wm831x_on); return 0; } -- cgit v0.10.2 From ad5396ee32afbdabb6188ffba67778080ea795b8 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 11 Oct 2012 01:03:50 -0700 Subject: Input: mms114 - add device tree bindings Add device tree bindings for mms114 touchscreen. [Dmitry Torokhov: added #ifdef CONFIG_OF guards] Signed-off-by: Tomasz Figa Signed-off-by: Dmitry Torokhov diff --git a/Documentation/devicetree/bindings/input/touchscreen/mms114.txt b/Documentation/devicetree/bindings/input/touchscreen/mms114.txt new file mode 100644 index 0000000..89d4c56 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/mms114.txt @@ -0,0 +1,34 @@ +* MELFAS MMS114 touchscreen controller + +Required properties: +- compatible: must be "melfas,mms114" +- reg: I2C address of the chip +- interrupts: interrupt to which the chip is connected +- x-size: horizontal resolution of touchscreen +- y-size: vertical resolution of touchscreen + +Optional properties: +- contact-threshold: +- moving-threshold: +- x-invert: invert X axis +- y-invert: invert Y axis + +Example: + + i2c@00000000 { + /* ... */ + + touchscreen@48 { + compatible = "melfas,mms114"; + reg = <0x48>; + interrupts = <39 0>; + x-size = <720>; + y-size = <1280>; + contact-threshold = <10>; + moving-threshold = <10>; + x-invert; + y-invert; + }; + + /* ... */ + }; diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 560cf09..3426d2e 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -360,14 +361,63 @@ static void mms114_input_close(struct input_dev *dev) mms114_stop(data); } +#ifdef CONFIG_OF +static struct mms114_platform_data * __devinit mms114_parse_dt(struct device *dev) +{ + struct mms114_platform_data *pdata; + struct device_node *np = dev->of_node; + + if (!np) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "failed to allocate platform data\n"); + return NULL; + } + + if (of_property_read_u32(np, "x-size", &pdata->x_size)) { + dev_err(dev, "failed to get x-size property\n"); + return NULL; + }; + + if (of_property_read_u32(np, "y-size", &pdata->y_size)) { + dev_err(dev, "failed to get y-size property\n"); + return NULL; + }; + + of_property_read_u32(np, "contact-threshold", + &pdata->contact_threshold); + of_property_read_u32(np, "moving-threshold", + &pdata->moving_threshold); + + if (of_find_property(np, "x-invert", NULL)) + pdata->x_invert = true; + if (of_find_property(np, "y-invert", NULL)) + pdata->y_invert = true; + + return pdata; +} +#else +static inline struct mms114_platform_data *mms114_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + static int __devinit mms114_probe(struct i2c_client *client, const struct i2c_device_id *id) { + const struct mms114_platform_data *pdata; struct mms114_data *data; struct input_dev *input_dev; int error; - if (!client->dev.platform_data) { + pdata = dev_get_platdata(&client->dev); + if (!pdata) + pdata = mms114_parse_dt(&client->dev); + + if (!pdata) { dev_err(&client->dev, "Need platform data\n"); return -EINVAL; } @@ -389,7 +439,7 @@ static int __devinit mms114_probe(struct i2c_client *client, data->client = client; data->input_dev = input_dev; - data->pdata = client->dev.platform_data; + data->pdata = pdata; input_dev->name = "MELPAS MMS114 Touchscreen"; input_dev->id.bustype = BUS_I2C; @@ -525,11 +575,19 @@ static const struct i2c_device_id mms114_id[] = { }; MODULE_DEVICE_TABLE(i2c, mms114_id); +#ifdef CONFIG_OF +static struct of_device_id __devinitdata mms114_dt_match[] = { + { .compatible = "melfas,mms114" }, + { } +}; +#endif + static struct i2c_driver mms114_driver = { .driver = { .name = "mms114", .owner = THIS_MODULE, .pm = &mms114_pm_ops, + .of_match_table = of_match_ptr(mms114_dt_match), }, .probe = mms114_probe, .remove = __devexit_p(mms114_remove), -- cgit v0.10.2 From b6755ffb0c03c2e763cc56f72cc2ceaba8ea2805 Mon Sep 17 00:00:00 2001 From: Sachin Bhamare Date: Thu, 9 Feb 2012 17:09:32 -0800 Subject: osduld: Add osdname & systemid sysfs at scsi_osd class This patch adds the support for following two read-only sysfs attributes to scsi_osd class members : osdname & systemid These attributes will show up as below in sysfs class hierarchy: /sys/class/scsi_osd/osdX/osdname /sys/class/scsi_osd/osdX/systemid The osdname & systemid are OSD device attributes which uniquely identify a device on the network, while it's IP and certainly it's /dev/osdX device path might change. Userspace utilities (e.g. mkfs.exofs) can parse these attributes to identify the correct OSD in safer and faster way. (Today osd apps open each device in the system and send a attributes query for these, in order to access the user requested device) Signed-off-by: Sachin Bhamare Signed-off-by: Boaz Harrosh diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index d4ed9eb..4375417 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c @@ -97,9 +97,37 @@ struct osd_dev_handle { static DEFINE_IDA(osd_minor_ida); +/* + * scsi sysfs attribute operations + */ +static ssize_t osdname_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct osd_uld_device *ould = container_of(dev, struct osd_uld_device, + class_dev); + return sprintf(buf, "%s\n", ould->odi.osdname); +} + +static ssize_t systemid_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct osd_uld_device *ould = container_of(dev, struct osd_uld_device, + class_dev); + + memcpy(buf, ould->odi.systemid, ould->odi.systemid_len); + return ould->odi.systemid_len; +} + +static struct device_attribute osd_uld_attrs[] = { + __ATTR(osdname, S_IRUGO, osdname_show, NULL), + __ATTR(systemid, S_IRUGO, systemid_show, NULL), + __ATTR_NULL, +}; + static struct class osd_uld_class = { .owner = THIS_MODULE, .name = "scsi_osd", + .dev_attrs = osd_uld_attrs, }; /* -- cgit v0.10.2 From be5b779ae9ce64ede0a8f4939360b0320bb257e2 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 15 Oct 2012 23:42:55 +0200 Subject: random: make it possible to enable debugging without rebuild The module parameter that turns debugging mode (which basically means printing a few extra lines during runtime) is in '#if 0' block. Forcing everyone who would like to see how entropy is behaving on his system to rebuild seems to be a little bit too harsh. If we were concerned about speed, we could potentially turn 'debug' into a static key, but I don't think it's necessary. Drop the '#if 0' block to allow using the 'debug' parameter without rebuilding. Signed-off-by: Jiri Kosina Signed-off-by: Theodore Ts'o diff --git a/drivers/char/random.c b/drivers/char/random.c index b86eae9..9ac4443 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -399,7 +399,6 @@ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); static struct fasync_struct *fasync; -#if 0 static bool debug; module_param(debug, bool, 0644); #define DEBUG_ENT(fmt, arg...) do { \ @@ -410,9 +409,6 @@ module_param(debug, bool, 0644); blocking_pool.entropy_count,\ nonblocking_pool.entropy_count,\ ## arg); } while (0) -#else -#define DEBUG_ENT(fmt, arg...) do {} while (0) -#endif /********************************************************************** * -- cgit v0.10.2 From 197a1e96c8be5b6005145af3a4c0e45e2d651444 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 17 Oct 2012 23:55:34 -0700 Subject: Input: i8042-io - fix up region handling on MIPS i8042_platform_init() skips reguest_region() on MIPS, but in i8042_platform_exit() release_region() is still called. Fix this by reserving the region also on MIPS. The patch eliminates the following error message seen on MIPS: [ 2.112000] Trying to free nonexistent resource <0000000000000060-000000000000006f> Signed-off-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index 5d48bb6..a5eed2a 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -76,7 +76,7 @@ static inline int i8042_platform_init(void) if (check_legacy_ioport(I8042_DATA_REG)) return -ENODEV; #endif -#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) +#if !defined(__sh__) && !defined(__alpha__) if (!request_region(I8042_DATA_REG, 16, "i8042")) return -EBUSY; #endif -- cgit v0.10.2 From f6c0df6acbfc49abe0fe593936f170cc726e21fb Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 17 Oct 2012 23:55:54 -0700 Subject: Input: edt-ft5x06 - convert to use simple_open() This removes an open coded simple_open() function and replaces file operations references to the function with simple_open() instead. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 7b786e7..bcaea7a 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -491,14 +491,6 @@ static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode) DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get, edt_ft5x06_debugfs_mode_set, "%llu\n"); -static int edt_ft5x06_debugfs_raw_data_open(struct inode *inode, - struct file *file) -{ - file->private_data = inode->i_private; - - return 0; -} - static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, char __user *buf, size_t count, loff_t *off) { @@ -576,7 +568,7 @@ out: static const struct file_operations debugfs_raw_data_fops = { - .open = edt_ft5x06_debugfs_raw_data_open, + .open = simple_open, .read = edt_ft5x06_debugfs_raw_data_read, }; -- cgit v0.10.2 From 837d678dc264c797c16f81cf56f615f7544891c1 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Thu, 16 Aug 2012 00:02:40 +0900 Subject: slub: remove one code path and reduce lock contention in __slab_free() When we try to free object, there is some of case that we need to take a node lock. This is the necessary step for preventing a race. After taking a lock, then we try to cmpxchg_double_slab(). But, there is a possible scenario that cmpxchg_double_slab() is failed with taking a lock. Following example explains it. CPU A CPU B need lock ... need lock ... lock!! lock..but spin free success spin... unlock lock!! free fail In this case, retry with taking a lock is occured in CPU A. I think that in this case for CPU A, "release a lock first, and re-take a lock if necessary" is preferable way. There are two reasons for this. First, this makes __slab_free()'s logic somehow simple. With this patch, 'was_frozen = 1' is "always" handled without taking a lock. So we can remove one code path. Second, it may reduce lock contention. When we do retrying, status of slab is already changed, so we don't need a lock anymore in almost every case. "release a lock first, and re-take a lock if necessary" policy is helpful to this. Signed-off-by: Joonsoo Kim Acked-by: Christoph Lameter Signed-off-by: Pekka Enberg diff --git a/mm/slub.c b/mm/slub.c index a0d6984..e7aec20 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2459,7 +2459,6 @@ static void __slab_free(struct kmem_cache *s, struct page *page, void *prior; void **object = (void *)x; int was_frozen; - int inuse; struct page new; unsigned long counters; struct kmem_cache_node *n = NULL; @@ -2472,13 +2471,17 @@ static void __slab_free(struct kmem_cache *s, struct page *page, return; do { + if (unlikely(n)) { + spin_unlock_irqrestore(&n->list_lock, flags); + n = NULL; + } prior = page->freelist; counters = page->counters; set_freepointer(s, object, prior); new.counters = counters; was_frozen = new.frozen; new.inuse--; - if ((!new.inuse || !prior) && !was_frozen && !n) { + if ((!new.inuse || !prior) && !was_frozen) { if (!kmem_cache_debug(s) && !prior) @@ -2503,7 +2506,6 @@ static void __slab_free(struct kmem_cache *s, struct page *page, } } - inuse = new.inuse; } while (!cmpxchg_double_slab(s, page, prior, counters, @@ -2529,25 +2531,17 @@ static void __slab_free(struct kmem_cache *s, struct page *page, return; } + if (unlikely(!new.inuse && n->nr_partial > s->min_partial)) + goto slab_empty; + /* - * was_frozen may have been set after we acquired the list_lock in - * an earlier loop. So we need to check it here again. + * Objects left in the slab. If it was not on the partial list before + * then add it. */ - if (was_frozen) - stat(s, FREE_FROZEN); - else { - if (unlikely(!inuse && n->nr_partial > s->min_partial)) - goto slab_empty; - - /* - * Objects left in the slab. If it was not on the partial list before - * then add it. - */ - if (unlikely(!prior)) { - remove_full(s, page); - add_partial(n, page, DEACTIVATE_TO_TAIL); - stat(s, FREE_ADD_PARTIAL); - } + if (kmem_cache_debug(s) && unlikely(!prior)) { + remove_full(s, page); + add_partial(n, page, DEACTIVATE_TO_TAIL); + stat(s, FREE_ADD_PARTIAL); } spin_unlock_irqrestore(&n->list_lock, flags); return; -- cgit v0.10.2 From f0263d2d222e9e25f2587e51a9dc58c6fb2a9352 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 19 Oct 2012 14:03:31 +0100 Subject: mm: highmem: export kmap_to_page for modules Some virtio device drivers (9p) need to translate high virtual addresses to physical addresses, which are inserted into the virtqueue for processing by userspace. This patch exports the kmap_to_page symbol, so that the affected drivers can be compiled as modules. Cc: stable@kernel.org Signed-off-by: Will Deacon Signed-off-by: Rusty Russell diff --git a/mm/highmem.c b/mm/highmem.c index d517cd1..2a07f97 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -105,6 +105,7 @@ struct page *kmap_to_page(void *vaddr) return virt_to_page(addr); } +EXPORT_SYMBOL(kmap_to_page); static void flush_all_zero_pkmaps(void) { -- cgit v0.10.2 From b9cdc88df8e63e81c723b82c286fc97f5d0dc325 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 19 Oct 2012 14:03:32 +0100 Subject: virtio: 9p: correctly pass physical address to userspace for high pages When using a virtio transport, the 9p net device may pass the physical address of a kernel buffer to userspace via a scatterlist inside a virtqueue. If the kernel buffer is mapped outside of the linear mapping (e.g. highmem), then virt_to_page will return a bogus value and we will populate the scatterlist with junk. This patch uses kmap_to_page when populating the page array for a kernel buffer. Cc: stable@kernel.org Cc: Sasha Levin Signed-off-by: Will Deacon Signed-off-by: Rusty Russell diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 35b8911..fd05c81 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -325,7 +326,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan, int count = nr_pages; while (nr_pages) { s = rest_of_page(data); - pages[index++] = virt_to_page(data); + pages[index++] = kmap_to_page(data); data += s; nr_pages--; } -- cgit v0.10.2 From b92b1b89a33c172c075edccf6afb0edc41d851fd Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 19 Oct 2012 14:03:33 +0100 Subject: virtio: force vring descriptors to be allocated from lowmem Virtio devices may attempt to add descriptors to a virtqueue from atomic context using GFP_ATOMIC allocation. This is problematic because such allocations can fall outside of the lowmem mapping, causing virt_to_phys to report bogus physical addresses which are subsequently passed to userspace via the buffers for the virtual device. This patch masks out __GFP_HIGH and __GFP_HIGHMEM from the requested flags when allocating descriptors for a virtqueue. If an atomic allocation is requested and later fails, we will return -ENOSPC which will be handled by the driver. Cc: stable@kernel.org Cc: Sasha Levin Signed-off-by: Will Deacon Signed-off-by: Rusty Russell diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index e639584..286c30c 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -135,6 +135,13 @@ static int vring_add_indirect(struct vring_virtqueue *vq, unsigned head; int i; + /* + * We require lowmem mappings for the descriptors because + * otherwise virt_to_phys will give us bogus addresses in the + * virtqueue. + */ + gfp &= ~(__GFP_HIGHMEM | __GFP_HIGH); + desc = kmalloc((out + in) * sizeof(struct vring_desc), gfp); if (!desc) return -ENOMEM; -- cgit v0.10.2 From 7e05484f02e1ea05a3aae0724d4df1e8a5a1920f Mon Sep 17 00:00:00 2001 From: Bryan Venteicher Date: Tue, 16 Oct 2012 23:55:54 +1030 Subject: virtio-scsi: Add real 2-clause BSD license to header This is analogous to commit a1b383870a made by Rusty Russell to all the VirtIO headers at the time. This eases the use of the header as is by other OSes. Signed-off-by: Bryan Venteicher Acked-by: Paolo Bonzini Signed-off-by: Rusty Russell diff --git a/include/linux/virtio_scsi.h b/include/linux/virtio_scsi.h index d6b4440..4195b97 100644 --- a/include/linux/virtio_scsi.h +++ b/include/linux/virtio_scsi.h @@ -1,7 +1,31 @@ +/* + * This header is BSD licensed so anyone can use the definitions to implement + * compatible drivers/servers. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + #ifndef _LINUX_VIRTIO_SCSI_H #define _LINUX_VIRTIO_SCSI_H -/* This header is BSD licensed so anyone can use the definitions to implement - * compatible drivers/servers. */ #define VIRTIO_SCSI_CDB_SIZE 32 #define VIRTIO_SCSI_SENSE_SIZE 96 -- cgit v0.10.2 From c0316a945ae3df1a9c9d1fb44ac3eb47f16d9cd9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 16 Oct 2012 23:56:13 +1030 Subject: lguest: fix block request handling in example launcher. virtio requests are scatter-gather-style descriptors, but no assumptions should be made about the layout. lguest was lazy here, but saved by the fact that the network device hands all requests to tun (which does it correctly) and console and random devices simply use readv and writev. Block devices, however, are broken: we convert to iovecs internally, just make sure we handle the correctly. Signed-off-by: Rusty Russell diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index fd2f922..07a0345 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c @@ -179,29 +179,6 @@ static struct termios orig_term; #define wmb() __asm__ __volatile__("" : : : "memory") #define mb() __asm__ __volatile__("" : : : "memory") -/* - * Convert an iovec element to the given type. - * - * This is a fairly ugly trick: we need to know the size of the type and - * alignment requirement to check the pointer is kosher. It's also nice to - * have the name of the type in case we report failure. - * - * Typing those three things all the time is cumbersome and error prone, so we - * have a macro which sets them all up and passes to the real function. - */ -#define convert(iov, type) \ - ((type *)_convert((iov), sizeof(type), __alignof__(type), #type)) - -static void *_convert(struct iovec *iov, size_t size, size_t align, - const char *name) -{ - if (iov->iov_len != size) - errx(1, "Bad iovec size %zu for %s", iov->iov_len, name); - if ((unsigned long)iov->iov_base % align != 0) - errx(1, "Bad alignment %p for %s", iov->iov_base, name); - return iov->iov_base; -} - /* Wrapper for the last available index. Makes it easier to change. */ #define lg_last_avail(vq) ((vq)->last_avail_idx) @@ -228,7 +205,8 @@ static bool iov_empty(const struct iovec iov[], unsigned int num_iov) } /* Take len bytes from the front of this iovec. */ -static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len) +static void iov_consume(struct iovec iov[], unsigned num_iov, + void *dest, unsigned len) { unsigned int i; @@ -236,11 +214,16 @@ static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len) unsigned int used; used = iov[i].iov_len < len ? iov[i].iov_len : len; + if (dest) { + memcpy(dest, iov[i].iov_base, used); + dest += used; + } iov[i].iov_base += used; iov[i].iov_len -= used; len -= used; } - assert(len == 0); + if (len != 0) + errx(1, "iovec too short!"); } /* The device virtqueue descriptors are followed by feature bitmasks. */ @@ -864,7 +847,7 @@ static void console_output(struct virtqueue *vq) warn("Write to stdout gave %i (%d)", len, errno); break; } - iov_consume(iov, out, len); + iov_consume(iov, out, NULL, len); } /* @@ -1591,9 +1574,9 @@ static void blk_request(struct virtqueue *vq) { struct vblk_info *vblk = vq->dev->priv; unsigned int head, out_num, in_num, wlen; - int ret; + int ret, i; u8 *in; - struct virtio_blk_outhdr *out; + struct virtio_blk_outhdr out; struct iovec iov[vq->vring.num]; off64_t off; @@ -1603,32 +1586,36 @@ static void blk_request(struct virtqueue *vq) */ head = wait_for_vq_desc(vq, iov, &out_num, &in_num); - /* - * Every block request should contain at least one output buffer - * (detailing the location on disk and the type of request) and one - * input buffer (to hold the result). - */ - if (out_num == 0 || in_num == 0) - errx(1, "Bad virtblk cmd %u out=%u in=%u", - head, out_num, in_num); + /* Copy the output header from the front of the iov (adjusts iov) */ + iov_consume(iov, out_num, &out, sizeof(out)); + + /* Find and trim end of iov input array, for our status byte. */ + in = NULL; + for (i = out_num + in_num - 1; i >= out_num; i--) { + if (iov[i].iov_len > 0) { + in = iov[i].iov_base + iov[i].iov_len - 1; + iov[i].iov_len--; + break; + } + } + if (!in) + errx(1, "Bad virtblk cmd with no room for status"); - out = convert(&iov[0], struct virtio_blk_outhdr); - in = convert(&iov[out_num+in_num-1], u8); /* * For historical reasons, block operations are expressed in 512 byte * "sectors". */ - off = out->sector * 512; + off = out.sector * 512; /* * In general the virtio block driver is allowed to try SCSI commands. * It'd be nice if we supported eject, for example, but we don't. */ - if (out->type & VIRTIO_BLK_T_SCSI_CMD) { + if (out.type & VIRTIO_BLK_T_SCSI_CMD) { fprintf(stderr, "Scsi commands unsupported\n"); *in = VIRTIO_BLK_S_UNSUPP; wlen = sizeof(*in); - } else if (out->type & VIRTIO_BLK_T_OUT) { + } else if (out.type & VIRTIO_BLK_T_OUT) { /* * Write * @@ -1636,10 +1623,10 @@ static void blk_request(struct virtqueue *vq) * if they try to write past end. */ if (lseek64(vblk->fd, off, SEEK_SET) != off) - err(1, "Bad seek to sector %llu", out->sector); + err(1, "Bad seek to sector %llu", out.sector); - ret = writev(vblk->fd, iov+1, out_num-1); - verbose("WRITE to sector %llu: %i\n", out->sector, ret); + ret = writev(vblk->fd, iov, out_num); + verbose("WRITE to sector %llu: %i\n", out.sector, ret); /* * Grr... Now we know how long the descriptor they sent was, we @@ -1655,7 +1642,7 @@ static void blk_request(struct virtqueue *vq) wlen = sizeof(*in); *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); - } else if (out->type & VIRTIO_BLK_T_FLUSH) { + } else if (out.type & VIRTIO_BLK_T_FLUSH) { /* Flush */ ret = fdatasync(vblk->fd); verbose("FLUSH fdatasync: %i\n", ret); @@ -1669,10 +1656,9 @@ static void blk_request(struct virtqueue *vq) * if they try to read past end. */ if (lseek64(vblk->fd, off, SEEK_SET) != off) - err(1, "Bad seek to sector %llu", out->sector); + err(1, "Bad seek to sector %llu", out.sector); - ret = readv(vblk->fd, iov+1, in_num-1); - verbose("READ from sector %llu: %i\n", out->sector, ret); + ret = readv(vblk->fd, iov + out_num, in_num); if (ret >= 0) { wlen = sizeof(*in) + ret; *in = VIRTIO_BLK_S_OK; @@ -1758,7 +1744,7 @@ static void rng_input(struct virtqueue *vq) len = readv(rng_info->rfd, iov, in_num); if (len <= 0) err(1, "Read from /dev/random gave %i", len); - iov_consume(iov, in_num, len); + iov_consume(iov, in_num, NULL, len); totlen += len; } -- cgit v0.10.2 From e4b290094603423623d3f268e054f40f3f51afa8 Mon Sep 17 00:00:00 2001 From: Mischa Jonker Date: Mon, 22 Oct 2012 22:48:08 -0700 Subject: Input: serio - add ARC PS/2 driver This adds support for the PS/2 block that is used in various ARC FPGA platforms. Signed-off-by: Mischa Jonker Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 55f2c22..4a4e182 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -234,4 +234,13 @@ config SERIO_PS2MULT To compile this driver as a module, choose M here: the module will be called ps2mult. +config SERIO_ARC_PS2 + tristate "ARC PS/2 support" + help + Say Y here if you have an ARC FPGA platform with a PS/2 + controller in it. + + To compile this driver as a module, choose M here; the module + will be called arc_ps2. + endif diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index dbbe376..4b0c8f8 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_SERIO_RAW) += serio_raw.o obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o +obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c new file mode 100644 index 0000000..f8c026a --- /dev/null +++ b/drivers/input/serio/arc_ps2.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Driver is originally developed by Pavel Sokolov + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARC_PS2_PORTS 2 + +#define ARC_ARC_PS2_ID 0x0001f609 + +#define STAT_TIMEOUT 128 + +#define PS2_STAT_RX_FRM_ERR (1) +#define PS2_STAT_RX_BUF_OVER (1 << 1) +#define PS2_STAT_RX_INT_EN (1 << 2) +#define PS2_STAT_RX_VAL (1 << 3) +#define PS2_STAT_TX_ISNOT_FUL (1 << 4) +#define PS2_STAT_TX_INT_EN (1 << 5) + +struct arc_ps2_port { + void __iomem *data_addr; + void __iomem *status_addr; + struct serio *io; +}; + +struct arc_ps2_data { + struct arc_ps2_port port[ARC_PS2_PORTS]; + struct resource *iomem_res; + int irq; + void __iomem *addr; + unsigned int frame_error; + unsigned int buf_overflow; + unsigned int total_int; +}; + +static void arc_ps2_check_rx(struct arc_ps2_data *arc_ps2, + struct arc_ps2_port *port) +{ + unsigned int timeout = 1000; + unsigned int flag, status; + unsigned char data; + + do { + status = ioread32(port->status_addr); + if (!(status & PS2_STAT_RX_VAL)) + return; + + data = ioread32(port->data_addr) & 0xff; + + flag = 0; + arc_ps2->total_int++; + if (status & PS2_STAT_RX_FRM_ERR) { + arc_ps2->frame_error++; + flag |= SERIO_PARITY; + } else if (status & PS2_STAT_RX_BUF_OVER) { + arc_ps2->buf_overflow++; + flag |= SERIO_FRAME; + } + + serio_interrupt(port->io, data, flag); + } while (--timeout); + + dev_err(&port->io->dev, "PS/2 hardware stuck\n"); +} + +static irqreturn_t arc_ps2_interrupt(int irq, void *dev) +{ + struct arc_ps2_data *arc_ps2 = dev; + int i; + + for (i = 0; i < ARC_PS2_PORTS; i++) + arc_ps2_check_rx(arc_ps2, &arc_ps2->port[i]); + + return IRQ_HANDLED; +} + +static int arc_ps2_write(struct serio *io, unsigned char val) +{ + unsigned status; + struct arc_ps2_port *port = io->port_data; + int timeout = STAT_TIMEOUT; + + do { + status = ioread32(port->status_addr); + cpu_relax(); + + if (status & PS2_STAT_TX_ISNOT_FUL) { + iowrite32(val & 0xff, port->data_addr); + return 0; + } + + } while (--timeout); + + dev_err(&io->dev, "write timeout\n"); + return -ETIMEDOUT; +} + +static int arc_ps2_open(struct serio *io) +{ + struct arc_ps2_port *port = io->port_data; + + iowrite32(PS2_STAT_RX_INT_EN, port->status_addr); + + return 0; +} + +static void arc_ps2_close(struct serio *io) +{ + struct arc_ps2_port *port = io->port_data; + + iowrite32(ioread32(port->status_addr) & ~PS2_STAT_RX_INT_EN, + port->status_addr); +} + +static int __devinit arc_ps2_create_port(struct platform_device *pdev, + struct arc_ps2_data *arc_ps2, + int index) +{ + struct arc_ps2_port *port = &arc_ps2->port[index]; + struct serio *io; + + io = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!io) + return -ENOMEM; + + io->id.type = SERIO_8042; + io->write = arc_ps2_write; + io->open = arc_ps2_open; + io->close = arc_ps2_close; + snprintf(io->name, sizeof(io->name), "ARC PS/2 port%d", index); + snprintf(io->phys, sizeof(io->phys), "arc/serio%d", index); + io->port_data = port; + + port->io = io; + + port->data_addr = arc_ps2->addr + 4 + index * 4; + port->status_addr = arc_ps2->addr + 4 + ARC_PS2_PORTS * 4 + index * 4; + + dev_dbg(&pdev->dev, "port%d is allocated (data = 0x%p, status = 0x%p)\n", + index, port->data_addr, port->status_addr); + + serio_register_port(port->io); + return 0; +} + +static int __devinit arc_ps2_probe(struct platform_device *pdev) +{ + struct arc_ps2_data *arc_ps2; + int error, id, i; + + arc_ps2 = kzalloc(sizeof(struct arc_ps2_data), GFP_KERNEL); + if (!arc_ps2) { + dev_err(&pdev->dev, "out of memory\n"); + return -ENOMEM; + } + + arc_ps2->iomem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!arc_ps2->iomem_res) { + dev_err(&pdev->dev, "no IO memory defined\n"); + error = -EINVAL; + goto err_free_mem; + } + + arc_ps2->irq = platform_get_irq_byname(pdev, "arc_ps2_irq"); + if (arc_ps2->irq < 0) { + dev_err(&pdev->dev, "no IRQ defined\n"); + error = -EINVAL; + goto err_free_mem; + } + + if (!request_mem_region(arc_ps2->iomem_res->start, + resource_size(arc_ps2->iomem_res), pdev->name)) { + dev_err(&pdev->dev, "memory region allocation failed for %pR\n", + arc_ps2->iomem_res); + + error = -EBUSY; + goto err_free_mem; + } + + arc_ps2->addr = ioremap_nocache(arc_ps2->iomem_res->start, + resource_size(arc_ps2->iomem_res)); + if (!arc_ps2->addr) { + dev_err(&pdev->dev, "memory mapping failed\n"); + error = -ENOMEM; + goto err_release_region; + } + + dev_info(&pdev->dev, "irq = %d, address = 0x%p, ports = %i\n", + arc_ps2->irq, arc_ps2->addr, ARC_PS2_PORTS); + + id = ioread32(arc_ps2->addr); + if (id != ARC_ARC_PS2_ID) { + dev_err(&pdev->dev, "device id does not match\n"); + error = -ENXIO; + goto err_unmap; + } + + for (i = 0; i < ARC_PS2_PORTS; i++) { + error = arc_ps2_create_port(pdev, arc_ps2, i); + if (error) + goto err_unregister_ports; + } + + error = request_irq(arc_ps2->irq, arc_ps2_interrupt, 0, + "arc_ps2", arc_ps2); + if (error) { + dev_err(&pdev->dev, "Could not allocate IRQ\n"); + goto err_unregister_ports; + } + + platform_set_drvdata(pdev, arc_ps2); + + return 0; + +err_unregister_ports: + for (i = 0; i < ARC_PS2_PORTS; i++) { + if (arc_ps2->port[i].io) + serio_unregister_port(arc_ps2->port[i].io); + } +err_unmap: + iounmap(arc_ps2->addr); +err_release_region: + release_mem_region(arc_ps2->iomem_res->start, + resource_size(arc_ps2->iomem_res)); +err_free_mem: + kfree(arc_ps2); + return error; +} + +static int __devexit arc_ps2_remove(struct platform_device *pdev) +{ + struct arc_ps2_data *arc_ps2 = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < ARC_PS2_PORTS; i++) + serio_unregister_port(arc_ps2->port[i].io); + + free_irq(arc_ps2->irq, arc_ps2); + iounmap(arc_ps2->addr); + release_mem_region(arc_ps2->iomem_res->start, + resource_size(arc_ps2->iomem_res)); + + dev_dbg(&pdev->dev, "interrupt count = %i\n", arc_ps2->total_int); + dev_dbg(&pdev->dev, "frame error count = %i\n", arc_ps2->frame_error); + dev_dbg(&pdev->dev, "buffer overflow count = %i\n", + arc_ps2->buf_overflow); + + kfree(arc_ps2); + + return 0; +} + +static struct platform_driver arc_ps2_driver = { + .driver = { + .name = "arc_ps2", + .owner = THIS_MODULE, + }, + .probe = arc_ps2_probe, + .remove = __devexit_p(arc_ps2_remove), +}; + +module_platform_driver(arc_ps2_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pavel Sokolov "); +MODULE_DESCRIPTION("ARC PS/2 Driver"); -- cgit v0.10.2 From b7454ad3cfc3043c5264729a6204f049fe1f34b1 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Fri, 19 Oct 2012 18:20:25 +0400 Subject: mm/sl[au]b: Move slabinfo processing to slab_common.c This patch moves all the common machinery to slabinfo processing to slab_common.c. We can do better by noticing that the output is heavily common, and having the allocators to just provide finished information about this. But after this first step, this can be done easier. Signed-off-by: Glauber Costa Acked-by: Christoph Lameter CC: David Rientjes Signed-off-by: Pekka Enberg diff --git a/mm/slab.c b/mm/slab.c index 33d3363..a6e045c 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -4277,7 +4277,7 @@ out: #ifdef CONFIG_SLABINFO -static void print_slabinfo_header(struct seq_file *m) +void print_slabinfo_header(struct seq_file *m) { /* * Output format version, so at least we can change it @@ -4300,28 +4300,7 @@ static void print_slabinfo_header(struct seq_file *m) seq_putc(m, '\n'); } -static void *s_start(struct seq_file *m, loff_t *pos) -{ - loff_t n = *pos; - - mutex_lock(&slab_mutex); - if (!n) - print_slabinfo_header(m); - - return seq_list_start(&slab_caches, *pos); -} - -static void *s_next(struct seq_file *m, void *p, loff_t *pos) -{ - return seq_list_next(p, &slab_caches, pos); -} - -static void s_stop(struct seq_file *m, void *p) -{ - mutex_unlock(&slab_mutex); -} - -static int s_show(struct seq_file *m, void *p) +int slabinfo_show(struct seq_file *m, void *p) { struct kmem_cache *cachep = list_entry(p, struct kmem_cache, list); struct slab *slabp; @@ -4418,27 +4397,6 @@ static int s_show(struct seq_file *m, void *p) return 0; } -/* - * slabinfo_op - iterator that generates /proc/slabinfo - * - * Output layout: - * cache-name - * num-active-objs - * total-objs - * object size - * num-active-slabs - * total-slabs - * num-pages-per-slab - * + further values on SMP and with statistics enabled - */ - -static const struct seq_operations slabinfo_op = { - .start = s_start, - .next = s_next, - .stop = s_stop, - .show = s_show, -}; - #define MAX_SLABINFO_WRITE 128 /** * slabinfo_write - Tuning for the slab allocator @@ -4447,7 +4405,7 @@ static const struct seq_operations slabinfo_op = { * @count: data length * @ppos: unused */ -static ssize_t slabinfo_write(struct file *file, const char __user *buffer, +ssize_t slabinfo_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { char kbuf[MAX_SLABINFO_WRITE + 1], *tmp; @@ -4490,19 +4448,6 @@ static ssize_t slabinfo_write(struct file *file, const char __user *buffer, return res; } -static int slabinfo_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &slabinfo_op); -} - -static const struct file_operations proc_slabinfo_operations = { - .open = slabinfo_open, - .read = seq_read, - .write = slabinfo_write, - .llseek = seq_lseek, - .release = seq_release, -}; - #ifdef CONFIG_DEBUG_SLAB_LEAK static void *leaks_start(struct seq_file *m, loff_t *pos) @@ -4631,6 +4576,16 @@ static int leaks_show(struct seq_file *m, void *p) return 0; } +static void *s_next(struct seq_file *m, void *p, loff_t *pos) +{ + return seq_list_next(p, &slab_caches, pos); +} + +static void s_stop(struct seq_file *m, void *p) +{ + mutex_unlock(&slab_mutex); +} + static const struct seq_operations slabstats_op = { .start = leaks_start, .next = s_next, @@ -4665,7 +4620,6 @@ static const struct file_operations proc_slabstats_operations = { static int __init slab_proc_init(void) { - proc_create("slabinfo",S_IWUSR|S_IRUSR,NULL,&proc_slabinfo_operations); #ifdef CONFIG_DEBUG_SLAB_LEAK proc_create("slab_allocators", 0, NULL, &proc_slabstats_operations); #endif diff --git a/mm/slab.h b/mm/slab.h index 7deeb44..dc78101 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -47,4 +47,12 @@ static inline struct kmem_cache *__kmem_cache_alias(const char *name, size_t siz int __kmem_cache_shutdown(struct kmem_cache *); +struct seq_file; +struct file; +void print_slabinfo_header(struct seq_file *m); + +int slabinfo_show(struct seq_file *m, void *p); + +ssize_t slabinfo_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos); #endif diff --git a/mm/slab_common.c b/mm/slab_common.c index 069a24e6..2e4b4c6 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -192,3 +194,71 @@ int slab_is_available(void) { return slab_state >= UP; } + +#ifdef CONFIG_SLABINFO +static void *s_start(struct seq_file *m, loff_t *pos) +{ + loff_t n = *pos; + + mutex_lock(&slab_mutex); + if (!n) + print_slabinfo_header(m); + + return seq_list_start(&slab_caches, *pos); +} + +static void *s_next(struct seq_file *m, void *p, loff_t *pos) +{ + return seq_list_next(p, &slab_caches, pos); +} + +static void s_stop(struct seq_file *m, void *p) +{ + mutex_unlock(&slab_mutex); +} + +static int s_show(struct seq_file *m, void *p) +{ + return slabinfo_show(m, p); +} + +/* + * slabinfo_op - iterator that generates /proc/slabinfo + * + * Output layout: + * cache-name + * num-active-objs + * total-objs + * object size + * num-active-slabs + * total-slabs + * num-pages-per-slab + * + further values on SMP and with statistics enabled + */ +static const struct seq_operations slabinfo_op = { + .start = s_start, + .next = s_next, + .stop = s_stop, + .show = s_show, +}; + +static int slabinfo_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &slabinfo_op); +} + +static const struct file_operations proc_slabinfo_operations = { + .open = slabinfo_open, + .read = seq_read, + .write = slabinfo_write, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init slab_proc_init(void) +{ + proc_create("slabinfo", S_IRUSR, NULL, &proc_slabinfo_operations); + return 0; +} +module_init(slab_proc_init); +#endif /* CONFIG_SLABINFO */ diff --git a/mm/slub.c b/mm/slub.c index a0d6984..77a0c8a 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5405,7 +5405,7 @@ __initcall(slab_sysfs_init); * The /proc/slabinfo ABI */ #ifdef CONFIG_SLABINFO -static void print_slabinfo_header(struct seq_file *m) +void print_slabinfo_header(struct seq_file *m) { seq_puts(m, "slabinfo - version: 2.1\n"); seq_puts(m, "# name " @@ -5415,28 +5415,7 @@ static void print_slabinfo_header(struct seq_file *m) seq_putc(m, '\n'); } -static void *s_start(struct seq_file *m, loff_t *pos) -{ - loff_t n = *pos; - - mutex_lock(&slab_mutex); - if (!n) - print_slabinfo_header(m); - - return seq_list_start(&slab_caches, *pos); -} - -static void *s_next(struct seq_file *m, void *p, loff_t *pos) -{ - return seq_list_next(p, &slab_caches, pos); -} - -static void s_stop(struct seq_file *m, void *p) -{ - mutex_unlock(&slab_mutex); -} - -static int s_show(struct seq_file *m, void *p) +int slabinfo_show(struct seq_file *m, void *p) { unsigned long nr_partials = 0; unsigned long nr_slabs = 0; @@ -5472,29 +5451,9 @@ static int s_show(struct seq_file *m, void *p) return 0; } -static const struct seq_operations slabinfo_op = { - .start = s_start, - .next = s_next, - .stop = s_stop, - .show = s_show, -}; - -static int slabinfo_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &slabinfo_op); -} - -static const struct file_operations proc_slabinfo_operations = { - .open = slabinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init slab_proc_init(void) +ssize_t slabinfo_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) { - proc_create("slabinfo", S_IRUSR, NULL, &proc_slabinfo_operations); - return 0; + return -EIO; } -module_init(slab_proc_init); #endif /* CONFIG_SLABINFO */ -- cgit v0.10.2 From bcee6e2a13d580f6c21d748fcd7239ccc66cb4b8 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Fri, 19 Oct 2012 18:20:26 +0400 Subject: mm/sl[au]b: Move print_slabinfo_header to slab_common.c The header format is highly similar between slab and slub. The main difference lays in the fact that slab may optionally have statistics added here in case of CONFIG_SLAB_DEBUG, while the slub will stick them somewhere else. By making sure that information conditionally lives inside a globally-visible CONFIG_DEBUG_SLAB switch, we can move the header printing to a common location. Signed-off-by: Glauber Costa Acked-by: Christoph Lameter CC: David Rientjes Signed-off-by: Pekka Enberg diff --git a/mm/slab.c b/mm/slab.c index a6e045c..73811ca 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -4276,30 +4276,6 @@ out: } #ifdef CONFIG_SLABINFO - -void print_slabinfo_header(struct seq_file *m) -{ - /* - * Output format version, so at least we can change it - * without _too_ many complaints. - */ -#if STATS - seq_puts(m, "slabinfo - version: 2.1 (statistics)\n"); -#else - seq_puts(m, "slabinfo - version: 2.1\n"); -#endif - seq_puts(m, "# name " - " "); - seq_puts(m, " : tunables "); - seq_puts(m, " : slabdata "); -#if STATS - seq_puts(m, " : globalstat " - " "); - seq_puts(m, " : cpustat "); -#endif - seq_putc(m, '\n'); -} - int slabinfo_show(struct seq_file *m, void *p) { struct kmem_cache *cachep = list_entry(p, struct kmem_cache, list); diff --git a/mm/slab.h b/mm/slab.h index dc78101..3442eb8 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -49,8 +49,6 @@ int __kmem_cache_shutdown(struct kmem_cache *); struct seq_file; struct file; -void print_slabinfo_header(struct seq_file *m); - int slabinfo_show(struct seq_file *m, void *p); ssize_t slabinfo_write(struct file *file, const char __user *buffer, diff --git a/mm/slab_common.c b/mm/slab_common.c index 2e4b4c6..c64a043 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -196,6 +196,29 @@ int slab_is_available(void) } #ifdef CONFIG_SLABINFO +static void print_slabinfo_header(struct seq_file *m) +{ + /* + * Output format version, so at least we can change it + * without _too_ many complaints. + */ +#ifdef CONFIG_DEBUG_SLAB + seq_puts(m, "slabinfo - version: 2.1 (statistics)\n"); +#else + seq_puts(m, "slabinfo - version: 2.1\n"); +#endif + seq_puts(m, "# name " + " "); + seq_puts(m, " : tunables "); + seq_puts(m, " : slabdata "); +#ifdef CONFIG_DEBUG_SLAB + seq_puts(m, " : globalstat " + " "); + seq_puts(m, " : cpustat "); +#endif + seq_putc(m, '\n'); +} + static void *s_start(struct seq_file *m, loff_t *pos) { loff_t n = *pos; diff --git a/mm/slub.c b/mm/slub.c index 77a0c8a..6b5ee34 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5405,16 +5405,6 @@ __initcall(slab_sysfs_init); * The /proc/slabinfo ABI */ #ifdef CONFIG_SLABINFO -void print_slabinfo_header(struct seq_file *m) -{ - seq_puts(m, "slabinfo - version: 2.1\n"); - seq_puts(m, "# name " - " "); - seq_puts(m, " : tunables "); - seq_puts(m, " : slabdata "); - seq_putc(m, '\n'); -} - int slabinfo_show(struct seq_file *m, void *p) { unsigned long nr_partials = 0; -- cgit v0.10.2 From 0d7561c61d76690ed84bd1016acc0fcbff063205 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Fri, 19 Oct 2012 18:20:27 +0400 Subject: sl[au]b: Process slabinfo_show in common code With all the infrastructure in place, we can now have slabinfo_show done from slab_common.c. A cache-specific function is called to grab information about the cache itself, since that is still heavily dependent on the implementation. But with the values produced by it, all the printing and handling is done from common code. Signed-off-by: Glauber Costa CC: Christoph Lameter CC: David Rientjes Signed-off-by: Pekka Enberg diff --git a/mm/slab.c b/mm/slab.c index 73811ca..6d5c83c 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -4276,9 +4276,8 @@ out: } #ifdef CONFIG_SLABINFO -int slabinfo_show(struct seq_file *m, void *p) +void get_slabinfo(struct kmem_cache *cachep, struct slabinfo *sinfo) { - struct kmem_cache *cachep = list_entry(p, struct kmem_cache, list); struct slab *slabp; unsigned long active_objs; unsigned long num_objs; @@ -4333,13 +4332,20 @@ int slabinfo_show(struct seq_file *m, void *p) if (error) printk(KERN_ERR "slab: cache %s error: %s\n", name, error); - seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", - name, active_objs, num_objs, cachep->size, - cachep->num, (1 << cachep->gfporder)); - seq_printf(m, " : tunables %4u %4u %4u", - cachep->limit, cachep->batchcount, cachep->shared); - seq_printf(m, " : slabdata %6lu %6lu %6lu", - active_slabs, num_slabs, shared_avail); + sinfo->active_objs = active_objs; + sinfo->num_objs = num_objs; + sinfo->active_slabs = active_slabs; + sinfo->num_slabs = num_slabs; + sinfo->shared_avail = shared_avail; + sinfo->limit = cachep->limit; + sinfo->batchcount = cachep->batchcount; + sinfo->shared = cachep->shared; + sinfo->objects_per_slab = cachep->num; + sinfo->cache_order = cachep->gfporder; +} + +void slabinfo_show_stats(struct seq_file *m, struct kmem_cache *cachep) +{ #if STATS { /* list3 stats */ unsigned long high = cachep->high_mark; @@ -4369,8 +4375,6 @@ int slabinfo_show(struct seq_file *m, void *p) allochit, allocmiss, freehit, freemiss); } #endif - seq_putc(m, '\n'); - return 0; } #define MAX_SLABINFO_WRITE 128 diff --git a/mm/slab.h b/mm/slab.h index 3442eb8..5a43c2f 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -49,8 +49,22 @@ int __kmem_cache_shutdown(struct kmem_cache *); struct seq_file; struct file; -int slabinfo_show(struct seq_file *m, void *p); +struct slabinfo { + unsigned long active_objs; + unsigned long num_objs; + unsigned long active_slabs; + unsigned long num_slabs; + unsigned long shared_avail; + unsigned int limit; + unsigned int batchcount; + unsigned int shared; + unsigned int objects_per_slab; + unsigned int cache_order; +}; + +void get_slabinfo(struct kmem_cache *s, struct slabinfo *sinfo); +void slabinfo_show_stats(struct seq_file *m, struct kmem_cache *s); ssize_t slabinfo_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos); #endif diff --git a/mm/slab_common.c b/mm/slab_common.c index c64a043..5fb753d 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -242,7 +242,23 @@ static void s_stop(struct seq_file *m, void *p) static int s_show(struct seq_file *m, void *p) { - return slabinfo_show(m, p); + struct kmem_cache *s = list_entry(p, struct kmem_cache, list); + struct slabinfo sinfo; + + memset(&sinfo, 0, sizeof(sinfo)); + get_slabinfo(s, &sinfo); + + seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", + s->name, sinfo.active_objs, sinfo.num_objs, s->size, + sinfo.objects_per_slab, (1 << sinfo.cache_order)); + + seq_printf(m, " : tunables %4u %4u %4u", + sinfo.limit, sinfo.batchcount, sinfo.shared); + seq_printf(m, " : slabdata %6lu %6lu %6lu", + sinfo.active_slabs, sinfo.num_slabs, sinfo.shared_avail); + slabinfo_show_stats(m, s); + seq_putc(m, '\n'); + return 0; } /* diff --git a/mm/slub.c b/mm/slub.c index 6b5ee34..472e739 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5405,18 +5405,14 @@ __initcall(slab_sysfs_init); * The /proc/slabinfo ABI */ #ifdef CONFIG_SLABINFO -int slabinfo_show(struct seq_file *m, void *p) +void get_slabinfo(struct kmem_cache *s, struct slabinfo *sinfo) { unsigned long nr_partials = 0; unsigned long nr_slabs = 0; - unsigned long nr_inuse = 0; unsigned long nr_objs = 0; unsigned long nr_free = 0; - struct kmem_cache *s; int node; - s = list_entry(p, struct kmem_cache, list); - for_each_online_node(node) { struct kmem_cache_node *n = get_node(s, node); @@ -5429,16 +5425,16 @@ int slabinfo_show(struct seq_file *m, void *p) nr_free += count_partial(n, count_free); } - nr_inuse = nr_objs - nr_free; + sinfo->active_objs = nr_objs - nr_free; + sinfo->num_objs = nr_objs; + sinfo->active_slabs = nr_slabs; + sinfo->num_slabs = nr_slabs; + sinfo->objects_per_slab = oo_objects(s->oo); + sinfo->cache_order = oo_order(s->oo); +} - seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", s->name, nr_inuse, - nr_objs, s->size, oo_objects(s->oo), - (1 << oo_order(s->oo))); - seq_printf(m, " : tunables %4u %4u %4u", 0, 0, 0); - seq_printf(m, " : slabdata %6lu %6lu %6lu", nr_slabs, nr_slabs, - 0UL); - seq_putc(m, '\n'); - return 0; +void slabinfo_show_stats(struct seq_file *m, struct kmem_cache *s) +{ } ssize_t slabinfo_write(struct file *file, const char __user *buffer, -- cgit v0.10.2 From 1b4f59e356cc94929305bd107b7f38eec62715ad Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Mon, 22 Oct 2012 18:05:36 +0400 Subject: slub: Commonize slab_cache field in struct page Right now, slab and slub have fields in struct page to derive which cache a page belongs to, but they do it slightly differently. slab uses a field called slab_cache, that lives in the third double word. slub, uses a field called "slab", living outside of the doublewords area. Ideally, we could use the same field for this. Since slub heavily makes use of the doubleword region, there isn't really much room to move slub's slab_cache field around. Since slab does not have such strict placement restrictions, we can move it outside the doubleword area. The naming used by slab, "slab_cache", is less confusing, and it is preferred over slub's generic "slab". Signed-off-by: Glauber Costa Acked-by: Christoph Lameter CC: David Rientjes Signed-off-by: Pekka Enberg diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 31f8a3a..2fef4e7 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -128,10 +128,7 @@ struct page { }; struct list_head list; /* slobs list of pages */ - struct { /* slab fields */ - struct kmem_cache *slab_cache; - struct slab *slab_page; - }; + struct slab *slab_page; /* slab fields */ }; /* Remainder is not double word aligned */ @@ -146,7 +143,7 @@ struct page { #if USE_SPLIT_PTLOCKS spinlock_t ptl; #endif - struct kmem_cache *slab; /* SLUB: Pointer to slab */ + struct kmem_cache *slab_cache; /* SL[AU]B: Pointer to slab */ struct page *first_page; /* Compound tail pages */ }; diff --git a/mm/slub.c b/mm/slub.c index 16274b2..35483e0 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1092,11 +1092,11 @@ static noinline struct kmem_cache_node *free_debug_processing( if (!check_object(s, page, object, SLUB_RED_ACTIVE)) goto out; - if (unlikely(s != page->slab)) { + if (unlikely(s != page->slab_cache)) { if (!PageSlab(page)) { slab_err(s, page, "Attempt to free object(0x%p) " "outside of slab", object); - } else if (!page->slab) { + } else if (!page->slab_cache) { printk(KERN_ERR "SLUB : no slab for object 0x%p.\n", object); @@ -1357,7 +1357,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) goto out; inc_slabs_node(s, page_to_nid(page), page->objects); - page->slab = s; + page->slab_cache = s; __SetPageSlab(page); if (page->pfmemalloc) SetPageSlabPfmemalloc(page); @@ -1424,7 +1424,7 @@ static void rcu_free_slab(struct rcu_head *h) else page = container_of((struct list_head *)h, struct page, lru); - __free_slab(page->slab, page); + __free_slab(page->slab_cache, page); } static void free_slab(struct kmem_cache *s, struct page *page) @@ -2617,9 +2617,9 @@ void kmem_cache_free(struct kmem_cache *s, void *x) page = virt_to_head_page(x); - if (kmem_cache_debug(s) && page->slab != s) { + if (kmem_cache_debug(s) && page->slab_cache != s) { pr_err("kmem_cache_free: Wrong slab cache. %s but object" - " is from %s\n", page->slab->name, s->name); + " is from %s\n", page->slab_cache->name, s->name); WARN_ON_ONCE(1); return; } @@ -3418,7 +3418,7 @@ size_t ksize(const void *object) return PAGE_SIZE << compound_order(page); } - return slab_ksize(page->slab); + return slab_ksize(page->slab_cache); } EXPORT_SYMBOL(ksize); @@ -3443,8 +3443,8 @@ bool verify_mem_not_deleted(const void *x) } slab_lock(page); - if (on_freelist(page->slab, page, object)) { - object_err(page->slab, page, object, "Object is on free-list"); + if (on_freelist(page->slab_cache, page, object)) { + object_err(page->slab_cache, page, object, "Object is on free-list"); rv = false; } else { rv = true; @@ -3475,7 +3475,7 @@ void kfree(const void *x) __free_pages(page, compound_order(page)); return; } - slab_free(page->slab, page, object, _RET_IP_); + slab_free(page->slab_cache, page, object, _RET_IP_); } EXPORT_SYMBOL(kfree); @@ -3686,11 +3686,11 @@ static void __init kmem_cache_bootstrap_fixup(struct kmem_cache *s) if (n) { list_for_each_entry(p, &n->partial, lru) - p->slab = s; + p->slab_cache = s; #ifdef CONFIG_SLUB_DEBUG list_for_each_entry(p, &n->full, lru) - p->slab = s; + p->slab_cache = s; #endif } } -- cgit v0.10.2 From 6c9c6d6301287e369a754d628230fa6e50cdb74b Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 8 Oct 2012 11:08:06 -0600 Subject: dma-debug: New interfaces to debug dma mapping errors Add dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. This interface clears a flag set by debug_dma_map_page() to indicate that dma_mapping_error() has been called by the driver. When driver does unmap, debug_dma_unmap() checks the flag and if this flag is still set, prints warning message that includes call trace that leads up to the unmap. This interface can be called from dma_mapping_error() routines to enable dma mapping error check debugging. Tested: Intel iommu and swiotlb (iommu=soft) on x86-64 with CONFIG_DMA_API_DEBUG enabled and disabled. Signed-off-by: Shuah Khan Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: Joerg Roedel diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt index 66bd97a..78a6c56 100644 --- a/Documentation/DMA-API.txt +++ b/Documentation/DMA-API.txt @@ -678,3 +678,15 @@ out of dma_debug_entries. These entries are preallocated at boot. The number of preallocated entries is defined per architecture. If it is too low for you boot with 'dma_debug_entries=' to overwrite the architectural default. + +void debug_dmap_mapping_error(struct device *dev, dma_addr_t dma_addr); + +dma-debug interface debug_dma_mapping_error() to debug drivers that fail +to check dma mapping errors on addresses returned by dma_map_single() and +dma_map_page() interfaces. This interface clears a flag set by +debug_dma_map_page() to indicate that dma_mapping_error() has been called by +the driver. When driver does unmap, debug_dma_unmap() checks the flag and if +this flag is still set, prints warning message that includes call trace that +leads up to the unmap. This interface can be called from dma_mapping_error() +routines to enable dma mapping error check debugging. + diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index f7b4c79..808dae6 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -47,6 +47,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *ops = get_dma_ops(dev); + debug_dma_mapping_error(dev, dma_addr); if (ops->mapping_error) return ops->mapping_error(dev, dma_addr); diff --git a/include/linux/dma-debug.h b/include/linux/dma-debug.h index 171ad8a..fc0e34c 100644 --- a/include/linux/dma-debug.h +++ b/include/linux/dma-debug.h @@ -39,6 +39,8 @@ extern void debug_dma_map_page(struct device *dev, struct page *page, int direction, dma_addr_t dma_addr, bool map_single); +extern void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr); + extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, size_t size, int direction, bool map_single); @@ -105,6 +107,11 @@ static inline void debug_dma_map_page(struct device *dev, struct page *page, { } +static inline void debug_dma_mapping_error(struct device *dev, + dma_addr_t dma_addr) +{ +} + static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, size_t size, int direction, bool map_single) diff --git a/lib/dma-debug.c b/lib/dma-debug.c index d84beb9..59f4a1a 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -45,6 +45,12 @@ enum { dma_debug_coherent, }; +enum map_err_types { + MAP_ERR_CHECK_NOT_APPLICABLE, + MAP_ERR_NOT_CHECKED, + MAP_ERR_CHECKED, +}; + #define DMA_DEBUG_STACKTRACE_ENTRIES 5 struct dma_debug_entry { @@ -57,6 +63,7 @@ struct dma_debug_entry { int direction; int sg_call_ents; int sg_mapped_ents; + enum map_err_types map_err_type; #ifdef CONFIG_STACKTRACE struct stack_trace stacktrace; unsigned long st_entries[DMA_DEBUG_STACKTRACE_ENTRIES]; @@ -114,6 +121,12 @@ static struct device_driver *current_driver __read_mostly; static DEFINE_RWLOCK(driver_name_lock); +static const char *const maperr2str[] = { + [MAP_ERR_CHECK_NOT_APPLICABLE] = "dma map error check not applicable", + [MAP_ERR_NOT_CHECKED] = "dma map error not checked", + [MAP_ERR_CHECKED] = "dma map error checked", +}; + static const char *type2name[4] = { "single", "page", "scather-gather", "coherent" }; @@ -376,11 +389,12 @@ void debug_dma_dump_mappings(struct device *dev) list_for_each_entry(entry, &bucket->list, list) { if (!dev || dev == entry->dev) { dev_info(entry->dev, - "%s idx %d P=%Lx D=%Lx L=%Lx %s\n", + "%s idx %d P=%Lx D=%Lx L=%Lx %s %s\n", type2name[entry->type], idx, (unsigned long long)entry->paddr, entry->dev_addr, entry->size, - dir2name[entry->direction]); + dir2name[entry->direction], + maperr2str[entry->map_err_type]); } } @@ -838,13 +852,28 @@ static __init int dma_debug_entries_cmdline(char *str) __setup("dma_debug=", dma_debug_cmdline); __setup("dma_debug_entries=", dma_debug_entries_cmdline); +/* Calling dma_mapping_error() from dma-debug api will result in calling + debug_dma_mapping_error() - need internal mapping error routine to + avoid debug checks */ +#ifndef DMA_ERROR_CODE +#define DMA_ERROR_CODE 0 +#endif +static inline int has_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + const struct dma_map_ops *ops = get_dma_ops(dev); + if (ops->mapping_error) + return ops->mapping_error(dev, dma_addr); + + return (dma_addr == DMA_ERROR_CODE); +} + static void check_unmap(struct dma_debug_entry *ref) { struct dma_debug_entry *entry; struct hash_bucket *bucket; unsigned long flags; - if (dma_mapping_error(ref->dev, ref->dev_addr)) { + if (unlikely(has_mapping_error(ref->dev, ref->dev_addr))) { err_printk(ref->dev, NULL, "DMA-API: device driver tries " "to free an invalid DMA memory address\n"); return; @@ -910,6 +939,15 @@ static void check_unmap(struct dma_debug_entry *ref) dir2name[ref->direction]); } + if (entry->map_err_type == MAP_ERR_NOT_CHECKED) { + err_printk(ref->dev, entry, + "DMA-API: device driver failed to check map error" + "[device address=0x%016llx] [size=%llu bytes] " + "[mapped as %s]", + ref->dev_addr, ref->size, + type2name[entry->type]); + } + hash_bucket_del(entry); dma_entry_free(entry); @@ -1017,7 +1055,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, if (unlikely(global_disable)) return; - if (unlikely(dma_mapping_error(dev, dma_addr))) + if (unlikely(has_mapping_error(dev, dma_addr))) return; entry = dma_entry_alloc(); @@ -1030,6 +1068,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, entry->dev_addr = dma_addr; entry->size = size; entry->direction = direction; + entry->map_err_type = MAP_ERR_NOT_CHECKED; if (map_single) entry->type = dma_debug_single; @@ -1045,6 +1084,30 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, } EXPORT_SYMBOL(debug_dma_map_page); +void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + struct dma_debug_entry ref; + struct dma_debug_entry *entry; + struct hash_bucket *bucket; + unsigned long flags; + + if (unlikely(global_disable)) + return; + + ref.dev = dev; + ref.dev_addr = dma_addr; + bucket = get_hash_bucket(&ref, &flags); + entry = bucket_find_exact(bucket, &ref); + + if (!entry) + goto out; + + entry->map_err_type = MAP_ERR_CHECKED; +out: + put_hash_bucket(bucket, &flags); +} +EXPORT_SYMBOL(debug_dma_mapping_error); + void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, size_t size, int direction, bool map_single) { -- cgit v0.10.2 From 8d7f62e6a7aa0bfd7163d3c4a5fb59280f6a6eb5 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 18 Oct 2012 14:00:58 -0600 Subject: Documentation DMA-API-HOWTO.txt Add dma mapping error check usage examples Enhance the document to discuss the importance of dma mapping error checks after dma_map_single() and dma_map_page() calls. Also added usage examples that include unmap examples in error paths when dma mapping error is returned. Includes correct and incorrect usages to high light some common mistakes in error paths especially when dma mapping fails when more than one dma mapping call is made. Signed-off-by: Shuah Khan Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: Joerg Roedel diff --git a/Documentation/DMA-API-HOWTO.txt b/Documentation/DMA-API-HOWTO.txt index a0b6250..4a4fb29 100644 --- a/Documentation/DMA-API-HOWTO.txt +++ b/Documentation/DMA-API-HOWTO.txt @@ -468,11 +468,46 @@ To map a single region, you do: size_t size = buffer->len; dma_handle = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dma_handle)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } and to unmap it: dma_unmap_single(dev, dma_handle, size, direction); +You should call dma_mapping_error() as dma_map_single() could fail and return +error. Not all dma implementations support dma_mapping_error() interface. +However, it is a good practice to call dma_mapping_error() interface, which +will invoke the generic mapping error check interface. Doing so will ensure +that the mapping code will work correctly on all dma implementations without +any dependency on the specifics of the underlying implementation. Using the +returned address without checking for errors could result in failures ranging +from panics to silent data corruption. Couple of example of incorrect ways to +check for errors that make assumptions about the underlying dma implementation +are as follows and these are applicable to dma_map_page() as well. + +Incorrect example 1: + dma_addr_t dma_handle; + + dma_handle = dma_map_single(dev, addr, size, direction); + if ((dma_handle & 0xffff != 0) || (dma_handle >= 0x1000000)) { + goto map_error; + } + +Incorrect example 2: + dma_addr_t dma_handle; + + dma_handle = dma_map_single(dev, addr, size, direction); + if (dma_handle == DMA_ERROR_CODE) { + goto map_error; + } + You should call dma_unmap_single when the DMA activity is finished, e.g. from the interrupt which told you that the DMA transfer is done. @@ -489,6 +524,14 @@ Specifically: size_t size = buffer->len; dma_handle = dma_map_page(dev, page, offset, size, direction); + if (dma_mapping_error(dma_handle)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } ... @@ -496,6 +539,12 @@ Specifically: Here, "offset" means byte offset within the given page. +You should call dma_mapping_error() as dma_map_page() could fail and return +error as outlined under the dma_map_single() discussion. + +You should call dma_unmap_page when the DMA activity is finished, e.g. +from the interrupt which told you that the DMA transfer is done. + With scatterlists, you map a region gathered from several regions by: int i, count = dma_map_sg(dev, sglist, nents, direction); @@ -578,6 +627,14 @@ to use the dma_sync_*() interfaces. dma_addr_t mapping; mapping = dma_map_single(cp->dev, buffer, len, DMA_FROM_DEVICE); + if (dma_mapping_error(dma_handle)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } cp->rx_buf = buffer; cp->rx_len = len; @@ -658,6 +715,75 @@ failure can be determined by: * delay and try again later or * reset driver. */ + goto map_error_handling; + } + +- unmap pages that are already mapped, when mapping error occurs in the middle + of a multiple page mapping attempt. These example are applicable to + dma_map_page() as well. + +Example 1: + dma_addr_t dma_handle1; + dma_addr_t dma_handle2; + + dma_handle1 = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_handle1)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling1; + } + dma_handle2 = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_handle2)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling2; + } + + ... + + map_error_handling2: + dma_unmap_single(dma_handle1); + map_error_handling1: + +Example 2: (if buffers are allocated a loop, unmap all mapped buffers when + mapping error is detected in the middle) + + dma_addr_t dma_addr; + dma_addr_t array[DMA_BUFFERS]; + int save_index = 0; + + for (i = 0; i < DMA_BUFFERS; i++) { + + ... + + dma_addr = dma_map_single(dev, addr, size, direction); + if (dma_mapping_error(dev, dma_addr)) { + /* + * reduce current DMA mapping usage, + * delay and try again later or + * reset driver. + */ + goto map_error_handling; + } + array[i].dma_addr = dma_addr; + save_index++; + } + + ... + + map_error_handling: + + for (i = 0; i < save_index; i++) { + + ... + + dma_unmap_single(array[i].dma_addr); } Networking drivers must call dev_kfree_skb to free the socket buffer -- cgit v0.10.2 From eb9c95271eafb62f7024547016ad00636c1425c1 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 8 Oct 2012 22:49:35 -0600 Subject: iommu/amd: Split IOMMU group initialization This needs to be broken apart, start with pulling all the IOMMU group init code into a new function. Signed-off-by: Alex Williamson Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 55074cb..b65b377 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -276,39 +276,32 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) #define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) -static int iommu_init_device(struct device *dev) +static int init_iommu_group(struct device *dev) { - struct pci_dev *dma_pdev = NULL, *pdev = to_pci_dev(dev); struct iommu_dev_data *dev_data; struct iommu_group *group; - u16 alias; + struct pci_dev *dma_pdev = NULL; int ret; - if (dev->archdata.iommu) + group = iommu_group_get(dev); + if (group) { + iommu_group_put(group); return 0; + } dev_data = find_dev_data(get_device_id(dev)); if (!dev_data) return -ENOMEM; - alias = amd_iommu_alias_table[dev_data->devid]; - if (alias != dev_data->devid) { - struct iommu_dev_data *alias_data; - - alias_data = find_dev_data(alias); - if (alias_data == NULL) { - pr_err("AMD-Vi: Warning: Unhandled device %s\n", - dev_name(dev)); - free_dev_data(dev_data); - return -ENOTSUPP; - } - dev_data->alias_data = alias_data; + if (dev_data->alias_data) { + u16 alias; + alias = amd_iommu_alias_table[dev_data->devid]; dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); } - if (dma_pdev == NULL) - dma_pdev = pci_dev_get(pdev); + if (!dma_pdev) + dma_pdev = pci_dev_get(to_pci_dev(dev)); /* Account for quirked devices */ swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); @@ -358,6 +351,38 @@ root_bus: iommu_group_put(group); + return ret; +} + +static int iommu_init_device(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct iommu_dev_data *dev_data; + u16 alias; + int ret; + + if (dev->archdata.iommu) + return 0; + + dev_data = find_dev_data(get_device_id(dev)); + if (!dev_data) + return -ENOMEM; + + alias = amd_iommu_alias_table[dev_data->devid]; + if (alias != dev_data->devid) { + struct iommu_dev_data *alias_data; + + alias_data = find_dev_data(alias); + if (alias_data == NULL) { + pr_err("AMD-Vi: Warning: Unhandled device %s\n", + dev_name(dev)); + free_dev_data(dev_data); + return -ENOTSUPP; + } + dev_data->alias_data = alias_data; + } + + ret = init_iommu_group(dev); if (ret) return ret; -- cgit v0.10.2 From 2851db21b88ff3e80e1b3ab5e23b1a49d6f734bf Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 8 Oct 2012 22:49:41 -0600 Subject: iommu/amd: Split IOMMU Group topology walk Signed-off-by: Alex Williamson Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index b65b377..6edbd0e 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -276,32 +276,9 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) #define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) -static int init_iommu_group(struct device *dev) +static struct pci_dev *get_isolation_root(struct pci_dev *pdev) { - struct iommu_dev_data *dev_data; - struct iommu_group *group; - struct pci_dev *dma_pdev = NULL; - int ret; - - group = iommu_group_get(dev); - if (group) { - iommu_group_put(group); - return 0; - } - - dev_data = find_dev_data(get_device_id(dev)); - if (!dev_data) - return -ENOMEM; - - if (dev_data->alias_data) { - u16 alias; - - alias = amd_iommu_alias_table[dev_data->devid]; - dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); - } - - if (!dma_pdev) - dma_pdev = pci_dev_get(to_pci_dev(dev)); + struct pci_dev *dma_pdev = pdev; /* Account for quirked devices */ swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); @@ -339,6 +316,37 @@ static int init_iommu_group(struct device *dev) } root_bus: + return dma_pdev; +} + +static int init_iommu_group(struct device *dev) +{ + struct iommu_dev_data *dev_data; + struct iommu_group *group; + struct pci_dev *dma_pdev = NULL; + int ret; + + group = iommu_group_get(dev); + if (group) { + iommu_group_put(group); + return 0; + } + + dev_data = find_dev_data(get_device_id(dev)); + if (!dev_data) + return -ENOMEM; + + if (dev_data->alias_data) { + u16 alias; + + alias = amd_iommu_alias_table[dev_data->devid]; + dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); + } + + if (!dma_pdev) + dma_pdev = pci_dev_get(to_pci_dev(dev)); + + dma_pdev = get_isolation_root(dma_pdev); group = iommu_group_get(&dma_pdev->dev); pci_dev_put(dma_pdev); if (!group) { -- cgit v0.10.2 From 2bff6a508eb2ba8b341c20db3099e050e5496e3d Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 8 Oct 2012 22:49:48 -0600 Subject: iommu/amd: Split upstream bus device lookup Signed-off-by: Alex Williamson Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 6edbd0e..3a00b5ce 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -274,6 +274,18 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) *from = to; } +static struct pci_bus *find_hosted_bus(struct pci_bus *bus) +{ + while (!bus->self) { + if (!pci_is_root_bus(bus)) + bus = bus->parent; + else + return ERR_PTR(-ENODEV); + } + + return bus; +} + #define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) static struct pci_dev *get_isolation_root(struct pci_dev *pdev) @@ -300,14 +312,9 @@ static struct pci_dev *get_isolation_root(struct pci_dev *pdev) * Finding the next device may require skipping virtual buses. */ while (!pci_is_root_bus(dma_pdev->bus)) { - struct pci_bus *bus = dma_pdev->bus; - - while (!bus->self) { - if (!pci_is_root_bus(bus)) - bus = bus->parent; - else - goto root_bus; - } + struct pci_bus *bus = find_hosted_bus(dma_pdev->bus); + if (IS_ERR(bus)) + break; if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS)) break; @@ -315,7 +322,6 @@ static struct pci_dev *get_isolation_root(struct pci_dev *pdev) swap_pci_ref(&dma_pdev, pci_dev_get(bus->self)); } -root_bus: return dma_pdev; } -- cgit v0.10.2 From ce7ac4abf2401dfdcb1ac4c7277dab8ed90c8788 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 8 Oct 2012 22:49:54 -0600 Subject: iommu/amd: Split IOMMU group allocation and attach Add a WARN_ON to make it clear why we don't add dma_pdev->dev to the group we're allocating. Signed-off-by: Alex Williamson Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 3a00b5ce..7fa97a5 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -325,6 +325,24 @@ static struct pci_dev *get_isolation_root(struct pci_dev *pdev) return dma_pdev; } +static int use_pdev_iommu_group(struct pci_dev *pdev, struct device *dev) +{ + struct iommu_group *group = iommu_group_get(&pdev->dev); + int ret; + + if (!group) { + group = iommu_group_alloc(); + if (IS_ERR(group)) + return PTR_ERR(group); + + WARN_ON(&pdev->dev != dev); + } + + ret = iommu_group_add_device(group, dev); + iommu_group_put(group); + return ret; +} + static int init_iommu_group(struct device *dev) { struct iommu_dev_data *dev_data; @@ -353,18 +371,8 @@ static int init_iommu_group(struct device *dev) dma_pdev = pci_dev_get(to_pci_dev(dev)); dma_pdev = get_isolation_root(dma_pdev); - group = iommu_group_get(&dma_pdev->dev); + ret = use_pdev_iommu_group(dma_pdev, dev); pci_dev_put(dma_pdev); - if (!group) { - group = iommu_group_alloc(); - if (IS_ERR(group)) - return PTR_ERR(group); - } - - ret = iommu_group_add_device(group, dev); - - iommu_group_put(group); - return ret; } -- cgit v0.10.2 From 78bfa9f395f6bbab168b83f69b99659818517b02 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 8 Oct 2012 22:50:00 -0600 Subject: iommu/amd: Properly account for virtual aliases in IOMMU groups An alias doesn't always point to a physical device. When this happens we must first verify that the IOMMU group isn't rooted in a device above the alias. In this case the alias is effectively just another quirk for the devices aliased to it. Alternatively, the virtual alias itself may be the root of the IOMMU group. To support this, allow a group to be hosted on the alias dev_data for use by anything that might have the same alias. Signed-off-by: Alex williamson Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 7fa97a5..cb63cc5 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -140,6 +140,9 @@ static void free_dev_data(struct iommu_dev_data *dev_data) list_del(&dev_data->dev_data_list); spin_unlock_irqrestore(&dev_data_list_lock, flags); + if (dev_data->group) + iommu_group_put(dev_data->group); + kfree(dev_data); } @@ -343,11 +346,25 @@ static int use_pdev_iommu_group(struct pci_dev *pdev, struct device *dev) return ret; } +static int use_dev_data_iommu_group(struct iommu_dev_data *dev_data, + struct device *dev) +{ + if (!dev_data->group) { + struct iommu_group *group = iommu_group_alloc(); + if (IS_ERR(group)) + return PTR_ERR(group); + + dev_data->group = group; + } + + return iommu_group_add_device(dev_data->group, dev); +} + static int init_iommu_group(struct device *dev) { struct iommu_dev_data *dev_data; struct iommu_group *group; - struct pci_dev *dma_pdev = NULL; + struct pci_dev *dma_pdev; int ret; group = iommu_group_get(dev); @@ -362,18 +379,52 @@ static int init_iommu_group(struct device *dev) if (dev_data->alias_data) { u16 alias; + struct pci_bus *bus; + + if (dev_data->alias_data->group) + goto use_group; + /* + * If the alias device exists, it's effectively just a first + * level quirk for finding the DMA source. + */ alias = amd_iommu_alias_table[dev_data->devid]; dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); - } + if (dma_pdev) { + dma_pdev = get_isolation_root(dma_pdev); + goto use_pdev; + } + + /* + * If the alias is virtual, try to find a parent device + * and test whether the IOMMU group is actualy rooted above + * the alias. Be careful to also test the parent device if + * we think the alias is the root of the group. + */ + bus = pci_find_bus(0, alias >> 8); + if (!bus) + goto use_group; + + bus = find_hosted_bus(bus); + if (IS_ERR(bus) || !bus->self) + goto use_group; - if (!dma_pdev) - dma_pdev = pci_dev_get(to_pci_dev(dev)); + dma_pdev = get_isolation_root(pci_dev_get(bus->self)); + if (dma_pdev != bus->self || (dma_pdev->multifunction && + !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))) + goto use_pdev; + + pci_dev_put(dma_pdev); + goto use_group; + } - dma_pdev = get_isolation_root(dma_pdev); + dma_pdev = get_isolation_root(pci_dev_get(to_pci_dev(dev))); +use_pdev: ret = use_pdev_iommu_group(dma_pdev, dev); pci_dev_put(dma_pdev); return ret; +use_group: + return use_dev_data_iommu_group(dev_data->alias_data, dev); } static int iommu_init_device(struct device *dev) diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index c9aa3d0..e38ab43 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -426,6 +426,7 @@ struct iommu_dev_data { struct iommu_dev_data *alias_data;/* The alias dev_data */ struct protection_domain *domain; /* Domain the device is bound to */ atomic_t bind; /* Domain attach reference count */ + struct iommu_group *group; /* IOMMU group for virtual aliases */ u16 devid; /* PCI Device ID */ bool iommu_v2; /* Device can make use of IOMMUv2 */ bool passthrough; /* Default for device is pt_domain */ -- cgit v0.10.2 From a4d6983c7a164c39bc0289124a2cd9f765d333d0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 24 Oct 2012 23:53:01 -0700 Subject: Input: arc_ps2 - switch to using managed resources Using managed resources simplifies error handling and shrinks size of arc_ps2_remove(). Tested-by: Mischa Jonker Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c index f8c026a..89ad763 100644 --- a/drivers/input/serio/arc_ps2.c +++ b/drivers/input/serio/arc_ps2.c @@ -38,8 +38,6 @@ struct arc_ps2_port { struct arc_ps2_data { struct arc_ps2_port port[ARC_PS2_PORTS]; - struct resource *iomem_res; - int irq; void __iomem *addr; unsigned int frame_error; unsigned int buf_overflow; @@ -125,6 +123,32 @@ static void arc_ps2_close(struct serio *io) port->status_addr); } +static void __iomem * __devinit arc_ps2_calc_addr(struct arc_ps2_data *arc_ps2, + int index, bool status) +{ + void __iomem *addr; + + addr = arc_ps2->addr + 4 + 4 * index; + if (status) + addr += ARC_PS2_PORTS * 4; + + return addr; +} + +static void __devinit arc_ps2_inhibit_ports(struct arc_ps2_data *arc_ps2) +{ + void __iomem *addr; + u32 val; + int i; + + for (i = 0; i < ARC_PS2_PORTS; i++) { + addr = arc_ps2_calc_addr(arc_ps2, i, true); + val = ioread32(addr); + val &= ~(PS2_STAT_RX_INT_EN | PS2_STAT_TX_INT_EN); + iowrite32(val, addr); + } +} + static int __devinit arc_ps2_create_port(struct platform_device *pdev, struct arc_ps2_data *arc_ps2, int index) @@ -146,8 +170,8 @@ static int __devinit arc_ps2_create_port(struct platform_device *pdev, port->io = io; - port->data_addr = arc_ps2->addr + 4 + index * 4; - port->status_addr = arc_ps2->addr + 4 + ARC_PS2_PORTS * 4 + index * 4; + port->data_addr = arc_ps2_calc_addr(arc_ps2, index, false); + port->status_addr = arc_ps2_calc_addr(arc_ps2, index, true); dev_dbg(&pdev->dev, "port%d is allocated (data = 0x%p, status = 0x%p)\n", index, port->data_addr, port->status_addr); @@ -159,85 +183,63 @@ static int __devinit arc_ps2_create_port(struct platform_device *pdev, static int __devinit arc_ps2_probe(struct platform_device *pdev) { struct arc_ps2_data *arc_ps2; + struct resource *res; + int irq; int error, id, i; - arc_ps2 = kzalloc(sizeof(struct arc_ps2_data), GFP_KERNEL); - if (!arc_ps2) { - dev_err(&pdev->dev, "out of memory\n"); - return -ENOMEM; - } - - arc_ps2->iomem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!arc_ps2->iomem_res) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { dev_err(&pdev->dev, "no IO memory defined\n"); - error = -EINVAL; - goto err_free_mem; + return -EINVAL; } - arc_ps2->irq = platform_get_irq_byname(pdev, "arc_ps2_irq"); - if (arc_ps2->irq < 0) { + irq = platform_get_irq_byname(pdev, "arc_ps2_irq"); + if (irq < 0) { dev_err(&pdev->dev, "no IRQ defined\n"); - error = -EINVAL; - goto err_free_mem; + return -EINVAL; } - if (!request_mem_region(arc_ps2->iomem_res->start, - resource_size(arc_ps2->iomem_res), pdev->name)) { - dev_err(&pdev->dev, "memory region allocation failed for %pR\n", - arc_ps2->iomem_res); - - error = -EBUSY; - goto err_free_mem; + arc_ps2 = devm_kzalloc(&pdev->dev, sizeof(struct arc_ps2_data), + GFP_KERNEL); + if (!arc_ps2) { + dev_err(&pdev->dev, "out of memory\n"); + return -ENOMEM; } - arc_ps2->addr = ioremap_nocache(arc_ps2->iomem_res->start, - resource_size(arc_ps2->iomem_res)); - if (!arc_ps2->addr) { - dev_err(&pdev->dev, "memory mapping failed\n"); - error = -ENOMEM; - goto err_release_region; - } + arc_ps2->addr = devm_request_and_ioremap(&pdev->dev, res); + if (!arc_ps2->addr) + return -EBUSY; dev_info(&pdev->dev, "irq = %d, address = 0x%p, ports = %i\n", - arc_ps2->irq, arc_ps2->addr, ARC_PS2_PORTS); + irq, arc_ps2->addr, ARC_PS2_PORTS); id = ioread32(arc_ps2->addr); if (id != ARC_ARC_PS2_ID) { dev_err(&pdev->dev, "device id does not match\n"); - error = -ENXIO; - goto err_unmap; + return -ENXIO; } - for (i = 0; i < ARC_PS2_PORTS; i++) { - error = arc_ps2_create_port(pdev, arc_ps2, i); - if (error) - goto err_unregister_ports; - } + arc_ps2_inhibit_ports(arc_ps2); - error = request_irq(arc_ps2->irq, arc_ps2_interrupt, 0, - "arc_ps2", arc_ps2); + error = devm_request_irq(&pdev->dev, irq, arc_ps2_interrupt, + 0, "arc_ps2", arc_ps2); if (error) { dev_err(&pdev->dev, "Could not allocate IRQ\n"); - goto err_unregister_ports; + return error; + } + + for (i = 0; i < ARC_PS2_PORTS; i++) { + error = arc_ps2_create_port(pdev, arc_ps2, i); + if (error) { + while (--i >= 0) + serio_unregister_port(arc_ps2->port[i].io); + return error; + } } platform_set_drvdata(pdev, arc_ps2); return 0; - -err_unregister_ports: - for (i = 0; i < ARC_PS2_PORTS; i++) { - if (arc_ps2->port[i].io) - serio_unregister_port(arc_ps2->port[i].io); - } -err_unmap: - iounmap(arc_ps2->addr); -err_release_region: - release_mem_region(arc_ps2->iomem_res->start, - resource_size(arc_ps2->iomem_res)); -err_free_mem: - kfree(arc_ps2); - return error; } static int __devexit arc_ps2_remove(struct platform_device *pdev) @@ -248,18 +250,11 @@ static int __devexit arc_ps2_remove(struct platform_device *pdev) for (i = 0; i < ARC_PS2_PORTS; i++) serio_unregister_port(arc_ps2->port[i].io); - free_irq(arc_ps2->irq, arc_ps2); - iounmap(arc_ps2->addr); - release_mem_region(arc_ps2->iomem_res->start, - resource_size(arc_ps2->iomem_res)); - dev_dbg(&pdev->dev, "interrupt count = %i\n", arc_ps2->total_int); dev_dbg(&pdev->dev, "frame error count = %i\n", arc_ps2->frame_error); dev_dbg(&pdev->dev, "buffer overflow count = %i\n", arc_ps2->buf_overflow); - kfree(arc_ps2); - return 0; } -- cgit v0.10.2 From 5161870f51acd74442375a6693c0586996d01f44 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 24 Oct 2012 23:53:01 -0700 Subject: Input: fix sparse warning in multitouch code This fixes the following sparse warning: drivers/input/input-mt.c:193:18: warning: Using plain integer as NULL pointer Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index c0ec7d4..bf2f30c0 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -190,7 +190,7 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) if (!mt) return; - oldest = 0; + oldest = NULL; oldid = mt->trkid; count = 0; -- cgit v0.10.2 From adc4633c86f3358fce676b6c7ce75055e395123a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 24 Oct 2012 23:53:01 -0700 Subject: Input: fix sparse warning in __input_release_device() This fixes the following warning: drivers/input/input.c:538:23: error: incompatible types in comparison expression (different address spaces) Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/input.c b/drivers/input/input.c index 53a0dde..f1be1a7 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -534,8 +534,11 @@ EXPORT_SYMBOL(input_grab_device); static void __input_release_device(struct input_handle *handle) { struct input_dev *dev = handle->dev; + struct input_handle *grabber; - if (dev->grab == handle) { + grabber = rcu_dereference_protected(dev->grab, + lockdep_is_held(&dev->mutex)); + if (grabber == handle) { rcu_assign_pointer(dev->grab, NULL); /* Make sure input_pass_event() notices that grab is gone */ synchronize_rcu(); -- cgit v0.10.2 From 6828b4bb7632051cdf925ad0b2f1ba3f906c5d47 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 24 Oct 2012 23:53:02 -0700 Subject: Input: remove CONFIG_EXPERIMENTAL from keyboard drivers This config item has not carried much meaning for a while now and is almost always enabled by default. As agreed during the Linux kernel summit, remove it. Signed-off-by: Kees Cook Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c50fa75..f483ce6 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -134,7 +134,7 @@ config KEYBOARD_QT1070 config KEYBOARD_QT2160 tristate "Atmel AT42QT2160 Touch Sensor Chip" - depends on I2C && EXPERIMENTAL + depends on I2C help If you say yes here you get support for Atmel AT42QT2160 Touch Sensor chip as a keyboard input. -- cgit v0.10.2 From e52278a36898dc93aa1991a3ac976c1c7c55e2ed Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 24 Oct 2012 23:53:02 -0700 Subject: Input: remove CONFIG_EXPERIMENTAL from miscellaneous drivers This config item has not carried much meaning for a while now and is almost always enabled by default. As agreed during the Linux kernel summit, remove it. Signed-off-by: Kees Cook Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7c0f1ec..a7719a2 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -290,8 +290,7 @@ config INPUT_ATI_REMOTE2 called ati_remote2. config INPUT_KEYSPAN_REMOTE - tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" - depends on EXPERIMENTAL + tristate "Keyspan DMR USB remote control" depends on USB_ARCH_HAS_HCD select USB help @@ -340,7 +339,6 @@ config INPUT_POWERMATE config INPUT_YEALINK tristate "Yealink usb-p1k voip phone" - depends on EXPERIMENTAL depends on USB_ARCH_HAS_HCD select USB help @@ -356,7 +354,6 @@ config INPUT_YEALINK config INPUT_CM109 tristate "C-Media CM109 USB I/O Controller" - depends on EXPERIMENTAL depends on USB_ARCH_HAS_HCD select USB help @@ -434,7 +431,7 @@ config INPUT_PCF50633_PMU config INPUT_PCF8574 tristate "PCF8574 Keypad input device" - depends on I2C && EXPERIMENTAL + depends on I2C help Say Y here if you want to support a keypad connected via I2C with a PCF8574. -- cgit v0.10.2 From a6e8c0a25377e27958b11b20e1927885ae7c9857 Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Wed, 24 Oct 2012 23:55:01 -0700 Subject: Input: qt2160 - fix qt2160_write() implementation The previous implementation of qt2160_write() didn't work properly because the value was actually not written to the device. Probably nobody detected this because the only write that was issued was the one related to auto calibration. In order to fix the problem use a similar aproach as qt1070 instead. Signed-off-by: Javier Martin Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index e7a5e36..73ea4b0 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -207,23 +207,14 @@ static int __devinit qt2160_read(struct i2c_client *client, u8 reg) static int __devinit qt2160_write(struct i2c_client *client, u8 reg, u8 data) { - int error; - - error = i2c_smbus_write_byte(client, reg); - if (error) { - dev_err(&client->dev, - "couldn't send request. Returned %d\n", error); - return error; - } + int ret; - error = i2c_smbus_write_byte(client, data); - if (error) { + ret = i2c_smbus_write_byte_data(client, reg, data); + if (ret < 0) dev_err(&client->dev, - "couldn't write data. Returned %d\n", error); - return error; - } + "couldn't write data. Returned %d\n", ret); - return error; + return ret; } -- cgit v0.10.2 From d48444cf39161bca014b9f6402e409d3e193e530 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 24 Oct 2012 17:56:33 +0200 Subject: openrisc: Use Kbuild infrastructure for kvm_para.h All the headers but kvm_para.h use the Kbuild infrastructure to get to the asm-generic headers. Cc: linux-kbuild@vger.kernel.org Cc: linux@lists.openrisc.net Signed-off-by: Steven Rostedt Signed-off-by: Jonas Bonn diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild index 78de680..9430b8c 100644 --- a/arch/openrisc/include/asm/Kbuild +++ b/arch/openrisc/include/asm/Kbuild @@ -32,6 +32,7 @@ generic-y += ipcbuf.h generic-y += irq_regs.h generic-y += kdebug.h generic-y += kmap_types.h +generic-y += kvm_para.h generic-y += local.h generic-y += mman.h generic-y += module.h diff --git a/arch/openrisc/include/uapi/asm/kvm_para.h b/arch/openrisc/include/uapi/asm/kvm_para.h deleted file mode 100644 index 14fab8f..0000000 --- a/arch/openrisc/include/uapi/asm/kvm_para.h +++ /dev/null @@ -1 +0,0 @@ -#include -- cgit v0.10.2 From 634bd40a894d64df09ba36c12bb6e70787989ba9 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 11 Oct 2012 10:03:01 +0100 Subject: openrisc: use kbuild.h instead of defining macros in asm-offset.c This is modelled on commits such as the one below: Commit fc1c3a003edb8a6778e64e10ef671a38c76c969e ("sh: use kbuild.h instead of defining macros in asm-offsets.c") introduced in v2.6.26. Signed-off-by: James Hogan Signed-off-by: Jonas Bonn diff --git a/arch/openrisc/kernel/asm-offsets.c b/arch/openrisc/kernel/asm-offsets.c index 1a242a0..ddb7368 100644 --- a/arch/openrisc/kernel/asm-offsets.c +++ b/arch/openrisc/kernel/asm-offsets.c @@ -34,15 +34,11 @@ #include #include #include +#include #include #include #include -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define BLANK() asm volatile("\n->" : : ) - int main(void) { /* offsets into the task_struct */ -- cgit v0.10.2 From 9b04ebd1584766229c58fedaa8fe4dfff575ac3a Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 23 Oct 2012 10:21:57 +0100 Subject: asm-generic/io.h: remove asm/cacheflush.h include Including from prevents cacheflush.h being able to use I/O functions like readl and writel due to circular include dependencies. It doesn't appear as if anything from cacheflush.h is actually used by the generic io.h, so remove the include. I've compile tested a defconfig compilation of blackfin, openrisc (which needed including from it's to get the PAGE_* definitions), and xtensa. Other architectures which use asm-generic/io.h are score and unicore32, and looking at their io.h I don't see any obvious problems. Signed-off-by: James Hogan Acked-by: Jonas Bonn Cc: Chris Zankel Cc: Max Filippov Cc: Mike Frysinger Cc: Chen Liqin Cc: Lennox Wu Cc: Guan Xuetao Signed-off-by: Arnd Bergmann diff --git a/arch/openrisc/include/asm/io.h b/arch/openrisc/include/asm/io.h index 07f5299..7c69139 100644 --- a/arch/openrisc/include/asm/io.h +++ b/arch/openrisc/include/asm/io.h @@ -30,6 +30,7 @@ #define PIO_MASK 0 #include +#include extern void __iomem *__ioremap(phys_addr_t offset, unsigned long size, pgprot_t prot); diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index 448303b..616eea5 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h @@ -12,7 +12,6 @@ #define __ASM_GENERIC_IO_H #include /* I/O is all done through memory accesses */ -#include #include #ifdef CONFIG_GENERIC_IOMAP -- cgit v0.10.2 From 6a059abdbae7b6b35ddc69f6336f7afc1ce79bac Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Oct 2012 14:14:21 +0800 Subject: UBI: use list_move_tail instead of list_del/list_add_tail Using list_move_tail() instead of list_del() + list_add_tail(). dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Acked-by: Richard Weinberger Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 1a5f53c..0648c69 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -814,10 +814,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (max_sqnum > ai->max_sqnum) ai->max_sqnum = max_sqnum; - list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) { - list_del(&tmp_aeb->u.list); - list_add_tail(&tmp_aeb->u.list, &ai->free); - } + list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) + list_move_tail(&tmp_aeb->u.list, &ai->free); /* * If fastmap is leaking PEBs (must not happen), raise a -- cgit v0.10.2 From b2656a138ab7bc4e7abd3b1cbd6d1f105c7a7186 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 17 Oct 2012 16:45:01 +0100 Subject: asm-generic: io: remove {read,write} string functions The {read,write}s{b,w,l} functions are not defined across all architectures and therefore shouldn't be used by portable drivers. We should encourage driver writers to use the io{read,write}{8,16,32}_rep functions instead. This patch removes the {read,write} string functions for the generic IO header as they have no place in a new architecture port. Cc: Arnd Bergmann Cc: Mike Frysinger Cc: Ben Herrenschmidt Signed-off-by: Will Deacon diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index 616eea5..063ce76 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h @@ -216,36 +216,6 @@ static inline void outsl(unsigned long addr, const void *buffer, int count) } #endif -static inline void readsl(const void __iomem *addr, void *buf, int len) -{ - insl(addr - PCI_IOBASE, buf, len); -} - -static inline void readsw(const void __iomem *addr, void *buf, int len) -{ - insw(addr - PCI_IOBASE, buf, len); -} - -static inline void readsb(const void __iomem *addr, void *buf, int len) -{ - insb(addr - PCI_IOBASE, buf, len); -} - -static inline void writesl(const void __iomem *addr, const void *buf, int len) -{ - outsl(addr - PCI_IOBASE, buf, len); -} - -static inline void writesw(const void __iomem *addr, const void *buf, int len) -{ - outsw(addr - PCI_IOBASE, buf, len); -} - -static inline void writesb(const void __iomem *addr, const void *buf, int len) -{ - outsb(addr - PCI_IOBASE, buf, len); -} - #ifndef CONFIG_GENERIC_IOMAP #define ioread8(addr) readb(addr) #define ioread16(addr) readw(addr) -- cgit v0.10.2 From d125a753425b9de3c251df519e521024c79c663d Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 26 Oct 2012 16:11:26 +0300 Subject: UBI: do not allocate the memory unnecessarily UBI reserves an LEB sized buffer for various needs. We can use this buffer while scanning, instead of allocating another one. This patch was originally created by Jan Luebbe , but then he dropped it and I picked up and tweaked a little bit. Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index fec406b..72fed30 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -322,7 +322,6 @@ static struct ubi_ainf_volume *add_volume(struct ubi_attach_info *ai, int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, int pnum, const struct ubi_vid_hdr *vid_hdr) { - void *buf; int len, err, second_is_newer, bitflips = 0, corrupted = 0; uint32_t data_crc, crc; struct ubi_vid_hdr *vh = NULL; @@ -393,18 +392,14 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, /* Read the data of the copy and check the CRC */ len = be32_to_cpu(vid_hdr->data_size); - buf = vmalloc(len); - if (!buf) { - err = -ENOMEM; - goto out_free_vidh; - } - err = ubi_io_read_data(ubi, buf, pnum, 0, len); + mutex_lock(&ubi->buf_mutex); + err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, len); if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) - goto out_free_buf; + goto out_unlock; data_crc = be32_to_cpu(vid_hdr->data_crc); - crc = crc32(UBI_CRC32_INIT, buf, len); + crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, len); if (crc != data_crc) { dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x", pnum, crc, data_crc); @@ -415,8 +410,8 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, dbg_bld("PEB %d CRC is OK", pnum); bitflips = !!err; } + mutex_unlock(&ubi->buf_mutex); - vfree(buf); ubi_free_vid_hdr(ubi, vh); if (second_is_newer) @@ -426,8 +421,8 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, return second_is_newer | (bitflips << 1) | (corrupted << 2); -out_free_buf: - vfree(buf); +out_unlock: + mutex_unlock(&ubi->buf_mutex); out_free_vidh: ubi_free_vid_hdr(ubi, vh); return err; -- cgit v0.10.2 From 0f9831a89310cebba52d3f526e6cc5c2e403e6f1 Mon Sep 17 00:00:00 2001 From: David Zafman Date: Thu, 18 Oct 2012 14:01:43 -0700 Subject: ceph: fix dentry reference leak in encode_fh() Call to d_find_alias() needs a corresponding dput() This fixes http://tracker.newdream.net/issues/3271 Signed-off-by: David Zafman Reviewed-by: Sage Weil diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 8e1b60e..8628870 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -90,6 +90,8 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len, *max_len = handle_length; type = 255; } + if (dentry) + dput(dentry); return type; } -- cgit v0.10.2 From 7246240c7c186542f73af4fadc744d66440f616f Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 25 Oct 2012 08:49:41 -0700 Subject: libceph: avoid NULL kref_put from NULL alloc_msg return The ceph_on_in_msg_alloc() method calls the ->alloc_msg() helper which may return NULL. It also drops con->mutex while it allocates a message, which means that the connection state may change (e.g., get closed). If that happens, we clean up and bail out. Avoid calling ceph_msg_put() on a NULL return value and triggering a crash. This was observed when an ->alloc_msg() call races with a timeout that resends a zillion messages and resets the connection, and ->alloc_msg() returns NULL (because the request was resent to another target). Fixes http://tracker.newdream.net/issues/3342 Signed-off-by: Sage Weil Reviewed-by: Alex Elder diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 66f6f56..1041114 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2742,7 +2742,8 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip) msg = con->ops->alloc_msg(con, hdr, skip); mutex_lock(&con->mutex); if (con->state != CON_STATE_OPEN) { - ceph_msg_put(msg); + if (msg) + ceph_msg_put(msg); return -EAGAIN; } con->in_msg = msg; -- cgit v0.10.2 From b000056a5a8d3f5a4a9fb80184a7ec14f86a43d4 Mon Sep 17 00:00:00 2001 From: David Zafman Date: Thu, 25 Oct 2012 10:23:46 -0700 Subject: ceph: Fix NULL ptr crash in strlen() set_request_path_attr() checks for NULL ptr before calling strlen() This fixes http://tracker.newdream.net/issues/3404 Signed-off-by: David Zafman Reviewed-by: Sage Weil diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 1bcf712..62d2342 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1590,7 +1590,7 @@ static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry, } else if (rpath || rino) { *ino = rino; *ppath = rpath; - *pathlen = strlen(rpath); + *pathlen = rpath ? strlen(rpath) : 0; dout(" path %.*s\n", *pathlen, rpath); } -- cgit v0.10.2 From b213e0b1a62637b2a9395a34349b13d73ca2b90a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 10 Oct 2012 21:19:13 -0700 Subject: rbd: fix bug in rbd_dev_id_put() In rbd_dev_id_put(), there's a loop that's intended to determine the maximum device id in use. But it isn't doing that at all, the effect of how it's written is to simply use the just-put id number, which ignores whole purpose of this function. Fix the bug. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 8f56d37..4a16464 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2680,8 +2680,8 @@ static void rbd_dev_id_put(struct rbd_device *rbd_dev) struct rbd_device *rbd_dev; rbd_dev = list_entry(tmp, struct rbd_device, node); - if (rbd_id > max_id) - max_id = rbd_id; + if (rbd_dev->dev_id > max_id) + max_id = rbd_dev->dev_id; } spin_unlock(&rbd_dev_list_lock); -- cgit v0.10.2 From a0ea3a40fd20b8c66381f747c454f89d6d1f50d4 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 10 Oct 2012 21:19:13 -0700 Subject: rbd: zero return code in rbd_dev_image_id() When rbd_dev_probe() calls rbd_dev_image_id() it expects to get a 0 return code if successful, but it is getting a positive value. The reason is that rbd_dev_image_id() returns the value it gets from rbd_req_sync_exec(), which returns the number of bytes read in as a result of the request. (This ultimately comes from ceph_copy_from_page_vector() in rbd_req_sync_op()). Force the return value to 0 when successful in rbd_dev_image_id(). Do the same in rbd_dev_v2_object_prefix(). Signed-off-by: Alex Elder Reviewed-by: Josh Durgin Reviewed-by: Dan Mick diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 4a16464..94d6132 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2207,6 +2207,7 @@ static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev) dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret); if (ret < 0) goto out; + ret = 0; /* rbd_req_sync_exec() can return positive */ p = reply_buf; rbd_dev->header.object_prefix = ceph_extract_encoded_string(&p, @@ -2900,6 +2901,7 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev) dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret); if (ret < 0) goto out; + ret = 0; /* rbd_req_sync_exec() can return positive */ p = response; rbd_dev->image_id = ceph_extract_encoded_string(&p, -- cgit v0.10.2 From be466c1cc36621590ef17b05a6d342dfd33f7280 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 22 Oct 2012 11:31:26 -0500 Subject: rbd: fix read-only option name The name of the "read-only" mapping option was inadvertently changed in this commit: f84344f3 rbd: separate mapping info in rbd_dev Revert that hunk to return it to what it should be. Signed-off-by: Alex Elder Reviewed-by: Dan Mick Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 94d6132..5d9e2cc 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -397,7 +397,7 @@ enum { static match_table_t rbd_opts_tokens = { /* int args above */ /* string args above */ - {Opt_read_only, "mapping.read_only"}, + {Opt_read_only, "read_only"}, {Opt_read_only, "ro"}, /* Alternate spelling */ {Opt_read_write, "read_write"}, {Opt_read_write, "rw"}, /* Alternate spelling */ -- cgit v0.10.2 From 13f4042c05b6a1a638ccab3f0cabdb84993803a2 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 10 Oct 2012 18:59:29 -0700 Subject: rbd: kill rbd_req_{read,write}() Both rbd_req_read() and rbd_req_write() are simple wrapper routines for rbd_do_op(), and each is only called once. Replace each wrapper call with a direct call to rbd_do_op(), and get rid of the wrapper functions. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 5d9e2cc..8f2c39a 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1211,41 +1211,6 @@ done: } /* - * Request async osd write - */ -static int rbd_req_write(struct request *rq, - struct rbd_device *rbd_dev, - struct ceph_snap_context *snapc, - u64 ofs, u64 len, - struct bio *bio, - struct rbd_req_coll *coll, - int coll_index) -{ - return rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP, - CEPH_OSD_OP_WRITE, - CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, - ofs, len, bio, coll, coll_index); -} - -/* - * Request async osd read - */ -static int rbd_req_read(struct request *rq, - struct rbd_device *rbd_dev, - u64 snapid, - u64 ofs, u64 len, - struct bio *bio, - struct rbd_req_coll *coll, - int coll_index) -{ - return rbd_do_op(rq, rbd_dev, NULL, - snapid, - CEPH_OSD_OP_READ, - CEPH_OSD_FLAG_READ, - ofs, len, bio, coll, coll_index); -} - -/* * Request sync osd read */ static int rbd_req_sync_read(struct rbd_device *rbd_dev, @@ -1550,21 +1515,22 @@ static void rbd_rq_fn(struct request_queue *q) goto next_seg; } - /* init OSD command: write or read */ if (do_write) - rbd_req_write(rq, rbd_dev, - snapc, - ofs, - op_size, bio, - coll, cur_seg); + (void) rbd_do_op(rq, rbd_dev, + snapc, CEPH_NOSNAP, + CEPH_OSD_OP_WRITE, + CEPH_OSD_FLAG_WRITE | + CEPH_OSD_FLAG_ONDISK, + ofs, op_size, bio, + coll, cur_seg); else - rbd_req_read(rq, rbd_dev, - rbd_dev->mapping.snap_id, - ofs, - op_size, bio, - coll, cur_seg); - + (void) rbd_do_op(rq, rbd_dev, + NULL, rbd_dev->mapping.snap_id, + CEPH_OSD_OP_READ, + CEPH_OSD_FLAG_READ, + ofs, op_size, bio, + coll, cur_seg); next_seg: size -= op_size; ofs += op_size; -- cgit v0.10.2 From ff2e4bb5b32f89c455979a4222a9b78007cde254 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 10 Oct 2012 18:59:29 -0700 Subject: rbd: drop rbd_do_op() opcode and flags The only callers of rbd_do_op() are in rbd_rq_fn(), where call one is used for writes and the other used for reads. The request passed to rbd_do_op() already encodes the I/O direction, and that information can be used inside the function to set the opcode and flags value (rather than passing them in as arguments). So get rid of the opcode and flags arguments to rbd_do_op(). Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 8f2c39a..a29c6d2 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1164,7 +1164,6 @@ static int rbd_do_op(struct request *rq, struct rbd_device *rbd_dev, struct ceph_snap_context *snapc, u64 snapid, - int opcode, int flags, u64 ofs, u64 len, struct bio *bio, struct rbd_req_coll *coll, @@ -1176,6 +1175,8 @@ static int rbd_do_op(struct request *rq, int ret; struct ceph_osd_req_op *ops; u32 payload_len; + int opcode; + int flags; seg_name = rbd_segment_name(rbd_dev, ofs); if (!seg_name) @@ -1183,7 +1184,15 @@ static int rbd_do_op(struct request *rq, seg_len = rbd_segment_length(rbd_dev, ofs, len); seg_ofs = rbd_segment_offset(rbd_dev, ofs); - payload_len = (flags & CEPH_OSD_FLAG_WRITE ? seg_len : 0); + if (rq_data_dir(rq) == WRITE) { + opcode = CEPH_OSD_OP_WRITE; + flags = CEPH_OSD_FLAG_WRITE|CEPH_OSD_FLAG_ONDISK; + payload_len = seg_len; + } else { + opcode = CEPH_OSD_OP_READ; + flags = CEPH_OSD_FLAG_READ; + payload_len = 0; + } ret = -ENOMEM; ops = rbd_create_rw_ops(1, opcode, payload_len); @@ -1519,16 +1528,11 @@ static void rbd_rq_fn(struct request_queue *q) if (do_write) (void) rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP, - CEPH_OSD_OP_WRITE, - CEPH_OSD_FLAG_WRITE | - CEPH_OSD_FLAG_ONDISK, ofs, op_size, bio, coll, cur_seg); else (void) rbd_do_op(rq, rbd_dev, NULL, rbd_dev->mapping.snap_id, - CEPH_OSD_OP_READ, - CEPH_OSD_FLAG_READ, ofs, op_size, bio, coll, cur_seg); next_seg: -- cgit v0.10.2 From 4634246db8cb2e5117ef7c682efcc383fa3354f8 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 10 Oct 2012 18:59:29 -0700 Subject: rbd: consolidate rbd_do_op() calls The two calls to rbd_do_op() from rbd_rq_fn() differ only in the value passed for the snapshot id and the snapshot context. For reads the snapshot always comes from the mapping, and for writes the snapshot id is always CEPH_NOSNAP. The snapshot context is always null for reads. For writes, the snapshot context always comes from the rbd header, but it is acquired under protection of header semaphore and could change thereafter, so we can't simply use what's available inside rbd_do_op(). Eliminate the snapid parameter from rbd_do_op(), and set it based on the I/O direction inside that function instead. Always pass the snapshot context acquired in the caller, but reset it to a null pointer inside rbd_do_op() if the operation is a read. As a result, there is no difference in the read and write calls to rbd_do_op() made in rbd_rq_fn(), so just call it unconditionally. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index a29c6d2..d032883 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1163,7 +1163,6 @@ done: static int rbd_do_op(struct request *rq, struct rbd_device *rbd_dev, struct ceph_snap_context *snapc, - u64 snapid, u64 ofs, u64 len, struct bio *bio, struct rbd_req_coll *coll, @@ -1177,6 +1176,7 @@ static int rbd_do_op(struct request *rq, u32 payload_len; int opcode; int flags; + u64 snapid; seg_name = rbd_segment_name(rbd_dev, ofs); if (!seg_name) @@ -1187,10 +1187,13 @@ static int rbd_do_op(struct request *rq, if (rq_data_dir(rq) == WRITE) { opcode = CEPH_OSD_OP_WRITE; flags = CEPH_OSD_FLAG_WRITE|CEPH_OSD_FLAG_ONDISK; + snapid = CEPH_NOSNAP; payload_len = seg_len; } else { opcode = CEPH_OSD_OP_READ; flags = CEPH_OSD_FLAG_READ; + snapc = NULL; + snapid = rbd_dev->mapping.snap_id; payload_len = 0; } @@ -1518,24 +1521,13 @@ static void rbd_rq_fn(struct request_queue *q) kref_get(&coll->kref); bio = bio_chain_clone(&rq_bio, &next_bio, &bp, op_size, GFP_ATOMIC); - if (!bio) { + if (bio) + (void) rbd_do_op(rq, rbd_dev, snapc, + ofs, op_size, + bio, coll, cur_seg); + else rbd_coll_end_req_index(rq, coll, cur_seg, -ENOMEM, op_size); - goto next_seg; - } - - /* init OSD command: write or read */ - if (do_write) - (void) rbd_do_op(rq, rbd_dev, - snapc, CEPH_NOSNAP, - ofs, op_size, bio, - coll, cur_seg); - else - (void) rbd_do_op(rq, rbd_dev, - NULL, rbd_dev->mapping.snap_id, - ofs, op_size, bio, - coll, cur_seg); -next_seg: size -= op_size; ofs += op_size; -- cgit v0.10.2 From db2388b6ee40a949084e4cdddc3b0a4357068a62 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Sat, 20 Oct 2012 22:17:27 -0500 Subject: rbd: verify rbd image order value This adds a verification that an rbd image's object order is within the upper and lower bounds supported by this implementation. It must be at least 9 (SECTOR_SHIFT), because the Linux bio system assumes that minimum granularity. It also must be less than 32 (at the moment anyway) because there exist spots in the code that store the size of a "segment" (object backing an rbd image) in a signed int variable, which can be 32 bits including the sign. We should be able to relax this limit once we've verified the code uses 64-bit types where needed. Note that the CLI tool already limits the order to the range 12-25. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index d032883..4734446 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -533,6 +533,16 @@ static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk) if (memcmp(&ondisk->text, RBD_HEADER_TEXT, sizeof (RBD_HEADER_TEXT))) return false; + /* The bio layer requires at least sector-sized I/O */ + + if (ondisk->options.order < SECTOR_SHIFT) + return false; + + /* If we use u64 in a few spots we may be able to loosen this */ + + if (ondisk->options.order > 8 * sizeof (int) - 1) + return false; + /* * The size of a snapshot header has to fit in a size_t, and * that limits the number of snapshots. -- cgit v0.10.2 From d4b125e9eb43babd14538ba61718e3db71a98d29 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 3 Jul 2012 16:01:19 -0500 Subject: rbd: increase maximum snapshot name length Change RBD_MAX_SNAP_NAME_LEN to be based on NAME_MAX. That is a practical limit for the length of a snapshot name (based on the presence of a directory using the name under /sys/bus/rbd to represent the snapshot). The /sys entry is created by prefixing it with "snap_"; define that prefix symbolically, and take its length into account in defining the snapshot name length limit. Enforce the limit in rbd_add_parse_args(). Also delete a dout() call in that function that was not meant to be committed. Signed-off-by: Alex Elder Reviewed-by: Dan Mick Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 4734446..4858d92 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -61,7 +61,10 @@ #define RBD_MINORS_PER_MAJOR 256 /* max minors per blkdev */ -#define RBD_MAX_SNAP_NAME_LEN 32 +#define RBD_SNAP_DEV_NAME_PREFIX "snap_" +#define RBD_MAX_SNAP_NAME_LEN \ + (NAME_MAX - (sizeof (RBD_SNAP_DEV_NAME_PREFIX) - 1)) + #define RBD_MAX_SNAP_COUNT 510 /* allows max snapc to fit in 4KB */ #define RBD_MAX_OPT_LEN 1024 @@ -2063,7 +2066,7 @@ static int rbd_register_snap_dev(struct rbd_snap *snap, dev->type = &rbd_snap_device_type; dev->parent = parent; dev->release = rbd_snap_dev_release; - dev_set_name(dev, "snap_%s", snap->name); + dev_set_name(dev, "%s%s", RBD_SNAP_DEV_NAME_PREFIX, snap->name); dout("%s: registering device for snapshot %s\n", __func__, snap->name); ret = device_register(dev); @@ -2797,8 +2800,13 @@ static char *rbd_add_parse_args(struct rbd_device *rbd_dev, if (!rbd_dev->image_name) goto out_err; - /* Snapshot name is optional */ + /* Snapshot name is optional; default is to use "head" */ + len = next_token(&buf); + if (len > RBD_MAX_SNAP_NAME_LEN) { + err_ptr = ERR_PTR(-ENAMETOOLONG); + goto out_err; + } if (!len) { buf = RBD_SNAP_HEAD_NAME; /* No snapshot supplied */ len = sizeof (RBD_SNAP_HEAD_NAME) - 1; @@ -2809,8 +2817,6 @@ static char *rbd_add_parse_args(struct rbd_device *rbd_dev, memcpy(snap_name, buf, len); *(snap_name + len) = '\0'; -dout(" SNAP_NAME is <%s>, len is %zd\n", snap_name, len); - return snap_name; out_err: -- cgit v0.10.2 From e5cfeed281a842a37c9da84bad2911c9b470347e Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Sat, 20 Oct 2012 22:17:27 -0500 Subject: rbd: simplify rbd_merge_bvec() The aim of this patch is to make what's going on rbd_merge_bvec() a bit more obvious than it was before. This was an issue when a recent btrfs bug led us to question whether the merge function was working correctly. Use "obj" rather than "chunk" to indicate the units whose boundaries we care about we call (rados) "objects". Signed-off-by: Alex Elder Reviewed-by: Dan Mick diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 4858d92..76fbfa1 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1566,22 +1566,41 @@ static int rbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd, struct bio_vec *bvec) { struct rbd_device *rbd_dev = q->queuedata; - unsigned int chunk_sectors; - sector_t sector; - unsigned int bio_sectors; - int max; - - chunk_sectors = 1 << (rbd_dev->header.obj_order - SECTOR_SHIFT); - sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev); - bio_sectors = bmd->bi_size >> SECTOR_SHIFT; - - max = (chunk_sectors - ((sector & (chunk_sectors - 1)) - + bio_sectors)) << SECTOR_SHIFT; - if (max < 0) - max = 0; /* bio_add cannot handle a negative return */ - if (max <= bvec->bv_len && bio_sectors == 0) - return bvec->bv_len; - return max; + sector_t sector_offset; + sector_t sectors_per_obj; + sector_t obj_sector_offset; + int ret; + + /* + * Find how far into its rbd object the partition-relative + * bio start sector is to offset relative to the enclosing + * device. + */ + sector_offset = get_start_sect(bmd->bi_bdev) + bmd->bi_sector; + sectors_per_obj = 1 << (rbd_dev->header.obj_order - SECTOR_SHIFT); + obj_sector_offset = sector_offset & (sectors_per_obj - 1); + + /* + * Compute the number of bytes from that offset to the end + * of the object. Account for what's already used by the bio. + */ + ret = (int) (sectors_per_obj - obj_sector_offset) << SECTOR_SHIFT; + if (ret > bmd->bi_size) + ret -= bmd->bi_size; + else + ret = 0; + + /* + * Don't send back more than was asked for. And if the bio + * was empty, let the whole thing through because: "Note + * that a block device *must* allow a single page to be + * added to an empty bio." + */ + rbd_assert(bvec->bv_len <= PAGE_SIZE); + if (ret > (int) bvec->bv_len || !bmd->bi_size) + ret = (int) bvec->bv_len; + + return ret; } static void rbd_free_disk(struct rbd_device *rbd_dev) -- cgit v0.10.2 From 069a4b5690a952e74157fd489833c71c73f012b3 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 22 Oct 2012 11:31:27 -0500 Subject: rbd: kill rbd_device->rbd_opts The rbd_device structure has an embedded rbd_options structure. Such a structure is needed to work with the generic ceph argument parsing code, but there's no need to keep it around once argument parsing is done. Use a local variable to hold the rbd options used in parsing in rbd_get_client(), and just transfer its content (it's just a read_only flag) into the field in the rbd_mapping sub-structure that requires that information. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin Reviewed-by: Dan Mick diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 76fbfa1..c800047 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -184,7 +184,6 @@ struct rbd_device { struct gendisk *disk; /* blkdev's gendisk and rq */ u32 image_format; /* Either 1 or 2 */ - struct rbd_options rbd_opts; struct rbd_client *rbd_client; char name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */ @@ -456,18 +455,24 @@ static int parse_rbd_opts_token(char *c, void *private) static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr, size_t mon_addr_len, char *options) { - struct rbd_options *rbd_opts = &rbd_dev->rbd_opts; + struct rbd_options rbd_opts; struct ceph_options *ceph_opts; struct rbd_client *rbdc; - rbd_opts->read_only = RBD_READ_ONLY_DEFAULT; + /* Initialize all rbd options to the defaults */ + + rbd_opts.read_only = RBD_READ_ONLY_DEFAULT; ceph_opts = ceph_parse_options(options, mon_addr, mon_addr + mon_addr_len, - parse_rbd_opts_token, rbd_opts); + parse_rbd_opts_token, &rbd_opts); if (IS_ERR(ceph_opts)) return PTR_ERR(ceph_opts); + /* Record the parsed rbd options */ + + rbd_dev->mapping.read_only = rbd_opts.read_only; + rbdc = rbd_client_find(ceph_opts); if (rbdc) { /* using an existing client */ @@ -685,7 +690,6 @@ static int rbd_dev_set_mapping(struct rbd_device *rbd_dev, char *snap_name) rbd_dev->mapping.size = rbd_dev->header.image_size; rbd_dev->mapping.features = rbd_dev->header.features; rbd_dev->mapping.snap_exists = false; - rbd_dev->mapping.read_only = rbd_dev->rbd_opts.read_only; ret = 0; } else { ret = snap_by_name(rbd_dev, snap_name); -- cgit v0.10.2 From 3b11292381aa5c57ceb6e089797afdd2e4066085 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 30 Oct 2012 00:24:41 -0700 Subject: Input: ALPS - print small buffers via %*ph Signed-off-by: Andy Shevchenko Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index cf5af1f..e229fa3 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -767,9 +767,8 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) psmouse->packet[5]) & 0x80) || (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { psmouse_dbg(psmouse, - "refusing packet %x %x %x %x (suspected interleaved ps/2)\n", - psmouse->packet[3], psmouse->packet[4], - psmouse->packet[5], psmouse->packet[6]); + "refusing packet %4ph (suspected interleaved ps/2)\n", + psmouse->packet + 3); return PSMOUSE_BAD_DATA; } @@ -831,9 +830,8 @@ static void alps_flush_packet(unsigned long data) psmouse->packet[4] | psmouse->packet[5]) & 0x80) { psmouse_dbg(psmouse, - "refusing packet %x %x %x (suspected interleaved ps/2)\n", - psmouse->packet[3], psmouse->packet[4], - psmouse->packet[5]); + "refusing packet %3ph (suspected interleaved ps/2)\n", + psmouse->packet + 3); } else { alps_process_packet(psmouse); } -- cgit v0.10.2 From 8ed2757edd0c6bacf20c1c55bd53a0acba565be8 Mon Sep 17 00:00:00 2001 From: Ashish Jangam Date: Tue, 30 Oct 2012 00:27:25 -0700 Subject: Input: add DA9055 Onkey driver This is the ONKEY driver of the Dialog DA9055 PMIC and depends on the DA9055 MFD core driver. This driver was functionally tested on SMDK6410 board. Signed-off-by: David Dajun Chen Signed-off-by: Ashish Jangam Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index a7719a2..c835357 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -483,6 +483,16 @@ config INPUT_DA9052_ONKEY To compile this driver as a module, choose M here: the module will be called da9052_onkey. +config INPUT_DA9055_ONKEY + tristate "Dialog Semiconductor DA9055 ONKEY" + depends on MFD_DA9055 + help + Support the ONKEY of DA9055 PMICs as an input device + reporting power button status. + + To compile this driver as a module, choose M here: the module + will be called da9055_onkey. + config INPUT_DM355EVM tristate "TI DaVinci DM355 EVM Keypad and IR Remote" depends on MFD_DM355EVM_MSP diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 83fe6f5..23347e3 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o +obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c new file mode 100644 index 0000000..10ebf15 --- /dev/null +++ b/drivers/input/misc/da9055_onkey.c @@ -0,0 +1,171 @@ +/* + * ON pin driver for Dialog DA9055 PMICs + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include + +#include +#include + +struct da9055_onkey { + struct da9055 *da9055; + struct input_dev *input; + struct delayed_work work; +}; + +static void da9055_onkey_query(struct da9055_onkey *onkey) +{ + int key_stat; + + key_stat = da9055_reg_read(onkey->da9055, DA9055_REG_STATUS_A); + if (key_stat < 0) { + dev_err(onkey->da9055->dev, + "Failed to read onkey event %d\n", key_stat); + } else { + key_stat &= DA9055_NOKEY_STS; + /* + * Onkey status bit is cleared when onkey button is relased. + */ + if (!key_stat) { + input_report_key(onkey->input, KEY_POWER, 0); + input_sync(onkey->input); + } + } + + /* + * Interrupt is generated only when the ONKEY pin is asserted. + * Hence the deassertion of the pin is simulated through work queue. + */ + if (key_stat) + schedule_delayed_work(&onkey->work, msecs_to_jiffies(10)); + +} + +static void da9055_onkey_work(struct work_struct *work) +{ + struct da9055_onkey *onkey = container_of(work, struct da9055_onkey, + work.work); + + da9055_onkey_query(onkey); +} + +static irqreturn_t da9055_onkey_irq(int irq, void *data) +{ + struct da9055_onkey *onkey = data; + + input_report_key(onkey->input, KEY_POWER, 1); + input_sync(onkey->input); + + da9055_onkey_query(onkey); + + return IRQ_HANDLED; +} + +static int __devinit da9055_onkey_probe(struct platform_device *pdev) +{ + struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent); + struct da9055_onkey *onkey; + struct input_dev *input_dev; + int irq, err; + + irq = platform_get_irq_byname(pdev, "ONKEY"); + if (irq < 0) { + dev_err(&pdev->dev, + "Failed to get an IRQ for input device, %d\n", irq); + return -EINVAL; + } + + onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL); + if (!onkey) { + dev_err(&pdev->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&pdev->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + onkey->input = input_dev; + onkey->da9055 = da9055; + input_dev->name = "da9055-onkey"; + input_dev->phys = "da9055-onkey/input0"; + input_dev->dev.parent = &pdev->dev; + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + __set_bit(KEY_POWER, input_dev->keybit); + + INIT_DELAYED_WORK(&onkey->work, da9055_onkey_work); + + irq = regmap_irq_get_virq(da9055->irq_data, irq); + err = request_threaded_irq(irq, NULL, da9055_onkey_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "ONKEY", onkey); + if (err < 0) { + dev_err(&pdev->dev, + "Failed to register ONKEY IRQ %d, error = %d\n", + irq, err); + goto err_free_input; + } + + err = input_register_device(input_dev); + if (err) { + dev_err(&pdev->dev, "Unable to register input device, %d\n", + err); + goto err_free_irq; + } + + platform_set_drvdata(pdev, onkey); + + return 0; + +err_free_irq: + free_irq(irq, onkey); + cancel_delayed_work_sync(&onkey->work); +err_free_input: + input_free_device(input_dev); + + return err; +} + +static int __devexit da9055_onkey_remove(struct platform_device *pdev) +{ + struct da9055_onkey *onkey = platform_get_drvdata(pdev); + int irq = platform_get_irq_byname(pdev, "ONKEY"); + + irq = regmap_irq_get_virq(onkey->da9055->irq_data, irq); + free_irq(irq, onkey); + cancel_delayed_work_sync(&onkey->work); + input_unregister_device(onkey->input); + + return 0; +} + +static struct platform_driver da9055_onkey_driver = { + .probe = da9055_onkey_probe, + .remove = __devexit_p(da9055_onkey_remove), + .driver = { + .name = "da9055-onkey", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(da9055_onkey_driver); + +MODULE_AUTHOR("David Dajun Chen "); +MODULE_DESCRIPTION("Onkey driver for DA9055"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-onkey"); -- cgit v0.10.2 From 0ed7285e0001b960c888e5455ae982025210ed3d Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 29 Oct 2012 11:01:42 -0700 Subject: libceph: fix osdmap decode error paths Ensure that we set the err value correctly so that we do not pass a 0 value to ERR_PTR and confuse the calling code. (In particular, osd_client.c handle_map() will BUG(!newmap)). Signed-off-by: Sage Weil Reviewed-by: Alex Elder diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 5433fb0..f552aa4 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -645,10 +645,12 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) ceph_decode_32_safe(p, end, max, bad); while (max--) { ceph_decode_need(p, end, 4 + 1 + sizeof(pi->v), bad); + err = -ENOMEM; pi = kzalloc(sizeof(*pi), GFP_NOFS); if (!pi) goto bad; pi->id = ceph_decode_32(p); + err = -EINVAL; ev = ceph_decode_8(p); /* encoding version */ if (ev > CEPH_PG_POOL_VERSION) { pr_warning("got unknown v %d > %d of ceph_pg_pool\n", @@ -664,8 +666,13 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) __insert_pg_pool(&map->pg_pools, pi); } - if (version >= 5 && __decode_pool_names(p, end, map) < 0) - goto bad; + if (version >= 5) { + err = __decode_pool_names(p, end, map); + if (err < 0) { + dout("fail to decode pool names"); + goto bad; + } + } ceph_decode_32_safe(p, end, map->pool_max, bad); @@ -745,7 +752,7 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) return map; bad: - dout("osdmap_decode fail\n"); + dout("osdmap_decode fail err %d\n", err); ceph_osdmap_destroy(map); return ERR_PTR(err); } @@ -839,6 +846,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, if (ev > CEPH_PG_POOL_VERSION) { pr_warning("got unknown v %d > %d of ceph_pg_pool\n", ev, CEPH_PG_POOL_VERSION); + err = -EINVAL; goto bad; } pi = __lookup_pg_pool(&map->pg_pools, pool); @@ -855,8 +863,11 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, if (err < 0) goto bad; } - if (version >= 5 && __decode_pool_names(p, end, map) < 0) - goto bad; + if (version >= 5) { + err = __decode_pool_names(p, end, map); + if (err < 0) + goto bad; + } /* old_pool */ ceph_decode_32_safe(p, end, len, bad); @@ -932,15 +943,13 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, (void) __remove_pg_mapping(&map->pg_temp, pgid); /* insert */ - if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) { - err = -EINVAL; + err = -EINVAL; + if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) goto bad; - } + err = -ENOMEM; pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS); - if (!pg) { - err = -ENOMEM; + if (!pg) goto bad; - } pg->pgid = pgid; pg->len = pglen; for (j = 0; j < pglen; j++) -- cgit v0.10.2 From f7760dad286829682a8d36f4563ab20a65732414 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Sat, 20 Oct 2012 22:17:27 -0500 Subject: rbd: simplify rbd_rq_fn() When processing a request, rbd_rq_fn() makes clones of the bio's in the request's bio chain and submits the results to osd's to be satisfied. If a request bio straddles the boundary between objects backing the rbd image, it must be represented by two cloned bio's, one for the first part (at the end of one object) and one for the second (at the beginning of the next object). This has been handled by a function bio_chain_clone(), which includes an interface only a mother could love, and which has been found to have other problems. This patch defines two new fairly generic bio functions (one which replaces bio_chain_clone()) to help out the situation, and then revises rbd_rq_fn() to make use of them. First, bio_clone_range() clones a portion of a single bio, starting at a given offset within the bio and including only as many bytes as requested. As a convenience, a request to clone the entire bio is passed directly to bio_clone(). Second, bio_chain_clone_range() performs a similar function, producing a chain of cloned bio's covering a sub-range of the source chain. No bio_pair structures are used, and if successful the result will represent exactly the specified range. Using bio_chain_clone_range() makes bio_rq_fn() a little easier to understand, because it avoids the need to pass very much state information between consecutive calls. By avoiding the need to track a bio_pair structure, it also eliminates the problem described here: http://tracker.newdream.net/issues/2933 Note that a block request (and therefore the complete length of a bio chain processed in rbd_rq_fn()) is an unsigned int, while the result of rbd_segment_length() is u64. This change makes this range trunctation explicit, and trips a bug if the the segment boundary is too far off. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index c800047..cc06c55 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -826,77 +826,144 @@ static void zero_bio_chain(struct bio *chain, int start_ofs) } /* - * bio_chain_clone - clone a chain of bios up to a certain length. - * might return a bio_pair that will need to be released. + * Clone a portion of a bio, starting at the given byte offset + * and continuing for the number of bytes indicated. */ -static struct bio *bio_chain_clone(struct bio **old, struct bio **next, - struct bio_pair **bp, - int len, gfp_t gfpmask) -{ - struct bio *old_chain = *old; - struct bio *new_chain = NULL; - struct bio *tail; - int total = 0; - - if (*bp) { - bio_pair_release(*bp); - *bp = NULL; - } +static struct bio *bio_clone_range(struct bio *bio_src, + unsigned int offset, + unsigned int len, + gfp_t gfpmask) +{ + struct bio_vec *bv; + unsigned int resid; + unsigned short idx; + unsigned int voff; + unsigned short end_idx; + unsigned short vcnt; + struct bio *bio; - while (old_chain && (total < len)) { - struct bio *tmp; + /* Handle the easy case for the caller */ - tmp = bio_kmalloc(gfpmask, old_chain->bi_max_vecs); - if (!tmp) - goto err_out; - gfpmask &= ~__GFP_WAIT; /* can't wait after the first */ + if (!offset && len == bio_src->bi_size) + return bio_clone(bio_src, gfpmask); - if (total + old_chain->bi_size > len) { - struct bio_pair *bp; + if (WARN_ON_ONCE(!len)) + return NULL; + if (WARN_ON_ONCE(len > bio_src->bi_size)) + return NULL; + if (WARN_ON_ONCE(offset > bio_src->bi_size - len)) + return NULL; - /* - * this split can only happen with a single paged bio, - * split_bio will BUG_ON if this is not the case - */ - dout("bio_chain_clone split! total=%d remaining=%d" - "bi_size=%u\n", - total, len - total, old_chain->bi_size); + /* Find first affected segment... */ - /* split the bio. We'll release it either in the next - call, or it will have to be released outside */ - bp = bio_split(old_chain, (len - total) / SECTOR_SIZE); - if (!bp) - goto err_out; + resid = offset; + __bio_for_each_segment(bv, bio_src, idx, 0) { + if (resid < bv->bv_len) + break; + resid -= bv->bv_len; + } + voff = resid; - __bio_clone(tmp, &bp->bio1); + /* ...and the last affected segment */ - *next = &bp->bio2; - } else { - __bio_clone(tmp, old_chain); - *next = old_chain->bi_next; - } + resid += len; + __bio_for_each_segment(bv, bio_src, end_idx, idx) { + if (resid <= bv->bv_len) + break; + resid -= bv->bv_len; + } + vcnt = end_idx - idx + 1; + + /* Build the clone */ + + bio = bio_alloc(gfpmask, (unsigned int) vcnt); + if (!bio) + return NULL; /* ENOMEM */ - tmp->bi_bdev = NULL; - tmp->bi_next = NULL; - if (new_chain) - tail->bi_next = tmp; - else - new_chain = tmp; - tail = tmp; - old_chain = old_chain->bi_next; + bio->bi_bdev = bio_src->bi_bdev; + bio->bi_sector = bio_src->bi_sector + (offset >> SECTOR_SHIFT); + bio->bi_rw = bio_src->bi_rw; + bio->bi_flags |= 1 << BIO_CLONED; - total += tmp->bi_size; + /* + * Copy over our part of the bio_vec, then update the first + * and last (or only) entries. + */ + memcpy(&bio->bi_io_vec[0], &bio_src->bi_io_vec[idx], + vcnt * sizeof (struct bio_vec)); + bio->bi_io_vec[0].bv_offset += voff; + if (vcnt > 1) { + bio->bi_io_vec[0].bv_len -= voff; + bio->bi_io_vec[vcnt - 1].bv_len = resid; + } else { + bio->bi_io_vec[0].bv_len = len; } - rbd_assert(total == len); + bio->bi_vcnt = vcnt; + bio->bi_size = len; + bio->bi_idx = 0; + + return bio; +} + +/* + * Clone a portion of a bio chain, starting at the given byte offset + * into the first bio in the source chain and continuing for the + * number of bytes indicated. The result is another bio chain of + * exactly the given length, or a null pointer on error. + * + * The bio_src and offset parameters are both in-out. On entry they + * refer to the first source bio and the offset into that bio where + * the start of data to be cloned is located. + * + * On return, bio_src is updated to refer to the bio in the source + * chain that contains first un-cloned byte, and *offset will + * contain the offset of that byte within that bio. + */ +static struct bio *bio_chain_clone_range(struct bio **bio_src, + unsigned int *offset, + unsigned int len, + gfp_t gfpmask) +{ + struct bio *bi = *bio_src; + unsigned int off = *offset; + struct bio *chain = NULL; + struct bio **end; + + /* Build up a chain of clone bios up to the limit */ + + if (!bi || off >= bi->bi_size || !len) + return NULL; /* Nothing to clone */ - *old = old_chain; + end = &chain; + while (len) { + unsigned int bi_size; + struct bio *bio; + + if (!bi) + goto out_err; /* EINVAL; ran out of bio's */ + bi_size = min_t(unsigned int, bi->bi_size - off, len); + bio = bio_clone_range(bi, off, bi_size, gfpmask); + if (!bio) + goto out_err; /* ENOMEM */ + + *end = bio; + end = &bio->bi_next; + + off += bi_size; + if (off == bi->bi_size) { + bi = bi->bi_next; + off = 0; + } + len -= bi_size; + } + *bio_src = bi; + *offset = off; - return new_chain; + return chain; +out_err: + bio_chain_put(chain); -err_out: - dout("bio_chain_clone with err\n"); - bio_chain_put(new_chain); return NULL; } @@ -1014,8 +1081,9 @@ static int rbd_do_request(struct request *rq, req_data->coll_index = coll_index; } - dout("rbd_do_request object_name=%s ofs=%llu len=%llu\n", object_name, - (unsigned long long) ofs, (unsigned long long) len); + dout("rbd_do_request object_name=%s ofs=%llu len=%llu coll=%p[%d]\n", + object_name, (unsigned long long) ofs, + (unsigned long long) len, coll, coll_index); osdc = &rbd_dev->rbd_client->client->osdc; req = ceph_osdc_alloc_request(osdc, flags, snapc, ops, @@ -1463,18 +1531,16 @@ static void rbd_rq_fn(struct request_queue *q) { struct rbd_device *rbd_dev = q->queuedata; struct request *rq; - struct bio_pair *bp = NULL; while ((rq = blk_fetch_request(q))) { struct bio *bio; - struct bio *rq_bio, *next_bio = NULL; bool do_write; unsigned int size; - u64 op_size = 0; u64 ofs; int num_segs, cur_seg = 0; struct rbd_req_coll *coll; struct ceph_snap_context *snapc; + unsigned int bio_offset; dout("fetched request\n"); @@ -1486,10 +1552,6 @@ static void rbd_rq_fn(struct request_queue *q) /* deduce our operation (read, write) */ do_write = (rq_data_dir(rq) == WRITE); - - size = blk_rq_bytes(rq); - ofs = blk_rq_pos(rq) * SECTOR_SIZE; - rq_bio = rq->bio; if (do_write && rbd_dev->mapping.read_only) { __blk_end_request_all(rq, -EROFS); continue; @@ -1512,6 +1574,10 @@ static void rbd_rq_fn(struct request_queue *q) up_read(&rbd_dev->header_rwsem); + size = blk_rq_bytes(rq); + ofs = blk_rq_pos(rq) * SECTOR_SIZE; + bio = rq->bio; + dout("%s 0x%x bytes at 0x%llx\n", do_write ? "write" : "read", size, (unsigned long long) blk_rq_pos(rq) * SECTOR_SIZE); @@ -1531,30 +1597,37 @@ static void rbd_rq_fn(struct request_queue *q) continue; } + bio_offset = 0; do { - /* a bio clone to be passed down to OSD req */ + u64 limit = rbd_segment_length(rbd_dev, ofs, size); + unsigned int chain_size; + struct bio *bio_chain; + + BUG_ON(limit > (u64) UINT_MAX); + chain_size = (unsigned int) limit; dout("rq->bio->bi_vcnt=%hu\n", rq->bio->bi_vcnt); - op_size = rbd_segment_length(rbd_dev, ofs, size); + kref_get(&coll->kref); - bio = bio_chain_clone(&rq_bio, &next_bio, &bp, - op_size, GFP_ATOMIC); - if (bio) + + /* Pass a cloned bio chain via an osd request */ + + bio_chain = bio_chain_clone_range(&bio, + &bio_offset, chain_size, + GFP_ATOMIC); + if (bio_chain) (void) rbd_do_op(rq, rbd_dev, snapc, - ofs, op_size, - bio, coll, cur_seg); + ofs, chain_size, + bio_chain, coll, cur_seg); else rbd_coll_end_req_index(rq, coll, cur_seg, - -ENOMEM, op_size); - size -= op_size; - ofs += op_size; + -ENOMEM, chain_size); + size -= chain_size; + ofs += chain_size; cur_seg++; - rq_bio = next_bio; } while (size > 0); kref_put(&coll->kref, rbd_coll_release); - if (bp) - bio_pair_release(bp); spin_lock_irq(q->queue_lock); ceph_put_snap_context(snapc); @@ -1564,7 +1637,7 @@ static void rbd_rq_fn(struct request_queue *q) /* * a queue callback. Makes sure that we don't create a bio that spans across * multiple osd objects. One exception would be with a single page bios, - * which we handle later at bio_chain_clone + * which we handle later at bio_chain_clone_range() */ static int rbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd, struct bio_vec *bvec) -- cgit v0.10.2 From 41f38c2b2f8b66b176a0e548ef06294343a7bfa2 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:40 -0500 Subject: rbd: remove snapshots on error in rbd_add() If rbd_dev_snaps_update() has ever been called for an rbd device structure there could be snapshot structures on its snaps list. In rbd_add(), this function is called but a subsequent error path neglected to clean up any of these snapshots. Add a call to rbd_remove_all_snaps() in the appropriate spot to remedy this. Change a couple of error labels to be a little clearer while there. Drop the leading underscores from the function name; there's nothing special about that function that they might signify. As suggested in review, the leading underscores in __rbd_remove_snap_dev() have been removed as well. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index cc06c55..c7681d4 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -228,7 +228,7 @@ static int rbd_dev_snaps_update(struct rbd_device *rbd_dev); static int rbd_dev_snaps_register(struct rbd_device *rbd_dev); static void rbd_dev_release(struct device *dev); -static void __rbd_remove_snap_dev(struct rbd_snap *snap); +static void rbd_remove_snap_dev(struct rbd_snap *snap); static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count); @@ -1787,13 +1787,13 @@ static int rbd_read_header(struct rbd_device *rbd_dev, return ret; } -static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev) +static void rbd_remove_all_snaps(struct rbd_device *rbd_dev) { struct rbd_snap *snap; struct rbd_snap *next; list_for_each_entry_safe(snap, next, &rbd_dev->snaps, node) - __rbd_remove_snap_dev(snap); + rbd_remove_snap_dev(snap); } static void rbd_update_mapping_size(struct rbd_device *rbd_dev) @@ -2146,7 +2146,7 @@ static bool rbd_snap_registered(struct rbd_snap *snap) return ret; } -static void __rbd_remove_snap_dev(struct rbd_snap *snap) +static void rbd_remove_snap_dev(struct rbd_snap *snap) { list_del(&snap->node); if (device_is_registered(&snap->dev)) @@ -2569,7 +2569,7 @@ static int rbd_dev_snaps_update(struct rbd_device *rbd_dev) if (rbd_dev->mapping.snap_id == snap->id) rbd_dev->mapping.snap_exists = false; - __rbd_remove_snap_dev(snap); + rbd_remove_snap_dev(snap); dout("%ssnap id %llu has been removed\n", rbd_dev->mapping.snap_id == snap->id ? "mapped " : "", @@ -3179,11 +3179,11 @@ static ssize_t rbd_add(struct bus_type *bus, /* no need to lock here, as rbd_dev is not registered yet */ rc = rbd_dev_snaps_update(rbd_dev); if (rc) - goto err_out_header; + goto err_out_probe; rc = rbd_dev_set_mapping(rbd_dev, snap_name); if (rc) - goto err_out_header; + goto err_out_snaps; /* generate unique id: find highest unique id, add one */ rbd_dev_id_get(rbd_dev); @@ -3247,7 +3247,9 @@ err_out_blkdev: unregister_blkdev(rbd_dev->major, rbd_dev->name); err_out_id: rbd_dev_id_put(rbd_dev); -err_out_header: +err_out_snaps: + rbd_remove_all_snaps(rbd_dev); +err_out_probe: rbd_header_free(&rbd_dev->header); err_out_client: kfree(rbd_dev->header_name); @@ -3345,7 +3347,7 @@ static ssize_t rbd_remove(struct bus_type *bus, goto done; } - __rbd_remove_all_snaps(rbd_dev); + rbd_remove_all_snaps(rbd_dev); rbd_bus_del_dev(rbd_dev); done: -- cgit v0.10.2 From 86992098e7fdb97d01feb51495a952b264a55b7c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:41 -0500 Subject: rbd: make pool_id a 64 bit value If a format 2 image has a parent, its pool id will be specified using a 64-bit value. Change the pool id we save for an image to match that. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index c7681d4..ef82e90 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -197,7 +197,7 @@ struct rbd_device { size_t image_name_len; char *header_name; char *pool_name; - int pool_id; + u64 pool_id; struct ceph_osd_event *watch_event; struct ceph_osd_request *watch_request; @@ -1113,7 +1113,7 @@ static int rbd_do_request(struct request *rq, layout->fl_stripe_unit = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER); layout->fl_stripe_count = cpu_to_le32(1); layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER); - layout->fl_pg_pool = cpu_to_le32(rbd_dev->pool_id); + layout->fl_pg_pool = cpu_to_le32((int) rbd_dev->pool_id); ret = ceph_calc_raw_layout(osdc, layout, snapid, ofs, &len, &bno, req, ops); rbd_assert(ret == 0); @@ -1982,7 +1982,7 @@ static ssize_t rbd_pool_id_show(struct device *dev, { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); - return sprintf(buf, "%d\n", rbd_dev->pool_id); + return sprintf(buf, "%llu\n", (unsigned long long) rbd_dev->pool_id); } static ssize_t rbd_name_show(struct device *dev, @@ -3170,7 +3170,7 @@ static ssize_t rbd_add(struct bus_type *bus, rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->pool_name); if (rc < 0) goto err_out_client; - rbd_dev->pool_id = rc; + rbd_dev->pool_id = (u64) rc; rc = rbd_dev_probe(rbd_dev); if (rc < 0) -- cgit v0.10.2 From 971f839a7670197366c04e99472943532caeb0dc Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:41 -0500 Subject: rbd: move snap info out of rbd_mapping struct Moving the snap_id and snap_name fields into the separate rbd_mapping structure was misguided. (And in time, perhaps we'll do away with that structure altogether...) Move these fields back into struct rbd_device. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index ef82e90..7d28ce3 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -166,8 +166,6 @@ struct rbd_snap { }; struct rbd_mapping { - char *snap_name; - u64 snap_id; u64 size; u64 features; bool snap_exists; @@ -199,6 +197,9 @@ struct rbd_device { char *pool_name; u64 pool_id; + char *snap_name; + u64 snap_id; + struct ceph_osd_event *watch_event; struct ceph_osd_request *watch_request; @@ -669,7 +670,7 @@ static int snap_by_name(struct rbd_device *rbd_dev, const char *snap_name) list_for_each_entry(snap, &rbd_dev->snaps, node) { if (!strcmp(snap_name, snap->name)) { - rbd_dev->mapping.snap_id = snap->id; + rbd_dev->snap_id = snap->id; rbd_dev->mapping.size = snap->size; rbd_dev->mapping.features = snap->features; @@ -686,7 +687,7 @@ static int rbd_dev_set_mapping(struct rbd_device *rbd_dev, char *snap_name) if (!memcmp(snap_name, RBD_SNAP_HEAD_NAME, sizeof (RBD_SNAP_HEAD_NAME))) { - rbd_dev->mapping.snap_id = CEPH_NOSNAP; + rbd_dev->snap_id = CEPH_NOSNAP; rbd_dev->mapping.size = rbd_dev->header.image_size; rbd_dev->mapping.features = rbd_dev->header.features; rbd_dev->mapping.snap_exists = false; @@ -698,7 +699,7 @@ static int rbd_dev_set_mapping(struct rbd_device *rbd_dev, char *snap_name) rbd_dev->mapping.snap_exists = true; rbd_dev->mapping.read_only = true; } - rbd_dev->mapping.snap_name = snap_name; + rbd_dev->snap_name = snap_name; done: return ret; } @@ -1278,7 +1279,7 @@ static int rbd_do_op(struct request *rq, opcode = CEPH_OSD_OP_READ; flags = CEPH_OSD_FLAG_READ; snapc = NULL; - snapid = rbd_dev->mapping.snap_id; + snapid = rbd_dev->snap_id; payload_len = 0; } @@ -1561,7 +1562,7 @@ static void rbd_rq_fn(struct request_queue *q) down_read(&rbd_dev->header_rwsem); - if (rbd_dev->mapping.snap_id != CEPH_NOSNAP && + if (rbd_dev->snap_id != CEPH_NOSNAP && !rbd_dev->mapping.snap_exists) { up_read(&rbd_dev->header_rwsem); dout("request for non-existent snapshot"); @@ -1800,7 +1801,7 @@ static void rbd_update_mapping_size(struct rbd_device *rbd_dev) { sector_t size; - if (rbd_dev->mapping.snap_id != CEPH_NOSNAP) + if (rbd_dev->snap_id != CEPH_NOSNAP) return; size = (sector_t) rbd_dev->header.image_size / SECTOR_SIZE; @@ -2011,7 +2012,7 @@ static ssize_t rbd_snap_show(struct device *dev, { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); - return sprintf(buf, "%s\n", rbd_dev->mapping.snap_name); + return sprintf(buf, "%s\n", rbd_dev->snap_name); } static ssize_t rbd_image_refresh(struct device *dev, @@ -2567,12 +2568,11 @@ static int rbd_dev_snaps_update(struct rbd_device *rbd_dev) /* Existing snapshot not in the new snap context */ - if (rbd_dev->mapping.snap_id == snap->id) + if (rbd_dev->snap_id == snap->id) rbd_dev->mapping.snap_exists = false; rbd_remove_snap_dev(snap); dout("%ssnap id %llu has been removed\n", - rbd_dev->mapping.snap_id == snap->id ? - "mapped " : "", + rbd_dev->snap_id == snap->id ? "mapped " : "", (unsigned long long) snap->id); /* Done with this list entry; advance */ @@ -3256,7 +3256,7 @@ err_out_client: rbd_put_client(rbd_dev); kfree(rbd_dev->image_id); err_out_args: - kfree(rbd_dev->mapping.snap_name); + kfree(rbd_dev->snap_name); kfree(rbd_dev->image_name); kfree(rbd_dev->pool_name); err_out_mem: @@ -3309,7 +3309,7 @@ static void rbd_dev_release(struct device *dev) rbd_header_free(&rbd_dev->header); /* done with the id, and with the rbd_dev */ - kfree(rbd_dev->mapping.snap_name); + kfree(rbd_dev->snap_name); kfree(rbd_dev->image_id); kfree(rbd_dev->header_name); kfree(rbd_dev->pool_name); -- cgit v0.10.2 From daba5fdb4c469838dcee4b8dd4fecf7be69fa218 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 26 Oct 2012 17:25:23 -0500 Subject: rbd: rename snap_exists field A Boolean field "snap_exists" in an rbd mapping is used to indicate whether a mapped snapshot has been removed from an image's snapshot context, to stop sending requests for that snapshot as soon as we know it's gone. Generalize the interpretation of this field so it applies to non-snapshot (i.e. "head") mappings. That is, define its value to be false until the mapping has been set, and then define it to be true for both snapshot mappings or head mappings. Rename the field "exists" to reflect the broader interpretation. The rbd_mapping structure is on its way out, so move the field back into the rbd_device structure. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 7d28ce3..589f565 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -168,7 +168,6 @@ struct rbd_snap { struct rbd_mapping { u64 size; u64 features; - bool snap_exists; bool read_only; }; @@ -189,6 +188,7 @@ struct rbd_device { spinlock_t lock; /* queue lock */ struct rbd_image_header header; + bool exists; char *image_id; size_t image_id_len; char *image_name; @@ -690,16 +690,15 @@ static int rbd_dev_set_mapping(struct rbd_device *rbd_dev, char *snap_name) rbd_dev->snap_id = CEPH_NOSNAP; rbd_dev->mapping.size = rbd_dev->header.image_size; rbd_dev->mapping.features = rbd_dev->header.features; - rbd_dev->mapping.snap_exists = false; ret = 0; } else { ret = snap_by_name(rbd_dev, snap_name); if (ret < 0) goto done; - rbd_dev->mapping.snap_exists = true; rbd_dev->mapping.read_only = true; } rbd_dev->snap_name = snap_name; + rbd_dev->exists = true; done: return ret; } @@ -1562,8 +1561,8 @@ static void rbd_rq_fn(struct request_queue *q) down_read(&rbd_dev->header_rwsem); - if (rbd_dev->snap_id != CEPH_NOSNAP && - !rbd_dev->mapping.snap_exists) { + if (!rbd_dev->exists) { + rbd_assert(rbd_dev->snap_id != CEPH_NOSNAP); up_read(&rbd_dev->header_rwsem); dout("request for non-existent snapshot"); spin_lock_irq(q->queue_lock); @@ -2569,7 +2568,7 @@ static int rbd_dev_snaps_update(struct rbd_device *rbd_dev) /* Existing snapshot not in the new snap context */ if (rbd_dev->snap_id == snap->id) - rbd_dev->mapping.snap_exists = false; + rbd_dev->exists = false; rbd_remove_snap_dev(snap); dout("%ssnap id %llu has been removed\n", rbd_dev->snap_id == snap->id ? "mapped " : "", -- cgit v0.10.2 From 78cea76e0580befaf561c6989f4fc985bc66c8f7 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:41 -0500 Subject: rbd: move ceph_parse_options() call up Move option parsing out of rbd_get_client() and into its caller. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 589f565..e83bddc 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -453,27 +453,11 @@ static int parse_rbd_opts_token(char *c, void *private) * Get a ceph client with specific addr and configuration, if one does * not exist create it. */ -static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr, - size_t mon_addr_len, char *options) +static int rbd_get_client(struct rbd_device *rbd_dev, + struct ceph_options *ceph_opts) { - struct rbd_options rbd_opts; - struct ceph_options *ceph_opts; struct rbd_client *rbdc; - /* Initialize all rbd options to the defaults */ - - rbd_opts.read_only = RBD_READ_ONLY_DEFAULT; - - ceph_opts = ceph_parse_options(options, mon_addr, - mon_addr + mon_addr_len, - parse_rbd_opts_token, &rbd_opts); - if (IS_ERR(ceph_opts)) - return PTR_ERR(ceph_opts); - - /* Record the parsed rbd options */ - - rbd_dev->mapping.read_only = rbd_opts.read_only; - rbdc = rbd_client_find(ceph_opts); if (rbdc) { /* using an existing client */ @@ -3132,9 +3116,11 @@ static ssize_t rbd_add(struct bus_type *bus, struct rbd_device *rbd_dev = NULL; const char *mon_addrs = NULL; size_t mon_addrs_size = 0; + char *snap_name; + struct rbd_options rbd_opts; + struct ceph_options *ceph_opts; struct ceph_osd_client *osdc; int rc = -ENOMEM; - char *snap_name; if (!try_module_get(THIS_MODULE)) return -ENODEV; @@ -3160,9 +3146,26 @@ static ssize_t rbd_add(struct bus_type *bus, goto err_out_mem; } - rc = rbd_get_client(rbd_dev, mon_addrs, mon_addrs_size - 1, options); - if (rc < 0) + /* Initialize all rbd options to the defaults */ + + rbd_opts.read_only = RBD_READ_ONLY_DEFAULT; + + ceph_opts = ceph_parse_options(options, mon_addrs, + mon_addrs + mon_addrs_size - 1, + parse_rbd_opts_token, &rbd_opts); + if (IS_ERR(ceph_opts)) { + rc = PTR_ERR(ceph_opts); goto err_out_args; + } + + /* Record the parsed rbd options */ + + rbd_dev->mapping.read_only = rbd_opts.read_only; + + rc = rbd_get_client(rbd_dev, ceph_opts); + if (rc < 0) + goto err_out_opts; + ceph_opts = NULL; /* ceph_opts now owned by rbd_dev client */ /* pick the pool */ osdc = &rbd_dev->rbd_client->client->osdc; @@ -3254,6 +3257,9 @@ err_out_client: kfree(rbd_dev->header_name); rbd_put_client(rbd_dev); kfree(rbd_dev->image_id); +err_out_opts: + if (ceph_opts) + ceph_destroy_options(ceph_opts); err_out_args: kfree(rbd_dev->snap_name); kfree(rbd_dev->image_name); -- cgit v0.10.2 From 0ddebc0c6c518ae42c376151e34d9d4b84443ba5 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:41 -0500 Subject: rbd: do all argument parsing in one place This patch makes rbd_add_parse_args() be the single place all argument parsing occurs for an image map request: - Move the ceph_parse_options() call into that function - Use local variables rather than parameters to hold the list of monitor addresses supplied - Rather than returning it, pass the snapshot name (and its length) back via parameters - Have the function return a ceph_options structure pointer Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index e83bddc..68447d8 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2845,24 +2845,27 @@ static inline char *dup_token(const char **buf, size_t *lenp) * * Note: rbd_dev is assumed to have been initially zero-filled. */ -static char *rbd_add_parse_args(struct rbd_device *rbd_dev, - const char *buf, - const char **mon_addrs, - size_t *mon_addrs_size, - char *options, - size_t options_size) +static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, + const char *buf, + char *options, + size_t options_size, + char **snap_name, + size_t *snap_name_len) { size_t len; - char *err_ptr = ERR_PTR(-EINVAL); - char *snap_name; + const char *mon_addrs; + size_t mon_addrs_size; + struct rbd_options rbd_opts; + struct ceph_options *ceph_opts; + struct ceph_options *err_ptr = ERR_PTR(-EINVAL); /* The first four tokens are required */ len = next_token(&buf); if (!len) return err_ptr; - *mon_addrs_size = len + 1; - *mon_addrs = buf; + mon_addrs_size = len + 1; + mon_addrs = buf; buf += len; @@ -2890,14 +2893,27 @@ static char *rbd_add_parse_args(struct rbd_device *rbd_dev, buf = RBD_SNAP_HEAD_NAME; /* No snapshot supplied */ len = sizeof (RBD_SNAP_HEAD_NAME) - 1; } - snap_name = kmalloc(len + 1, GFP_KERNEL); - if (!snap_name) + *snap_name = kmalloc(len + 1, GFP_KERNEL); + if (!*snap_name) goto out_err; - memcpy(snap_name, buf, len); - *(snap_name + len) = '\0'; + memcpy(*snap_name, buf, len); + *(*snap_name + len) = '\0'; + *snap_name_len = len; + /* Initialize all rbd options to the defaults */ - return snap_name; + rbd_opts.read_only = RBD_READ_ONLY_DEFAULT; + ceph_opts = ceph_parse_options(options, mon_addrs, + mon_addrs + mon_addrs_size - 1, + parse_rbd_opts_token, &rbd_opts); + + /* Record the parsed rbd options */ + + if (!IS_ERR(ceph_opts)) { + rbd_dev->mapping.read_only = rbd_opts.read_only; + } + + return ceph_opts; out_err: kfree(rbd_dev->image_name); rbd_dev->image_name = NULL; @@ -3114,10 +3130,8 @@ static ssize_t rbd_add(struct bus_type *bus, { char *options; struct rbd_device *rbd_dev = NULL; - const char *mon_addrs = NULL; - size_t mon_addrs_size = 0; char *snap_name; - struct rbd_options rbd_opts; + size_t snap_name_len = 0; struct ceph_options *ceph_opts; struct ceph_osd_client *osdc; int rc = -ENOMEM; @@ -3139,32 +3153,16 @@ static ssize_t rbd_add(struct bus_type *bus, init_rwsem(&rbd_dev->header_rwsem); /* parse add command */ - snap_name = rbd_add_parse_args(rbd_dev, buf, - &mon_addrs, &mon_addrs_size, options, count); - if (IS_ERR(snap_name)) { - rc = PTR_ERR(snap_name); - goto err_out_mem; - } - - /* Initialize all rbd options to the defaults */ - - rbd_opts.read_only = RBD_READ_ONLY_DEFAULT; - - ceph_opts = ceph_parse_options(options, mon_addrs, - mon_addrs + mon_addrs_size - 1, - parse_rbd_opts_token, &rbd_opts); + ceph_opts = rbd_add_parse_args(rbd_dev, buf, options, count, + &snap_name, &snap_name_len); if (IS_ERR(ceph_opts)) { rc = PTR_ERR(ceph_opts); - goto err_out_args; + goto err_out_mem; } - /* Record the parsed rbd options */ - - rbd_dev->mapping.read_only = rbd_opts.read_only; - rc = rbd_get_client(rbd_dev, ceph_opts); if (rc < 0) - goto err_out_opts; + goto err_out_args; ceph_opts = NULL; /* ceph_opts now owned by rbd_dev client */ /* pick the pool */ @@ -3257,10 +3255,9 @@ err_out_client: kfree(rbd_dev->header_name); rbd_put_client(rbd_dev); kfree(rbd_dev->image_id); -err_out_opts: +err_out_args: if (ceph_opts) ceph_destroy_options(ceph_opts); -err_out_args: kfree(rbd_dev->snap_name); kfree(rbd_dev->image_name); kfree(rbd_dev->pool_name); -- cgit v0.10.2 From e5c35534042f4b5957a32bba651222c91247beba Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:41 -0500 Subject: rbd: get rid of snap_name_len The value returned in the "snap_name_len" argument to rbd_add_parse_args() is never actually used, so get rid of it. The snap_name_len recorded in rbd_dev_v2_snap_name() is not useful either, so get rid of that too. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 68447d8..7bd2313 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2408,7 +2408,6 @@ static char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev, u32 which) int ret; void *p; void *end; - size_t snap_name_len; char *snap_name; size = sizeof (__le32) + RBD_MAX_SNAP_NAME_LEN; @@ -2428,9 +2427,7 @@ static char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev, u32 which) p = reply_buf; end = (char *) reply_buf + size; - snap_name_len = 0; - snap_name = ceph_extract_encoded_string(&p, end, &snap_name_len, - GFP_KERNEL); + snap_name = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL); if (IS_ERR(snap_name)) { ret = PTR_ERR(snap_name); goto out; @@ -2849,8 +2846,7 @@ static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, const char *buf, char *options, size_t options_size, - char **snap_name, - size_t *snap_name_len) + char **snap_name) { size_t len; const char *mon_addrs; @@ -2898,7 +2894,7 @@ static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, goto out_err; memcpy(*snap_name, buf, len); *(*snap_name + len) = '\0'; - *snap_name_len = len; + /* Initialize all rbd options to the defaults */ rbd_opts.read_only = RBD_READ_ONLY_DEFAULT; @@ -3131,7 +3127,6 @@ static ssize_t rbd_add(struct bus_type *bus, char *options; struct rbd_device *rbd_dev = NULL; char *snap_name; - size_t snap_name_len = 0; struct ceph_options *ceph_opts; struct ceph_osd_client *osdc; int rc = -ENOMEM; @@ -3154,7 +3149,7 @@ static ssize_t rbd_add(struct bus_type *bus, /* parse add command */ ceph_opts = rbd_add_parse_args(rbd_dev, buf, options, count, - &snap_name, &snap_name_len); + &snap_name); if (IS_ERR(ceph_opts)) { rc = PTR_ERR(ceph_opts); goto err_out_mem; -- cgit v0.10.2 From f28e565a1b15eef62618db4011d9e320089a4214 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:41 -0500 Subject: rbd: remove options args from rbd_add_parse_args() They "options" argument to rbd_add_parse_args() (and it's partner options_size) is now only needed within the function, so there's no need to have the caller allocate and pass the options buffer. Just allocate the options buffer within the function using dup_token(). Also distinguish between failures due to failed memory allocation and failing because a required argument was missing. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 7bd2313..62df67a1 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2844,54 +2844,58 @@ static inline char *dup_token(const char **buf, size_t *lenp) */ static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, const char *buf, - char *options, - size_t options_size, char **snap_name) { size_t len; const char *mon_addrs; size_t mon_addrs_size; + char *options; + struct ceph_options *err_ptr = ERR_PTR(-EINVAL); struct rbd_options rbd_opts; struct ceph_options *ceph_opts; - struct ceph_options *err_ptr = ERR_PTR(-EINVAL); /* The first four tokens are required */ len = next_token(&buf); if (!len) - return err_ptr; - mon_addrs_size = len + 1; + return err_ptr; /* Missing monitor address(es) */ mon_addrs = buf; - + mon_addrs_size = len + 1; buf += len; - len = copy_token(&buf, options, options_size); - if (!len || len >= options_size) - return err_ptr; + options = dup_token(&buf, NULL); + if (!options) + goto out_mem; + if (!*options) + goto out_err; /* Missing options */ - err_ptr = ERR_PTR(-ENOMEM); rbd_dev->pool_name = dup_token(&buf, NULL); if (!rbd_dev->pool_name) - goto out_err; + goto out_mem; + if (!*rbd_dev->pool_name) + goto out_err; /* Missing pool name */ rbd_dev->image_name = dup_token(&buf, &rbd_dev->image_name_len); if (!rbd_dev->image_name) - goto out_err; - - /* Snapshot name is optional; default is to use "head" */ + goto out_mem; + if (!*rbd_dev->image_name) + goto out_err; /* Missing image name */ + /* + * Snapshot name is optional; default is to use "-" + * (indicating the head/no snapshot). + */ len = next_token(&buf); - if (len > RBD_MAX_SNAP_NAME_LEN) { - err_ptr = ERR_PTR(-ENAMETOOLONG); - goto out_err; - } if (!len) { buf = RBD_SNAP_HEAD_NAME; /* No snapshot supplied */ len = sizeof (RBD_SNAP_HEAD_NAME) - 1; + } else if (len > RBD_MAX_SNAP_NAME_LEN) { + err_ptr = ERR_PTR(-ENAMETOOLONG); + goto out_err; } *snap_name = kmalloc(len + 1, GFP_KERNEL); if (!*snap_name) - goto out_err; + goto out_mem; memcpy(*snap_name, buf, len); *(*snap_name + len) = '\0'; @@ -2902,20 +2906,23 @@ static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, ceph_opts = ceph_parse_options(options, mon_addrs, mon_addrs + mon_addrs_size - 1, parse_rbd_opts_token, &rbd_opts); + kfree(options); /* Record the parsed rbd options */ - if (!IS_ERR(ceph_opts)) { + if (!IS_ERR(ceph_opts)) rbd_dev->mapping.read_only = rbd_opts.read_only; - } return ceph_opts; +out_mem: + err_ptr = ERR_PTR(-ENOMEM); out_err: kfree(rbd_dev->image_name); rbd_dev->image_name = NULL; rbd_dev->image_name_len = 0; kfree(rbd_dev->pool_name); rbd_dev->pool_name = NULL; + kfree(options); return err_ptr; } @@ -3124,7 +3131,6 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count) { - char *options; struct rbd_device *rbd_dev = NULL; char *snap_name; struct ceph_options *ceph_opts; @@ -3134,9 +3140,6 @@ static ssize_t rbd_add(struct bus_type *bus, if (!try_module_get(THIS_MODULE)) return -ENODEV; - options = kmalloc(count, GFP_KERNEL); - if (!options) - goto err_out_mem; rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL); if (!rbd_dev) goto err_out_mem; @@ -3148,8 +3151,7 @@ static ssize_t rbd_add(struct bus_type *bus, init_rwsem(&rbd_dev->header_rwsem); /* parse add command */ - ceph_opts = rbd_add_parse_args(rbd_dev, buf, options, count, - &snap_name); + ceph_opts = rbd_add_parse_args(rbd_dev, buf, &snap_name); if (IS_ERR(ceph_opts)) { rc = PTR_ERR(ceph_opts); goto err_out_mem; @@ -3233,7 +3235,6 @@ err_out_bus: /* this will also clean up rest of rbd_dev stuff */ rbd_bus_del_dev(rbd_dev); - kfree(options); return rc; err_out_disk: @@ -3258,7 +3259,6 @@ err_out_args: kfree(rbd_dev->pool_name); err_out_mem: kfree(rbd_dev); - kfree(options); dout("Error adding device %s\n", buf); module_put(THIS_MODULE); -- cgit v0.10.2 From 819d52bf72b61a8455024ff7863eed5d681e73c7 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:41 -0500 Subject: rbd: remove snap_name arg from rbd_add_parse_args() The snapshot name returned by rbd_add_parse_args() just gets saved in the rbd_dev eventually. So just do that inside that function and do away with the snap_name argument, both in rbd_add_parse_args() and rbd_dev_set_mapping(). Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 62df67a1..ae16cf6 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -665,23 +665,22 @@ static int snap_by_name(struct rbd_device *rbd_dev, const char *snap_name) return -ENOENT; } -static int rbd_dev_set_mapping(struct rbd_device *rbd_dev, char *snap_name) +static int rbd_dev_set_mapping(struct rbd_device *rbd_dev) { int ret; - if (!memcmp(snap_name, RBD_SNAP_HEAD_NAME, + if (!memcmp(rbd_dev->snap_name, RBD_SNAP_HEAD_NAME, sizeof (RBD_SNAP_HEAD_NAME))) { rbd_dev->snap_id = CEPH_NOSNAP; rbd_dev->mapping.size = rbd_dev->header.image_size; rbd_dev->mapping.features = rbd_dev->header.features; ret = 0; } else { - ret = snap_by_name(rbd_dev, snap_name); + ret = snap_by_name(rbd_dev, rbd_dev->snap_name); if (ret < 0) goto done; rbd_dev->mapping.read_only = true; } - rbd_dev->snap_name = snap_name; rbd_dev->exists = true; done: return ret; @@ -2843,8 +2842,7 @@ static inline char *dup_token(const char **buf, size_t *lenp) * Note: rbd_dev is assumed to have been initially zero-filled. */ static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, - const char *buf, - char **snap_name) + const char *buf) { size_t len; const char *mon_addrs; @@ -2893,11 +2891,11 @@ static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, err_ptr = ERR_PTR(-ENAMETOOLONG); goto out_err; } - *snap_name = kmalloc(len + 1, GFP_KERNEL); - if (!*snap_name) + rbd_dev->snap_name = kmalloc(len + 1, GFP_KERNEL); + if (!rbd_dev->snap_name) goto out_mem; - memcpy(*snap_name, buf, len); - *(*snap_name + len) = '\0'; + memcpy(rbd_dev->snap_name, buf, len); + *(rbd_dev->snap_name + len) = '\0'; /* Initialize all rbd options to the defaults */ @@ -3132,7 +3130,6 @@ static ssize_t rbd_add(struct bus_type *bus, size_t count) { struct rbd_device *rbd_dev = NULL; - char *snap_name; struct ceph_options *ceph_opts; struct ceph_osd_client *osdc; int rc = -ENOMEM; @@ -3151,7 +3148,7 @@ static ssize_t rbd_add(struct bus_type *bus, init_rwsem(&rbd_dev->header_rwsem); /* parse add command */ - ceph_opts = rbd_add_parse_args(rbd_dev, buf, &snap_name); + ceph_opts = rbd_add_parse_args(rbd_dev, buf); if (IS_ERR(ceph_opts)) { rc = PTR_ERR(ceph_opts); goto err_out_mem; @@ -3178,7 +3175,7 @@ static ssize_t rbd_add(struct bus_type *bus, if (rc) goto err_out_probe; - rc = rbd_dev_set_mapping(rbd_dev, snap_name); + rc = rbd_dev_set_mapping(rbd_dev); if (rc) goto err_out_snaps; -- cgit v0.10.2 From 4e9afeba7aa9ca925a79d9ce82f1a8e79e14c291 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:41 -0500 Subject: rbd: pass and populate rbd_options structure Have the caller pass the address of an rbd_options structure to rbd_add_parse_args(), to be initialized with the information gleaned as a result of the parse. I know, this is another near-reversal of a recent change... Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index ae16cf6..338cfad 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2842,15 +2842,16 @@ static inline char *dup_token(const char **buf, size_t *lenp) * Note: rbd_dev is assumed to have been initially zero-filled. */ static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, - const char *buf) + const char *buf, + struct rbd_options **opts) { size_t len; const char *mon_addrs; size_t mon_addrs_size; char *options; struct ceph_options *err_ptr = ERR_PTR(-EINVAL); - struct rbd_options rbd_opts; struct ceph_options *ceph_opts; + struct rbd_options *rbd_opts = NULL; /* The first four tokens are required */ @@ -2899,17 +2900,17 @@ static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, /* Initialize all rbd options to the defaults */ - rbd_opts.read_only = RBD_READ_ONLY_DEFAULT; + rbd_opts = kzalloc(sizeof (*rbd_opts), GFP_KERNEL); + if (!rbd_opts) + goto out_mem; + + rbd_opts->read_only = RBD_READ_ONLY_DEFAULT; ceph_opts = ceph_parse_options(options, mon_addrs, mon_addrs + mon_addrs_size - 1, - parse_rbd_opts_token, &rbd_opts); + parse_rbd_opts_token, rbd_opts); kfree(options); - - /* Record the parsed rbd options */ - - if (!IS_ERR(ceph_opts)) - rbd_dev->mapping.read_only = rbd_opts.read_only; + *opts = rbd_opts; return ceph_opts; out_mem: @@ -3131,6 +3132,7 @@ static ssize_t rbd_add(struct bus_type *bus, { struct rbd_device *rbd_dev = NULL; struct ceph_options *ceph_opts; + struct rbd_options *rbd_opts = NULL; struct ceph_osd_client *osdc; int rc = -ENOMEM; @@ -3139,7 +3141,7 @@ static ssize_t rbd_add(struct bus_type *bus, rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL); if (!rbd_dev) - goto err_out_mem; + return -ENOMEM; /* static rbd_device initialization */ spin_lock_init(&rbd_dev->lock); @@ -3148,11 +3150,12 @@ static ssize_t rbd_add(struct bus_type *bus, init_rwsem(&rbd_dev->header_rwsem); /* parse add command */ - ceph_opts = rbd_add_parse_args(rbd_dev, buf); + ceph_opts = rbd_add_parse_args(rbd_dev, buf, &rbd_opts); if (IS_ERR(ceph_opts)) { rc = PTR_ERR(ceph_opts); goto err_out_mem; } + rbd_dev->mapping.read_only = rbd_opts->read_only; rc = rbd_get_client(rbd_dev, ceph_opts); if (rc < 0) @@ -3219,6 +3222,8 @@ static ssize_t rbd_add(struct bus_type *bus, if (rc) goto err_out_bus; + kfree(rbd_opts); + /* Everything's ready. Announce the disk to the world. */ add_disk(rbd_dev->disk); @@ -3232,6 +3237,8 @@ err_out_bus: /* this will also clean up rest of rbd_dev stuff */ rbd_bus_del_dev(rbd_dev); + kfree(rbd_opts); + return rc; err_out_disk: @@ -3254,6 +3261,7 @@ err_out_args: kfree(rbd_dev->snap_name); kfree(rbd_dev->image_name); kfree(rbd_dev->pool_name); + kfree(rbd_opts); err_out_mem: kfree(rbd_dev); -- cgit v0.10.2 From dc79b113d6db48ee6ee7decf0216feee48757f01 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:41 -0500 Subject: rbd: have rbd_add_parse_args() return error Change the interface to rbd_add_parse_args() so it returns an error code rather than a pointer. Return the ceph_options result via a pointer whose address is passed as an argument. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 338cfad..ab6e6d8 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2841,30 +2841,31 @@ static inline char *dup_token(const char **buf, size_t *lenp) * * Note: rbd_dev is assumed to have been initially zero-filled. */ -static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, - const char *buf, - struct rbd_options **opts) +static int rbd_add_parse_args(struct rbd_device *rbd_dev, + const char *buf, + struct ceph_options **ceph_opts, + struct rbd_options **opts) { size_t len; const char *mon_addrs; size_t mon_addrs_size; char *options; - struct ceph_options *err_ptr = ERR_PTR(-EINVAL); - struct ceph_options *ceph_opts; struct rbd_options *rbd_opts = NULL; + int ret; /* The first four tokens are required */ len = next_token(&buf); if (!len) - return err_ptr; /* Missing monitor address(es) */ + return -EINVAL; /* Missing monitor address(es) */ mon_addrs = buf; mon_addrs_size = len + 1; buf += len; + ret = -EINVAL; options = dup_token(&buf, NULL); if (!options) - goto out_mem; + return -ENOMEM; if (!*options) goto out_err; /* Missing options */ @@ -2889,7 +2890,7 @@ static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, buf = RBD_SNAP_HEAD_NAME; /* No snapshot supplied */ len = sizeof (RBD_SNAP_HEAD_NAME) - 1; } else if (len > RBD_MAX_SNAP_NAME_LEN) { - err_ptr = ERR_PTR(-ENAMETOOLONG); + ret = -ENAMETOOLONG; goto out_err; } rbd_dev->snap_name = kmalloc(len + 1, GFP_KERNEL); @@ -2906,15 +2907,19 @@ static struct ceph_options *rbd_add_parse_args(struct rbd_device *rbd_dev, rbd_opts->read_only = RBD_READ_ONLY_DEFAULT; - ceph_opts = ceph_parse_options(options, mon_addrs, + *ceph_opts = ceph_parse_options(options, mon_addrs, mon_addrs + mon_addrs_size - 1, parse_rbd_opts_token, rbd_opts); kfree(options); + if (IS_ERR(*ceph_opts)) { + ret = PTR_ERR(*ceph_opts); + goto out_err; + } *opts = rbd_opts; - return ceph_opts; + return 0; out_mem: - err_ptr = ERR_PTR(-ENOMEM); + ret = -ENOMEM; out_err: kfree(rbd_dev->image_name); rbd_dev->image_name = NULL; @@ -2923,7 +2928,7 @@ out_err: rbd_dev->pool_name = NULL; kfree(options); - return err_ptr; + return ret; } /* @@ -3131,7 +3136,7 @@ static ssize_t rbd_add(struct bus_type *bus, size_t count) { struct rbd_device *rbd_dev = NULL; - struct ceph_options *ceph_opts; + struct ceph_options *ceph_opts = NULL; struct rbd_options *rbd_opts = NULL; struct ceph_osd_client *osdc; int rc = -ENOMEM; @@ -3150,11 +3155,9 @@ static ssize_t rbd_add(struct bus_type *bus, init_rwsem(&rbd_dev->header_rwsem); /* parse add command */ - ceph_opts = rbd_add_parse_args(rbd_dev, buf, &rbd_opts); - if (IS_ERR(ceph_opts)) { - rc = PTR_ERR(ceph_opts); + rc = rbd_add_parse_args(rbd_dev, buf, &ceph_opts, &rbd_opts); + if (rc < 0) goto err_out_mem; - } rbd_dev->mapping.read_only = rbd_opts->read_only; rc = rbd_get_client(rbd_dev, ceph_opts); -- cgit v0.10.2 From 0d7dbfce9d6e3a57a6946fadf7f92b1792b8acc0 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:41 -0500 Subject: rbd: define image specification structure Group the fields that uniquely specify an rbd image into a new reference-counted rbd_spec structure. This structure will be used to describe the desired image when mapping an image, and when probing parent images in layered rbd devices. Replace the set of fields in the rbd device structure with a pointer to a dynamically allocated rbd_spec. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index ab6e6d8..2049810 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -112,6 +112,27 @@ struct rbd_image_header { u64 obj_version; }; +/* + * An rbd image specification. + * + * The tuple (pool_id, image_id, snap_id) is sufficient to uniquely + * identify an image. + */ +struct rbd_spec { + u64 pool_id; + char *pool_name; + + char *image_id; + size_t image_id_len; + char *image_name; + size_t image_name_len; + + u64 snap_id; + char *snap_name; + + struct kref kref; +}; + struct rbd_options { bool read_only; }; @@ -189,16 +210,9 @@ struct rbd_device { struct rbd_image_header header; bool exists; - char *image_id; - size_t image_id_len; - char *image_name; - size_t image_name_len; - char *header_name; - char *pool_name; - u64 pool_id; + struct rbd_spec *spec; - char *snap_name; - u64 snap_id; + char *header_name; struct ceph_osd_event *watch_event; struct ceph_osd_request *watch_request; @@ -654,7 +668,7 @@ static int snap_by_name(struct rbd_device *rbd_dev, const char *snap_name) list_for_each_entry(snap, &rbd_dev->snaps, node) { if (!strcmp(snap_name, snap->name)) { - rbd_dev->snap_id = snap->id; + rbd_dev->spec->snap_id = snap->id; rbd_dev->mapping.size = snap->size; rbd_dev->mapping.features = snap->features; @@ -669,14 +683,14 @@ static int rbd_dev_set_mapping(struct rbd_device *rbd_dev) { int ret; - if (!memcmp(rbd_dev->snap_name, RBD_SNAP_HEAD_NAME, + if (!memcmp(rbd_dev->spec->snap_name, RBD_SNAP_HEAD_NAME, sizeof (RBD_SNAP_HEAD_NAME))) { - rbd_dev->snap_id = CEPH_NOSNAP; + rbd_dev->spec->snap_id = CEPH_NOSNAP; rbd_dev->mapping.size = rbd_dev->header.image_size; rbd_dev->mapping.features = rbd_dev->header.features; ret = 0; } else { - ret = snap_by_name(rbd_dev, rbd_dev->snap_name); + ret = snap_by_name(rbd_dev, rbd_dev->spec->snap_name); if (ret < 0) goto done; rbd_dev->mapping.read_only = true; @@ -1096,7 +1110,7 @@ static int rbd_do_request(struct request *rq, layout->fl_stripe_unit = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER); layout->fl_stripe_count = cpu_to_le32(1); layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER); - layout->fl_pg_pool = cpu_to_le32((int) rbd_dev->pool_id); + layout->fl_pg_pool = cpu_to_le32((int) rbd_dev->spec->pool_id); ret = ceph_calc_raw_layout(osdc, layout, snapid, ofs, &len, &bno, req, ops); rbd_assert(ret == 0); @@ -1261,7 +1275,7 @@ static int rbd_do_op(struct request *rq, opcode = CEPH_OSD_OP_READ; flags = CEPH_OSD_FLAG_READ; snapc = NULL; - snapid = rbd_dev->snap_id; + snapid = rbd_dev->spec->snap_id; payload_len = 0; } @@ -1545,7 +1559,7 @@ static void rbd_rq_fn(struct request_queue *q) down_read(&rbd_dev->header_rwsem); if (!rbd_dev->exists) { - rbd_assert(rbd_dev->snap_id != CEPH_NOSNAP); + rbd_assert(rbd_dev->spec->snap_id != CEPH_NOSNAP); up_read(&rbd_dev->header_rwsem); dout("request for non-existent snapshot"); spin_lock_irq(q->queue_lock); @@ -1726,13 +1740,13 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev, u64 *version) ret = -ENXIO; pr_warning("short header read for image %s" " (want %zd got %d)\n", - rbd_dev->image_name, size, ret); + rbd_dev->spec->image_name, size, ret); goto out_err; } if (!rbd_dev_ondisk_valid(ondisk)) { ret = -ENXIO; pr_warning("invalid header for image %s\n", - rbd_dev->image_name); + rbd_dev->spec->image_name); goto out_err; } @@ -1783,7 +1797,7 @@ static void rbd_update_mapping_size(struct rbd_device *rbd_dev) { sector_t size; - if (rbd_dev->snap_id != CEPH_NOSNAP) + if (rbd_dev->spec->snap_id != CEPH_NOSNAP) return; size = (sector_t) rbd_dev->header.image_size / SECTOR_SIZE; @@ -1957,7 +1971,7 @@ static ssize_t rbd_pool_show(struct device *dev, { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); - return sprintf(buf, "%s\n", rbd_dev->pool_name); + return sprintf(buf, "%s\n", rbd_dev->spec->pool_name); } static ssize_t rbd_pool_id_show(struct device *dev, @@ -1965,7 +1979,8 @@ static ssize_t rbd_pool_id_show(struct device *dev, { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); - return sprintf(buf, "%llu\n", (unsigned long long) rbd_dev->pool_id); + return sprintf(buf, "%llu\n", + (unsigned long long) rbd_dev->spec->pool_id); } static ssize_t rbd_name_show(struct device *dev, @@ -1973,7 +1988,7 @@ static ssize_t rbd_name_show(struct device *dev, { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); - return sprintf(buf, "%s\n", rbd_dev->image_name); + return sprintf(buf, "%s\n", rbd_dev->spec->image_name); } static ssize_t rbd_image_id_show(struct device *dev, @@ -1981,7 +1996,7 @@ static ssize_t rbd_image_id_show(struct device *dev, { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); - return sprintf(buf, "%s\n", rbd_dev->image_id); + return sprintf(buf, "%s\n", rbd_dev->spec->image_id); } /* @@ -1994,7 +2009,7 @@ static ssize_t rbd_snap_show(struct device *dev, { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); - return sprintf(buf, "%s\n", rbd_dev->snap_name); + return sprintf(buf, "%s\n", rbd_dev->spec->snap_name); } static ssize_t rbd_image_refresh(struct device *dev, @@ -2547,11 +2562,12 @@ static int rbd_dev_snaps_update(struct rbd_device *rbd_dev) /* Existing snapshot not in the new snap context */ - if (rbd_dev->snap_id == snap->id) + if (rbd_dev->spec->snap_id == snap->id) rbd_dev->exists = false; rbd_remove_snap_dev(snap); dout("%ssnap id %llu has been removed\n", - rbd_dev->snap_id == snap->id ? "mapped " : "", + rbd_dev->spec->snap_id == snap->id ? + "mapped " : "", (unsigned long long) snap->id); /* Done with this list entry; advance */ @@ -2869,16 +2885,17 @@ static int rbd_add_parse_args(struct rbd_device *rbd_dev, if (!*options) goto out_err; /* Missing options */ - rbd_dev->pool_name = dup_token(&buf, NULL); - if (!rbd_dev->pool_name) + rbd_dev->spec->pool_name = dup_token(&buf, NULL); + if (!rbd_dev->spec->pool_name) goto out_mem; - if (!*rbd_dev->pool_name) + if (!*rbd_dev->spec->pool_name) goto out_err; /* Missing pool name */ - rbd_dev->image_name = dup_token(&buf, &rbd_dev->image_name_len); - if (!rbd_dev->image_name) + rbd_dev->spec->image_name = + dup_token(&buf, &rbd_dev->spec->image_name_len); + if (!rbd_dev->spec->image_name) goto out_mem; - if (!*rbd_dev->image_name) + if (!*rbd_dev->spec->image_name) goto out_err; /* Missing image name */ /* @@ -2893,11 +2910,11 @@ static int rbd_add_parse_args(struct rbd_device *rbd_dev, ret = -ENAMETOOLONG; goto out_err; } - rbd_dev->snap_name = kmalloc(len + 1, GFP_KERNEL); - if (!rbd_dev->snap_name) + rbd_dev->spec->snap_name = kmalloc(len + 1, GFP_KERNEL); + if (!rbd_dev->spec->snap_name) goto out_mem; - memcpy(rbd_dev->snap_name, buf, len); - *(rbd_dev->snap_name + len) = '\0'; + memcpy(rbd_dev->spec->snap_name, buf, len); + *(rbd_dev->spec->snap_name + len) = '\0'; /* Initialize all rbd options to the defaults */ @@ -2921,11 +2938,11 @@ static int rbd_add_parse_args(struct rbd_device *rbd_dev, out_mem: ret = -ENOMEM; out_err: - kfree(rbd_dev->image_name); - rbd_dev->image_name = NULL; - rbd_dev->image_name_len = 0; - kfree(rbd_dev->pool_name); - rbd_dev->pool_name = NULL; + kfree(rbd_dev->spec->image_name); + rbd_dev->spec->image_name = NULL; + rbd_dev->spec->image_name_len = 0; + kfree(rbd_dev->spec->pool_name); + rbd_dev->spec->pool_name = NULL; kfree(options); return ret; @@ -2957,11 +2974,11 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev) * First, see if the format 2 image id file exists, and if * so, get the image's persistent id from it. */ - size = sizeof (RBD_ID_PREFIX) + rbd_dev->image_name_len; + size = sizeof (RBD_ID_PREFIX) + rbd_dev->spec->image_name_len; object_name = kmalloc(size, GFP_NOIO); if (!object_name) return -ENOMEM; - sprintf(object_name, "%s%s", RBD_ID_PREFIX, rbd_dev->image_name); + sprintf(object_name, "%s%s", RBD_ID_PREFIX, rbd_dev->spec->image_name); dout("rbd id object name is %s\n", object_name); /* Response will be an encoded string, which includes a length */ @@ -2984,15 +3001,15 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev) ret = 0; /* rbd_req_sync_exec() can return positive */ p = response; - rbd_dev->image_id = ceph_extract_encoded_string(&p, + rbd_dev->spec->image_id = ceph_extract_encoded_string(&p, p + RBD_IMAGE_ID_LEN_MAX, - &rbd_dev->image_id_len, + &rbd_dev->spec->image_id_len, GFP_NOIO); - if (IS_ERR(rbd_dev->image_id)) { - ret = PTR_ERR(rbd_dev->image_id); - rbd_dev->image_id = NULL; + if (IS_ERR(rbd_dev->spec->image_id)) { + ret = PTR_ERR(rbd_dev->spec->image_id); + rbd_dev->spec->image_id = NULL; } else { - dout("image_id is %s\n", rbd_dev->image_id); + dout("image_id is %s\n", rbd_dev->spec->image_id); } out: kfree(response); @@ -3008,20 +3025,21 @@ static int rbd_dev_v1_probe(struct rbd_device *rbd_dev) /* Version 1 images have no id; empty string is used */ - rbd_dev->image_id = kstrdup("", GFP_KERNEL); - if (!rbd_dev->image_id) + rbd_dev->spec->image_id = kstrdup("", GFP_KERNEL); + if (!rbd_dev->spec->image_id) return -ENOMEM; - rbd_dev->image_id_len = 0; + rbd_dev->spec->image_id_len = 0; /* Record the header object name for this rbd image. */ - size = rbd_dev->image_name_len + sizeof (RBD_SUFFIX); + size = rbd_dev->spec->image_name_len + sizeof (RBD_SUFFIX); rbd_dev->header_name = kmalloc(size, GFP_KERNEL); if (!rbd_dev->header_name) { ret = -ENOMEM; goto out_err; } - sprintf(rbd_dev->header_name, "%s%s", rbd_dev->image_name, RBD_SUFFIX); + sprintf(rbd_dev->header_name, "%s%s", + rbd_dev->spec->image_name, RBD_SUFFIX); /* Populate rbd image metadata */ @@ -3038,8 +3056,8 @@ static int rbd_dev_v1_probe(struct rbd_device *rbd_dev) out_err: kfree(rbd_dev->header_name); rbd_dev->header_name = NULL; - kfree(rbd_dev->image_id); - rbd_dev->image_id = NULL; + kfree(rbd_dev->spec->image_id); + rbd_dev->spec->image_id = NULL; return ret; } @@ -3054,12 +3072,12 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev) * Image id was filled in by the caller. Record the header * object name for this rbd image. */ - size = sizeof (RBD_HEADER_PREFIX) + rbd_dev->image_id_len; + size = sizeof (RBD_HEADER_PREFIX) + rbd_dev->spec->image_id_len; rbd_dev->header_name = kmalloc(size, GFP_KERNEL); if (!rbd_dev->header_name) return -ENOMEM; sprintf(rbd_dev->header_name, "%s%s", - RBD_HEADER_PREFIX, rbd_dev->image_id); + RBD_HEADER_PREFIX, rbd_dev->spec->image_id); /* Get the size and object order for the image */ @@ -3147,6 +3165,9 @@ static ssize_t rbd_add(struct bus_type *bus, rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL); if (!rbd_dev) return -ENOMEM; + rbd_dev->spec = kzalloc(sizeof (*rbd_dev->spec), GFP_KERNEL); + if (!rbd_dev->spec) + goto err_out_mem; /* static rbd_device initialization */ spin_lock_init(&rbd_dev->lock); @@ -3167,10 +3188,10 @@ static ssize_t rbd_add(struct bus_type *bus, /* pick the pool */ osdc = &rbd_dev->rbd_client->client->osdc; - rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->pool_name); + rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->spec->pool_name); if (rc < 0) goto err_out_client; - rbd_dev->pool_id = (u64) rc; + rbd_dev->spec->pool_id = (u64) rc; rc = rbd_dev_probe(rbd_dev); if (rc < 0) @@ -3257,15 +3278,16 @@ err_out_probe: err_out_client: kfree(rbd_dev->header_name); rbd_put_client(rbd_dev); - kfree(rbd_dev->image_id); + kfree(rbd_dev->spec->image_id); err_out_args: if (ceph_opts) ceph_destroy_options(ceph_opts); - kfree(rbd_dev->snap_name); - kfree(rbd_dev->image_name); - kfree(rbd_dev->pool_name); + kfree(rbd_dev->spec->snap_name); + kfree(rbd_dev->spec->image_name); + kfree(rbd_dev->spec->pool_name); kfree(rbd_opts); err_out_mem: + kfree(rbd_dev->spec); kfree(rbd_dev); dout("Error adding device %s\n", buf); @@ -3314,11 +3336,11 @@ static void rbd_dev_release(struct device *dev) rbd_header_free(&rbd_dev->header); /* done with the id, and with the rbd_dev */ - kfree(rbd_dev->snap_name); - kfree(rbd_dev->image_id); + kfree(rbd_dev->spec->snap_name); + kfree(rbd_dev->spec->image_id); kfree(rbd_dev->header_name); - kfree(rbd_dev->pool_name); - kfree(rbd_dev->image_name); + kfree(rbd_dev->spec->pool_name); + kfree(rbd_dev->spec->image_name); rbd_dev_id_put(rbd_dev); kfree(rbd_dev); -- cgit v0.10.2 From 999d8795d438d396936811b185428d70b7b7de6d Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 19 Oct 2012 09:33:10 -0300 Subject: mm/slob: Drop usage of page->private for storing page-sized allocations This field was being used to store size allocation so it could be retrieved by ksize(). However, it is a bad practice to not mark a page as a slab page and then use fields for special purposes. There is no need to store the allocated size and ksize() can simply return PAGE_SIZE << compound_order(page). Cc: Pekka Enberg Cc: Matt Mackall Acked-by: Christoph Lameter Signed-off-by: Ezequiel Garcia Signed-off-by: Pekka Enberg diff --git a/mm/slob.c b/mm/slob.c index a08e468..06a5ec7 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -28,9 +28,8 @@ * from kmalloc are prepended with a 4-byte header with the kmalloc size. * If kmalloc is asked for objects of PAGE_SIZE or larger, it calls * alloc_pages() directly, allocating compound pages so the page order - * does not have to be separately tracked, and also stores the exact - * allocation size in page->private so that it can be used to accurately - * provide ksize(). These objects are detected in kfree() because slob_page() + * does not have to be separately tracked. + * These objects are detected in kfree() because PageSlab() * is false for them. * * SLAB is emulated on top of SLOB by simply calling constructors and @@ -455,11 +454,6 @@ __do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller) if (likely(order)) gfp |= __GFP_COMP; ret = slob_new_pages(gfp, order, node); - if (ret) { - struct page *page; - page = virt_to_page(ret); - page->private = size; - } trace_kmalloc_node(caller, ret, size, PAGE_SIZE << order, gfp, node); @@ -514,18 +508,20 @@ EXPORT_SYMBOL(kfree); size_t ksize(const void *block) { struct page *sp; + int align; + unsigned int *m; BUG_ON(!block); if (unlikely(block == ZERO_SIZE_PTR)) return 0; sp = virt_to_page(block); - if (PageSlab(sp)) { - int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); - unsigned int *m = (unsigned int *)(block - align); - return SLOB_UNITS(*m) * SLOB_UNIT; - } else - return sp->private; + if (unlikely(!PageSlab(sp))) + return PAGE_SIZE << compound_order(sp); + + align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); + m = (unsigned int *)(block - align); + return SLOB_UNITS(*m) * SLOB_UNIT; } EXPORT_SYMBOL(ksize); -- cgit v0.10.2 From fe74fe2bf293d061826f0d7afc2ca8456bdbb40e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 19 Oct 2012 09:33:11 -0300 Subject: mm/slob: Use object_size field in kmem_cache_size() Fields object_size and size are not the same: the latter might include slab metadata. Return object_size field in kmem_cache_size(). Also, improve trace accuracy by correctly tracing reported size. Cc: Pekka Enberg Cc: Matt Mackall Acked-by: Christoph Lameter Acked-by: David Rientjes Signed-off-by: Ezequiel Garcia Signed-off-by: Pekka Enberg diff --git a/mm/slob.c b/mm/slob.c index 06a5ec7..287a88a 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -554,12 +554,12 @@ void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node) if (c->size < PAGE_SIZE) { b = slob_alloc(c->size, flags, c->align, node); - trace_kmem_cache_alloc_node(_RET_IP_, b, c->size, + trace_kmem_cache_alloc_node(_RET_IP_, b, c->object_size, SLOB_UNITS(c->size) * SLOB_UNIT, flags, node); } else { b = slob_new_pages(flags, get_order(c->size), node); - trace_kmem_cache_alloc_node(_RET_IP_, b, c->size, + trace_kmem_cache_alloc_node(_RET_IP_, b, c->object_size, PAGE_SIZE << get_order(c->size), flags, node); } @@ -606,7 +606,7 @@ EXPORT_SYMBOL(kmem_cache_free); unsigned int kmem_cache_size(struct kmem_cache *c) { - return c->size; + return c->object_size; } EXPORT_SYMBOL(kmem_cache_size); -- cgit v0.10.2 From 242860a47a75b933a79a30f6a40bf4858f4a3ecc Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 19 Oct 2012 09:33:12 -0300 Subject: mm/sl[aou]b: Move common kmem_cache_size() to slab.h This function is identically defined in all three allocators and it's trivial to move it to slab.h Since now it's static, inline, header-defined function this patch also drops the EXPORT_SYMBOL tag. Cc: Pekka Enberg Cc: Matt Mackall Acked-by: Christoph Lameter Signed-off-by: Ezequiel Garcia Signed-off-by: Pekka Enberg diff --git a/include/linux/slab.h b/include/linux/slab.h index 83d1a14..743a104 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -128,7 +128,6 @@ struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, void kmem_cache_destroy(struct kmem_cache *); int kmem_cache_shrink(struct kmem_cache *); void kmem_cache_free(struct kmem_cache *, void *); -unsigned int kmem_cache_size(struct kmem_cache *); /* * Please use this macro to create slab caches. Simply specify the @@ -388,6 +387,14 @@ static inline void *kzalloc_node(size_t size, gfp_t flags, int node) return kmalloc_node(size, flags | __GFP_ZERO, node); } +/* + * Determine the size of a slab object + */ +static inline unsigned int kmem_cache_size(struct kmem_cache *s) +{ + return s->object_size; +} + void __init kmem_cache_init_late(void); #endif /* _LINUX_SLAB_H */ diff --git a/mm/slab.c b/mm/slab.c index 6d5c83c..1f7fd5f 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3969,12 +3969,6 @@ void kfree(const void *objp) } EXPORT_SYMBOL(kfree); -unsigned int kmem_cache_size(struct kmem_cache *cachep) -{ - return cachep->object_size; -} -EXPORT_SYMBOL(kmem_cache_size); - /* * This initializes kmem_list3 or resizes various caches for all nodes. */ diff --git a/mm/slob.c b/mm/slob.c index 287a88a..fffbc82 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -604,12 +604,6 @@ void kmem_cache_free(struct kmem_cache *c, void *b) } EXPORT_SYMBOL(kmem_cache_free); -unsigned int kmem_cache_size(struct kmem_cache *c) -{ - return c->object_size; -} -EXPORT_SYMBOL(kmem_cache_size); - int __kmem_cache_shutdown(struct kmem_cache *c) { /* No way to check for remaining objects */ diff --git a/mm/slub.c b/mm/slub.c index 35483e0..deee7c7 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -3121,15 +3121,6 @@ error: return -EINVAL; } -/* - * Determine the size of a slab object - */ -unsigned int kmem_cache_size(struct kmem_cache *s) -{ - return s->object_size; -} -EXPORT_SYMBOL(kmem_cache_size); - static void list_slab_objects(struct kmem_cache *s, struct page *page, const char *text) { -- cgit v0.10.2 From 8cf9864b1382851d90c7c505f8441c8928f1469e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 22 Oct 2012 09:04:31 -0300 Subject: mm/slob: Use free_page instead of put_page for page-size kmalloc allocations When freeing objects, the slob allocator currently free empty pages calling __free_pages(). However, page-size kmallocs are disposed using put_page() instead. It makes no sense to call put_page() for kernel pages that are provided by the object allocator, so we shouldn't be doing this ourselves. This is based on: commit d9b7f22623b5fa9cc189581dcdfb2ac605933bf4 Author: Glauber Costa slub: use free_page instead of put_page for freeing kmalloc allocation Cc: Christoph Lameter Cc: Pekka Enberg Cc: Matt Mackall Acked-by: Glauber Costa Signed-off-by: Ezequiel Garcia Signed-off-by: Pekka Enberg diff --git a/mm/slob.c b/mm/slob.c index fffbc82..e7d7901 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -500,7 +500,7 @@ void kfree(const void *block) unsigned int *m = (unsigned int *)(block - align); slob_free(m, *m + align); } else - put_page(sp); + __free_pages(sp, compound_order(sp)); } EXPORT_SYMBOL(kfree); -- cgit v0.10.2 From d8843922fba49e887874aa1f9e748d620c5092af Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 17 Oct 2012 15:36:51 +0400 Subject: slab: Ignore internal flags in cache creation Some flags are used internally by the allocators for management purposes. One example of that is the CFLGS_OFF_SLAB flag that slab uses to mark that the metadata for that cache is stored outside of the slab. No cache should ever pass those as a creation flags. We can just ignore this bit if it happens to be passed (such as when duplicating a cache in the kmem memcg patches). Because such flags can vary from allocator to allocator, we allow them to make their own decisions on that, defining SLAB_AVAILABLE_FLAGS with all flags that are valid at creation time. Allocators that doesn't have any specific flag requirement should define that to mean all flags. Common code will mask out all flags not belonging to that set. Acked-by: Christoph Lameter Acked-by: David Rientjes Signed-off-by: Glauber Costa Signed-off-by: Pekka Enberg diff --git a/mm/slab.c b/mm/slab.c index 1f7fd5f..6ebb951 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -162,23 +162,6 @@ */ static bool pfmemalloc_active __read_mostly; -/* Legal flag mask for kmem_cache_create(). */ -#if DEBUG -# define CREATE_MASK (SLAB_RED_ZONE | \ - SLAB_POISON | SLAB_HWCACHE_ALIGN | \ - SLAB_CACHE_DMA | \ - SLAB_STORE_USER | \ - SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \ - SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \ - SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE | SLAB_NOTRACK) -#else -# define CREATE_MASK (SLAB_HWCACHE_ALIGN | \ - SLAB_CACHE_DMA | \ - SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \ - SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \ - SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE | SLAB_NOTRACK) -#endif - /* * kmem_bufctl_t: * @@ -2378,11 +2361,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) if (flags & SLAB_DESTROY_BY_RCU) BUG_ON(flags & SLAB_POISON); #endif - /* - * Always checks flags, a caller might be expecting debug support which - * isn't available. - */ - BUG_ON(flags & ~CREATE_MASK); /* * Check that size is in terms of words. This is needed to avoid diff --git a/mm/slab.h b/mm/slab.h index 5a43c2f..66a62d3 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -45,6 +45,31 @@ static inline struct kmem_cache *__kmem_cache_alias(const char *name, size_t siz #endif +/* Legal flag mask for kmem_cache_create(), for various configurations */ +#define SLAB_CORE_FLAGS (SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA | SLAB_PANIC | \ + SLAB_DESTROY_BY_RCU | SLAB_DEBUG_OBJECTS ) + +#if defined(CONFIG_DEBUG_SLAB) +#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER) +#elif defined(CONFIG_SLUB_DEBUG) +#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \ + SLAB_TRACE | SLAB_DEBUG_FREE) +#else +#define SLAB_DEBUG_FLAGS (0) +#endif + +#if defined(CONFIG_SLAB) +#define SLAB_CACHE_FLAGS (SLAB_MEM_SPREAD | SLAB_NOLEAKTRACE | \ + SLAB_RECLAIM_ACCOUNT | SLAB_TEMPORARY | SLAB_NOTRACK) +#elif defined(CONFIG_SLUB) +#define SLAB_CACHE_FLAGS (SLAB_NOLEAKTRACE | SLAB_RECLAIM_ACCOUNT | \ + SLAB_TEMPORARY | SLAB_NOTRACK) +#else +#define SLAB_CACHE_FLAGS (0) +#endif + +#define CACHE_CREATE_MASK (SLAB_CORE_FLAGS | SLAB_DEBUG_FLAGS | SLAB_CACHE_FLAGS) + int __kmem_cache_shutdown(struct kmem_cache *); struct seq_file; diff --git a/mm/slab_common.c b/mm/slab_common.c index 5fb753d..b705be7 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -109,6 +109,13 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align if (!kmem_cache_sanity_check(name, size) == 0) goto out_locked; + /* + * Some allocators will constraint the set of valid flags to a subset + * of all flags. We expect them to define CACHE_CREATE_MASK in this + * case, and we'll just provide them with a sanitized version of the + * passed flags. + */ + flags &= CACHE_CREATE_MASK; s = __kmem_cache_alias(name, size, align, flags, ctor); if (s) diff --git a/mm/slub.c b/mm/slub.c index deee7c7..b2ada3d 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -112,9 +112,6 @@ * the fast path and disables lockless freelists. */ -#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \ - SLAB_TRACE | SLAB_DEBUG_FREE) - static inline int kmem_cache_debug(struct kmem_cache *s) { #ifdef CONFIG_SLUB_DEBUG -- cgit v0.10.2 From 789306e5ad6b3051c263ac2478875efa8bc07462 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 5 Oct 2012 16:55:20 +0200 Subject: mm/slob: use min_t() to compare ARCH_SLAB_MINALIGN The definition of ARCH_SLAB_MINALIGN is architecture dependent and can be either of type size_t or int. Comparing that value with ARCH_KMALLOC_MINALIGN can cause harmless warnings on platforms where they are different. Since both are always small positive integer numbers, using the size_t type to compare them is safe and gets rid of the warning. Without this patch, building ARM collie_defconfig results in: mm/slob.c: In function '__kmalloc_node': mm/slob.c:431:152: warning: comparison of distinct pointer types lacks a cast [enabled by default] mm/slob.c: In function 'kfree': mm/slob.c:484:153: warning: comparison of distinct pointer types lacks a cast [enabled by default] mm/slob.c: In function 'ksize': mm/slob.c:503:153: warning: comparison of distinct pointer types lacks a cast [enabled by default] Acked-by: Christoph Lameter Signed-off-by: Arnd Bergmann [ penberg@kernel.org: updates for master ] Signed-off-by: Pekka Enberg diff --git a/mm/slob.c b/mm/slob.c index e7d7901..87e16c4 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -428,7 +428,7 @@ static __always_inline void * __do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller) { unsigned int *m; - int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); + int align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); void *ret; gfp &= gfp_allowed_mask; @@ -496,7 +496,7 @@ void kfree(const void *block) sp = virt_to_page(block); if (PageSlab(sp)) { - int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); + int align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); unsigned int *m = (unsigned int *)(block - align); slob_free(m, *m + align); } else @@ -519,7 +519,7 @@ size_t ksize(const void *block) if (unlikely(!PageSlab(sp))) return PAGE_SIZE << compound_order(sp); - align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); + align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); m = (unsigned int *)(block - align); return SLOB_UNITS(*m) * SLOB_UNIT; } -- cgit v0.10.2 From 8b8fb99c5c93a0bdfe7b0c0c9fd2d41a3244555e Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 26 Oct 2012 17:25:24 -0500 Subject: rbd: add reference counting to rbd_spec With layered images we'll share rbd_spec structures, so add a reference count to it. It neatens up some code also. A silly get/put pair is added to the alloc routine just to avoid "defined but not used" warnings. It will go away soon. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 2049810..86206a7 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2134,6 +2134,45 @@ static struct device_type rbd_snap_device_type = { .release = rbd_snap_dev_release, }; +static struct rbd_spec *rbd_spec_get(struct rbd_spec *spec) +{ + kref_get(&spec->kref); + + return spec; +} + +static void rbd_spec_free(struct kref *kref); +static void rbd_spec_put(struct rbd_spec *spec) +{ + if (spec) + kref_put(&spec->kref, rbd_spec_free); +} + +static struct rbd_spec *rbd_spec_alloc(void) +{ + struct rbd_spec *spec; + + spec = kzalloc(sizeof (*spec), GFP_KERNEL); + if (!spec) + return NULL; + kref_init(&spec->kref); + + rbd_spec_put(rbd_spec_get(spec)); /* TEMPORARY */ + + return spec; +} + +static void rbd_spec_free(struct kref *kref) +{ + struct rbd_spec *spec = container_of(kref, struct rbd_spec, kref); + + kfree(spec->pool_name); + kfree(spec->image_id); + kfree(spec->image_name); + kfree(spec->snap_name); + kfree(spec); +} + static bool rbd_snap_registered(struct rbd_snap *snap) { bool ret = snap->dev.type == &rbd_snap_device_type; @@ -3165,7 +3204,7 @@ static ssize_t rbd_add(struct bus_type *bus, rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL); if (!rbd_dev) return -ENOMEM; - rbd_dev->spec = kzalloc(sizeof (*rbd_dev->spec), GFP_KERNEL); + rbd_dev->spec = rbd_spec_alloc(); if (!rbd_dev->spec) goto err_out_mem; @@ -3278,16 +3317,12 @@ err_out_probe: err_out_client: kfree(rbd_dev->header_name); rbd_put_client(rbd_dev); - kfree(rbd_dev->spec->image_id); err_out_args: if (ceph_opts) ceph_destroy_options(ceph_opts); - kfree(rbd_dev->spec->snap_name); - kfree(rbd_dev->spec->image_name); - kfree(rbd_dev->spec->pool_name); kfree(rbd_opts); err_out_mem: - kfree(rbd_dev->spec); + rbd_spec_put(rbd_dev->spec); kfree(rbd_dev); dout("Error adding device %s\n", buf); @@ -3336,12 +3371,9 @@ static void rbd_dev_release(struct device *dev) rbd_header_free(&rbd_dev->header); /* done with the id, and with the rbd_dev */ - kfree(rbd_dev->spec->snap_name); - kfree(rbd_dev->spec->image_id); kfree(rbd_dev->header_name); - kfree(rbd_dev->spec->pool_name); - kfree(rbd_dev->spec->image_name); rbd_dev_id_put(rbd_dev); + rbd_spec_put(rbd_dev->spec); kfree(rbd_dev); /* release module ref */ -- cgit v0.10.2 From 859c31df9cee9d1e1308b3b024b61355e6a629a5 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:42 -0500 Subject: rbd: fill rbd_spec in rbd_add_parse_args() Pass the address of an rbd_spec structure to rbd_add_parse_args(). Use it to hold the information defining the rbd image to be mapped in an rbd_add() call. Use the result in the caller to initialize the rbd_dev->id field. This means rbd_dev is no longer needed in rbd_add_parse_args(), so get rid of it. Now that this transformation of rbd_add_parse_args() is complete, correct and expand on the its header documentation to reflect the new reality. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 86206a7..be85d92 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2887,25 +2887,58 @@ static inline char *dup_token(const char **buf, size_t *lenp) } /* - * This fills in the pool_name, image_name, image_name_len, rbd_dev, - * rbd_md_name, and name fields of the given rbd_dev, based on the - * list of monitor addresses and other options provided via - * /sys/bus/rbd/add. Returns a pointer to a dynamically-allocated - * copy of the snapshot name to map if successful, or a - * pointer-coded error otherwise. + * Parse the options provided for an "rbd add" (i.e., rbd image + * mapping) request. These arrive via a write to /sys/bus/rbd/add, + * and the data written is passed here via a NUL-terminated buffer. + * Returns 0 if successful or an error code otherwise. * - * Note: rbd_dev is assumed to have been initially zero-filled. + * The information extracted from these options is recorded in + * the other parameters which return dynamically-allocated + * structures: + * ceph_opts + * The address of a pointer that will refer to a ceph options + * structure. Caller must release the returned pointer using + * ceph_destroy_options() when it is no longer needed. + * rbd_opts + * Address of an rbd options pointer. Fully initialized by + * this function; caller must release with kfree(). + * spec + * Address of an rbd image specification pointer. Fully + * initialized by this function based on parsed options. + * Caller must release with rbd_spec_put(). + * + * The options passed take this form: + * [] + * where: + * + * A comma-separated list of one or more monitor addresses. + * A monitor address is an ip address, optionally followed + * by a port number (separated by a colon). + * I.e.: ip1[:port1][,ip2[:port2]...] + * + * A comma-separated list of ceph and/or rbd options. + * + * The name of the rados pool containing the rbd image. + * + * The name of the image in that pool to map. + * + * An optional snapshot id. If provided, the mapping will + * present data from the image at the time that snapshot was + * created. The image head is used if no snapshot id is + * provided. Snapshot mappings are always read-only. */ -static int rbd_add_parse_args(struct rbd_device *rbd_dev, - const char *buf, +static int rbd_add_parse_args(const char *buf, struct ceph_options **ceph_opts, - struct rbd_options **opts) + struct rbd_options **opts, + struct rbd_spec **rbd_spec) { size_t len; + char *options; const char *mon_addrs; size_t mon_addrs_size; - char *options; + struct rbd_spec *spec = NULL; struct rbd_options *rbd_opts = NULL; + struct ceph_options *copts; int ret; /* The first four tokens are required */ @@ -2924,17 +2957,20 @@ static int rbd_add_parse_args(struct rbd_device *rbd_dev, if (!*options) goto out_err; /* Missing options */ - rbd_dev->spec->pool_name = dup_token(&buf, NULL); - if (!rbd_dev->spec->pool_name) + spec = rbd_spec_alloc(); + if (!spec) goto out_mem; - if (!*rbd_dev->spec->pool_name) + + spec->pool_name = dup_token(&buf, NULL); + if (!spec->pool_name) + goto out_mem; + if (!*spec->pool_name) goto out_err; /* Missing pool name */ - rbd_dev->spec->image_name = - dup_token(&buf, &rbd_dev->spec->image_name_len); - if (!rbd_dev->spec->image_name) + spec->image_name = dup_token(&buf, &spec->image_name_len); + if (!spec->image_name) goto out_mem; - if (!*rbd_dev->spec->image_name) + if (!*spec->image_name) goto out_err; /* Missing image name */ /* @@ -2949,11 +2985,11 @@ static int rbd_add_parse_args(struct rbd_device *rbd_dev, ret = -ENAMETOOLONG; goto out_err; } - rbd_dev->spec->snap_name = kmalloc(len + 1, GFP_KERNEL); - if (!rbd_dev->spec->snap_name) + spec->snap_name = kmalloc(len + 1, GFP_KERNEL); + if (!spec->snap_name) goto out_mem; - memcpy(rbd_dev->spec->snap_name, buf, len); - *(rbd_dev->spec->snap_name + len) = '\0'; + memcpy(spec->snap_name, buf, len); + *(spec->snap_name + len) = '\0'; /* Initialize all rbd options to the defaults */ @@ -2963,25 +2999,25 @@ static int rbd_add_parse_args(struct rbd_device *rbd_dev, rbd_opts->read_only = RBD_READ_ONLY_DEFAULT; - *ceph_opts = ceph_parse_options(options, mon_addrs, + copts = ceph_parse_options(options, mon_addrs, mon_addrs + mon_addrs_size - 1, parse_rbd_opts_token, rbd_opts); - kfree(options); - if (IS_ERR(*ceph_opts)) { - ret = PTR_ERR(*ceph_opts); + if (IS_ERR(copts)) { + ret = PTR_ERR(copts); goto out_err; } + kfree(options); + + *ceph_opts = copts; *opts = rbd_opts; + *rbd_spec = spec; return 0; out_mem: ret = -ENOMEM; out_err: - kfree(rbd_dev->spec->image_name); - rbd_dev->spec->image_name = NULL; - rbd_dev->spec->image_name_len = 0; - kfree(rbd_dev->spec->pool_name); - rbd_dev->spec->pool_name = NULL; + kfree(rbd_opts); + rbd_spec_put(spec); kfree(options); return ret; @@ -3195,6 +3231,7 @@ static ssize_t rbd_add(struct bus_type *bus, struct rbd_device *rbd_dev = NULL; struct ceph_options *ceph_opts = NULL; struct rbd_options *rbd_opts = NULL; + struct rbd_spec *spec = NULL; struct ceph_osd_client *osdc; int rc = -ENOMEM; @@ -3204,9 +3241,6 @@ static ssize_t rbd_add(struct bus_type *bus, rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL); if (!rbd_dev) return -ENOMEM; - rbd_dev->spec = rbd_spec_alloc(); - if (!rbd_dev->spec) - goto err_out_mem; /* static rbd_device initialization */ spin_lock_init(&rbd_dev->lock); @@ -3215,9 +3249,10 @@ static ssize_t rbd_add(struct bus_type *bus, init_rwsem(&rbd_dev->header_rwsem); /* parse add command */ - rc = rbd_add_parse_args(rbd_dev, buf, &ceph_opts, &rbd_opts); + rc = rbd_add_parse_args(buf, &ceph_opts, &rbd_opts, &spec); if (rc < 0) goto err_out_mem; + rbd_dev->mapping.read_only = rbd_opts->read_only; rc = rbd_get_client(rbd_dev, ceph_opts); @@ -3227,10 +3262,12 @@ static ssize_t rbd_add(struct bus_type *bus, /* pick the pool */ osdc = &rbd_dev->rbd_client->client->osdc; - rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->spec->pool_name); + rc = ceph_pg_poolid_by_name(osdc->osdmap, spec->pool_name); if (rc < 0) goto err_out_client; - rbd_dev->spec->pool_id = (u64) rc; + spec->pool_id = (u64) rc; + + rbd_dev->spec = spec; rc = rbd_dev_probe(rbd_dev); if (rc < 0) @@ -3321,8 +3358,8 @@ err_out_args: if (ceph_opts) ceph_destroy_options(ceph_opts); kfree(rbd_opts); + rbd_spec_put(spec); err_out_mem: - rbd_spec_put(rbd_dev->spec); kfree(rbd_dev); dout("Error adding device %s\n", buf); -- cgit v0.10.2 From 9d3997fdf4c82adfb37a4886a21eaa513ee071b6 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:42 -0500 Subject: rbd: don't pass rbd_dev to rbd_get_client() The only reason rbd_dev is passed to rbd_get_client() is so its rbd_client field can get assigned. Instead, just return the rbd_client pointer as a result and have the caller do the assignment. Change rbd_put_client() so it takes an rbd_client structure, so follows the more typical symmetry with rbd_get_client(). Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index be85d92..a528d4c 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -467,23 +467,17 @@ static int parse_rbd_opts_token(char *c, void *private) * Get a ceph client with specific addr and configuration, if one does * not exist create it. */ -static int rbd_get_client(struct rbd_device *rbd_dev, - struct ceph_options *ceph_opts) +static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts) { struct rbd_client *rbdc; rbdc = rbd_client_find(ceph_opts); - if (rbdc) { - /* using an existing client */ + if (rbdc) /* using an existing client */ ceph_destroy_options(ceph_opts); - } else { + else rbdc = rbd_client_create(ceph_opts); - if (IS_ERR(rbdc)) - return PTR_ERR(rbdc); - } - rbd_dev->rbd_client = rbdc; - return 0; + return rbdc; } /* @@ -508,10 +502,9 @@ static void rbd_client_release(struct kref *kref) * Drop reference to ceph client node. If it's not referenced anymore, release * it. */ -static void rbd_put_client(struct rbd_device *rbd_dev) +static void rbd_put_client(struct rbd_client *rbdc) { - kref_put(&rbd_dev->rbd_client->kref, rbd_client_release); - rbd_dev->rbd_client = NULL; + kref_put(&rbdc->kref, rbd_client_release); } /* @@ -3232,6 +3225,7 @@ static ssize_t rbd_add(struct bus_type *bus, struct ceph_options *ceph_opts = NULL; struct rbd_options *rbd_opts = NULL; struct rbd_spec *spec = NULL; + struct rbd_client *rbdc; struct ceph_osd_client *osdc; int rc = -ENOMEM; @@ -3255,13 +3249,16 @@ static ssize_t rbd_add(struct bus_type *bus, rbd_dev->mapping.read_only = rbd_opts->read_only; - rc = rbd_get_client(rbd_dev, ceph_opts); - if (rc < 0) + rbdc = rbd_get_client(ceph_opts); + if (IS_ERR(rbdc)) { + rc = PTR_ERR(rbdc); goto err_out_args; + } + rbd_dev->rbd_client = rbdc; ceph_opts = NULL; /* ceph_opts now owned by rbd_dev client */ /* pick the pool */ - osdc = &rbd_dev->rbd_client->client->osdc; + osdc = &rbdc->client->osdc; rc = ceph_pg_poolid_by_name(osdc->osdmap, spec->pool_name); if (rc < 0) goto err_out_client; @@ -3353,7 +3350,7 @@ err_out_probe: rbd_header_free(&rbd_dev->header); err_out_client: kfree(rbd_dev->header_name); - rbd_put_client(rbd_dev); + rbd_put_client(rbdc); err_out_args: if (ceph_opts) ceph_destroy_options(ceph_opts); @@ -3398,7 +3395,7 @@ static void rbd_dev_release(struct device *dev) if (rbd_dev->watch_event) rbd_req_sync_unwatch(rbd_dev); - rbd_put_client(rbd_dev); + rbd_put_client(rbd_dev->rbd_client); /* clean up and free blkdev */ rbd_free_disk(rbd_dev); -- cgit v0.10.2 From bd4ba6554dcbae652b8b27a44f5a7795c9f3178a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:42 -0500 Subject: rbd: consolidate rbd_dev init in rbd_add() Group the allocation and initialization of fields of the rbd device structure created in rbd_add(). Move the grouped code down later in the function, just prior to the call to rbd_dev_probe(). This is for the most part simple code movement. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index a528d4c..4771de2 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3232,29 +3232,16 @@ static ssize_t rbd_add(struct bus_type *bus, if (!try_module_get(THIS_MODULE)) return -ENODEV; - rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL); - if (!rbd_dev) - return -ENOMEM; - - /* static rbd_device initialization */ - spin_lock_init(&rbd_dev->lock); - INIT_LIST_HEAD(&rbd_dev->node); - INIT_LIST_HEAD(&rbd_dev->snaps); - init_rwsem(&rbd_dev->header_rwsem); - /* parse add command */ rc = rbd_add_parse_args(buf, &ceph_opts, &rbd_opts, &spec); if (rc < 0) - goto err_out_mem; - - rbd_dev->mapping.read_only = rbd_opts->read_only; + goto err_out_module; rbdc = rbd_get_client(ceph_opts); if (IS_ERR(rbdc)) { rc = PTR_ERR(rbdc); goto err_out_args; } - rbd_dev->rbd_client = rbdc; ceph_opts = NULL; /* ceph_opts now owned by rbd_dev client */ /* pick the pool */ @@ -3264,11 +3251,22 @@ static ssize_t rbd_add(struct bus_type *bus, goto err_out_client; spec->pool_id = (u64) rc; + rbd_dev = kzalloc(sizeof (*rbd_dev), GFP_KERNEL); + if (!rbd_dev) + goto err_out_client; + + spin_lock_init(&rbd_dev->lock); + INIT_LIST_HEAD(&rbd_dev->node); + INIT_LIST_HEAD(&rbd_dev->snaps); + init_rwsem(&rbd_dev->header_rwsem); + rbd_dev->rbd_client = rbdc; rbd_dev->spec = spec; + rbd_dev->mapping.read_only = rbd_opts->read_only; + rc = rbd_dev_probe(rbd_dev); if (rc < 0) - goto err_out_client; + goto err_out_mem; /* no need to lock here, as rbd_dev is not registered yet */ rc = rbd_dev_snaps_update(rbd_dev); @@ -3348,19 +3346,20 @@ err_out_snaps: rbd_remove_all_snaps(rbd_dev); err_out_probe: rbd_header_free(&rbd_dev->header); -err_out_client: kfree(rbd_dev->header_name); +err_out_mem: + kfree(rbd_dev); +err_out_client: rbd_put_client(rbdc); err_out_args: if (ceph_opts) ceph_destroy_options(ceph_opts); kfree(rbd_opts); rbd_spec_put(spec); -err_out_mem: - kfree(rbd_dev); +err_out_module: + module_put(THIS_MODULE); dout("Error adding device %s\n", buf); - module_put(THIS_MODULE); return (ssize_t) rc; } -- cgit v0.10.2 From c53d589337e9a211413484a604c76072e8474dc0 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:42 -0500 Subject: rbd: define rbd_dev_{create,destroy}() helpers Encapsulate the creation/initialization and destruction of rbd device structures. The rbd_client and the rbd_spec structures provided on creation hold references whose ownership is transferred to the new rbd_device structure. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 4771de2..a8ad8f8 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -504,7 +504,8 @@ static void rbd_client_release(struct kref *kref) */ static void rbd_put_client(struct rbd_client *rbdc) { - kref_put(&rbdc->kref, rbd_client_release); + if (rbdc) + kref_put(&rbdc->kref, rbd_client_release); } /* @@ -2166,6 +2167,34 @@ static void rbd_spec_free(struct kref *kref) kfree(spec); } +struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, + struct rbd_spec *spec) +{ + struct rbd_device *rbd_dev; + + rbd_dev = kzalloc(sizeof (*rbd_dev), GFP_KERNEL); + if (!rbd_dev) + return NULL; + + spin_lock_init(&rbd_dev->lock); + INIT_LIST_HEAD(&rbd_dev->node); + INIT_LIST_HEAD(&rbd_dev->snaps); + init_rwsem(&rbd_dev->header_rwsem); + + rbd_dev->spec = spec; + rbd_dev->rbd_client = rbdc; + + return rbd_dev; +} + +static void rbd_dev_destroy(struct rbd_device *rbd_dev) +{ + kfree(rbd_dev->header_name); + rbd_put_client(rbd_dev->rbd_client); + rbd_spec_put(rbd_dev->spec); + kfree(rbd_dev); +} + static bool rbd_snap_registered(struct rbd_snap *snap) { bool ret = snap->dev.type == &rbd_snap_device_type; @@ -3242,7 +3271,7 @@ static ssize_t rbd_add(struct bus_type *bus, rc = PTR_ERR(rbdc); goto err_out_args; } - ceph_opts = NULL; /* ceph_opts now owned by rbd_dev client */ + ceph_opts = NULL; /* rbd_dev client now owns this */ /* pick the pool */ osdc = &rbdc->client->osdc; @@ -3251,22 +3280,19 @@ static ssize_t rbd_add(struct bus_type *bus, goto err_out_client; spec->pool_id = (u64) rc; - rbd_dev = kzalloc(sizeof (*rbd_dev), GFP_KERNEL); + rbd_dev = rbd_dev_create(rbdc, spec); if (!rbd_dev) goto err_out_client; - - spin_lock_init(&rbd_dev->lock); - INIT_LIST_HEAD(&rbd_dev->node); - INIT_LIST_HEAD(&rbd_dev->snaps); - init_rwsem(&rbd_dev->header_rwsem); - rbd_dev->rbd_client = rbdc; - rbd_dev->spec = spec; + rbdc = NULL; /* rbd_dev now owns this */ + spec = NULL; /* rbd_dev now owns this */ rbd_dev->mapping.read_only = rbd_opts->read_only; + kfree(rbd_opts); + rbd_opts = NULL; /* done with this */ rc = rbd_dev_probe(rbd_dev); if (rc < 0) - goto err_out_mem; + goto err_out_rbd_dev; /* no need to lock here, as rbd_dev is not registered yet */ rc = rbd_dev_snaps_update(rbd_dev); @@ -3317,8 +3343,6 @@ static ssize_t rbd_add(struct bus_type *bus, if (rc) goto err_out_bus; - kfree(rbd_opts); - /* Everything's ready. Announce the disk to the world. */ add_disk(rbd_dev->disk); @@ -3332,7 +3356,6 @@ err_out_bus: /* this will also clean up rest of rbd_dev stuff */ rbd_bus_del_dev(rbd_dev); - kfree(rbd_opts); return rc; @@ -3346,9 +3369,8 @@ err_out_snaps: rbd_remove_all_snaps(rbd_dev); err_out_probe: rbd_header_free(&rbd_dev->header); - kfree(rbd_dev->header_name); -err_out_mem: - kfree(rbd_dev); +err_out_rbd_dev: + rbd_dev_destroy(rbd_dev); err_out_client: rbd_put_client(rbdc); err_out_args: @@ -3394,7 +3416,6 @@ static void rbd_dev_release(struct device *dev) if (rbd_dev->watch_event) rbd_req_sync_unwatch(rbd_dev); - rbd_put_client(rbd_dev->rbd_client); /* clean up and free blkdev */ rbd_free_disk(rbd_dev); @@ -3404,10 +3425,9 @@ static void rbd_dev_release(struct device *dev) rbd_header_free(&rbd_dev->header); /* done with the id, and with the rbd_dev */ - kfree(rbd_dev->header_name); rbd_dev_id_put(rbd_dev); - rbd_spec_put(rbd_dev->spec); - kfree(rbd_dev); + rbd_assert(rbd_dev->rbd_client != NULL); + rbd_dev_destroy(rbd_dev); /* release module ref */ module_put(THIS_MODULE); -- cgit v0.10.2 From 83a06263625b823afa3a842ddbf53473c22f24b2 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Oct 2012 15:47:17 -0500 Subject: rbd: encapsulate last part of probe Group the activities that now take place after an rbd_dev_probe() call into a single function, and move the call to that function into rbd_dev_probe() itself. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index a8ad8f8..8d26c0f 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3221,6 +3221,84 @@ out_err: return ret; } +static int rbd_dev_probe_finish(struct rbd_device *rbd_dev) +{ + int ret; + + /* no need to lock here, as rbd_dev is not registered yet */ + ret = rbd_dev_snaps_update(rbd_dev); + if (ret) + return ret; + + ret = rbd_dev_set_mapping(rbd_dev); + if (ret) + goto err_out_snaps; + + /* generate unique id: find highest unique id, add one */ + rbd_dev_id_get(rbd_dev); + + /* Fill in the device name, now that we have its id. */ + BUILD_BUG_ON(DEV_NAME_LEN + < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH); + sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id); + + /* Get our block major device number. */ + + ret = register_blkdev(0, rbd_dev->name); + if (ret < 0) + goto err_out_id; + rbd_dev->major = ret; + + /* Set up the blkdev mapping. */ + + ret = rbd_init_disk(rbd_dev); + if (ret) + goto err_out_blkdev; + + ret = rbd_bus_add_dev(rbd_dev); + if (ret) + goto err_out_disk; + + /* + * At this point cleanup in the event of an error is the job + * of the sysfs code (initiated by rbd_bus_del_dev()). + */ + down_write(&rbd_dev->header_rwsem); + ret = rbd_dev_snaps_register(rbd_dev); + up_write(&rbd_dev->header_rwsem); + if (ret) + goto err_out_bus; + + ret = rbd_init_watch_dev(rbd_dev); + if (ret) + goto err_out_bus; + + /* Everything's ready. Announce the disk to the world. */ + + add_disk(rbd_dev->disk); + + pr_info("%s: added with size 0x%llx\n", rbd_dev->disk->disk_name, + (unsigned long long) rbd_dev->mapping.size); + + return ret; +err_out_bus: + /* this will also clean up rest of rbd_dev stuff */ + + rbd_bus_del_dev(rbd_dev); + + return ret; +err_out_disk: + rbd_free_disk(rbd_dev); +err_out_blkdev: + unregister_blkdev(rbd_dev->major, rbd_dev->name); +err_out_id: + rbd_dev_id_put(rbd_dev); +err_out_snaps: + rbd_remove_all_snaps(rbd_dev); + + return ret; +} + /* * Probe for the existence of the header object for the given rbd * device. For format 2 images this includes determining the image @@ -3240,9 +3318,16 @@ static int rbd_dev_probe(struct rbd_device *rbd_dev) ret = rbd_dev_v1_probe(rbd_dev); else ret = rbd_dev_v2_probe(rbd_dev); - if (ret) + if (ret) { dout("probe failed, returning %d\n", ret); + return ret; + } + + ret = rbd_dev_probe_finish(rbd_dev); + if (ret) + rbd_header_free(&rbd_dev->header); + return ret; } @@ -3294,81 +3379,7 @@ static ssize_t rbd_add(struct bus_type *bus, if (rc < 0) goto err_out_rbd_dev; - /* no need to lock here, as rbd_dev is not registered yet */ - rc = rbd_dev_snaps_update(rbd_dev); - if (rc) - goto err_out_probe; - - rc = rbd_dev_set_mapping(rbd_dev); - if (rc) - goto err_out_snaps; - - /* generate unique id: find highest unique id, add one */ - rbd_dev_id_get(rbd_dev); - - /* Fill in the device name, now that we have its id. */ - BUILD_BUG_ON(DEV_NAME_LEN - < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH); - sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id); - - /* Get our block major device number. */ - - rc = register_blkdev(0, rbd_dev->name); - if (rc < 0) - goto err_out_id; - rbd_dev->major = rc; - - /* Set up the blkdev mapping. */ - - rc = rbd_init_disk(rbd_dev); - if (rc) - goto err_out_blkdev; - - rc = rbd_bus_add_dev(rbd_dev); - if (rc) - goto err_out_disk; - - /* - * At this point cleanup in the event of an error is the job - * of the sysfs code (initiated by rbd_bus_del_dev()). - */ - - down_write(&rbd_dev->header_rwsem); - rc = rbd_dev_snaps_register(rbd_dev); - up_write(&rbd_dev->header_rwsem); - if (rc) - goto err_out_bus; - - rc = rbd_init_watch_dev(rbd_dev); - if (rc) - goto err_out_bus; - - /* Everything's ready. Announce the disk to the world. */ - - add_disk(rbd_dev->disk); - - pr_info("%s: added with size 0x%llx\n", rbd_dev->disk->disk_name, - (unsigned long long) rbd_dev->mapping.size); - return count; - -err_out_bus: - /* this will also clean up rest of rbd_dev stuff */ - - rbd_bus_del_dev(rbd_dev); - - return rc; - -err_out_disk: - rbd_free_disk(rbd_dev); -err_out_blkdev: - unregister_blkdev(rbd_dev->major, rbd_dev->name); -err_out_id: - rbd_dev_id_put(rbd_dev); -err_out_snaps: - rbd_remove_all_snaps(rbd_dev); -err_out_probe: - rbd_header_free(&rbd_dev->header); err_out_rbd_dev: rbd_dev_destroy(rbd_dev); err_out_client: -- cgit v0.10.2 From 2c0d0a10ea89456781218f458f6bf72e99d87d2a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Oct 2012 19:40:33 -0500 Subject: rbd: allow null image name We will know the image id for format 2 parent images, but won't initially know its image name. Avoid making the query for an image id in rbd_dev_image_id() if it's already known. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 8d26c0f..a852133 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3068,6 +3068,14 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev) void *p; /* + * When probing a parent image, the image id is already + * known (and the image name likely is not). There's no + * need to fetch the image id again in this case. + */ + if (rbd_dev->spec->image_id) + return 0; + + /* * First, see if the format 2 image id file exists, and if * so, get the image's persistent id from it. */ -- cgit v0.10.2 From a92ffdf8a9b09f8fae9a8f418f87f30a5e459570 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Oct 2012 19:40:33 -0500 Subject: rbd: allow null image name Format 2 parent images are partially identified by their image id, but it may not be possible to determine their image name. The name is not strictly needed for correct operation, so we won't be treating it as an error if we don't know it. Handle this case gracefully in rbd_name_show(). Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index a852133..28052ff 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1982,7 +1982,10 @@ static ssize_t rbd_name_show(struct device *dev, { struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); - return sprintf(buf, "%s\n", rbd_dev->spec->image_name); + if (rbd_dev->spec->image_name) + return sprintf(buf, "%s\n", rbd_dev->spec->image_name); + + return sprintf(buf, "(unknown)\n"); } static ssize_t rbd_image_id_show(struct device *dev, -- cgit v0.10.2 From 86b00e0da6be7bbc16412f126c5b548ac5d91d50 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Thu, 25 Oct 2012 23:34:42 -0500 Subject: rbd: get parent spec for version 2 images Add support for getting the the information identifying the parent image for rbd images that have them. The child image holds a reference to its parent image specification structure. Create a new entry "parent" in /sys/bus/rbd/image/N/ to report the identifying information for the parent image, if any. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/Documentation/ABI/testing/sysfs-bus-rbd b/Documentation/ABI/testing/sysfs-bus-rbd index 1cf2adf..cd9213c 100644 --- a/Documentation/ABI/testing/sysfs-bus-rbd +++ b/Documentation/ABI/testing/sysfs-bus-rbd @@ -70,6 +70,10 @@ snap_* A directory per each snapshot +parent + + Information identifying the pool, image, and snapshot id for + the parent image in a layered rbd image (format 2 only). Entries under /sys/bus/rbd/devices//snap_ ------------------------------------------------------------- diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 28052ff..bce1fcf 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -217,6 +217,9 @@ struct rbd_device { struct ceph_osd_event *watch_event; struct ceph_osd_request *watch_request; + struct rbd_spec *parent_spec; + u64 parent_overlap; + /* protects updating the header */ struct rw_semaphore header_rwsem; @@ -2009,6 +2012,49 @@ static ssize_t rbd_snap_show(struct device *dev, return sprintf(buf, "%s\n", rbd_dev->spec->snap_name); } +/* + * For an rbd v2 image, shows the pool id, image id, and snapshot id + * for the parent image. If there is no parent, simply shows + * "(no parent image)". + */ +static ssize_t rbd_parent_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct rbd_device *rbd_dev = dev_to_rbd_dev(dev); + struct rbd_spec *spec = rbd_dev->parent_spec; + int count; + char *bufp = buf; + + if (!spec) + return sprintf(buf, "(no parent image)\n"); + + count = sprintf(bufp, "pool_id %llu\npool_name %s\n", + (unsigned long long) spec->pool_id, spec->pool_name); + if (count < 0) + return count; + bufp += count; + + count = sprintf(bufp, "image_id %s\nimage_name %s\n", spec->image_id, + spec->image_name ? spec->image_name : "(unknown)"); + if (count < 0) + return count; + bufp += count; + + count = sprintf(bufp, "snap_id %llu\nsnap_name %s\n", + (unsigned long long) spec->snap_id, spec->snap_name); + if (count < 0) + return count; + bufp += count; + + count = sprintf(bufp, "overlap %llu\n", rbd_dev->parent_overlap); + if (count < 0) + return count; + bufp += count; + + return (ssize_t) (bufp - buf); +} + static ssize_t rbd_image_refresh(struct device *dev, struct device_attribute *attr, const char *buf, @@ -2032,6 +2078,7 @@ static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL); static DEVICE_ATTR(image_id, S_IRUGO, rbd_image_id_show, NULL); static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh); static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL); +static DEVICE_ATTR(parent, S_IRUGO, rbd_parent_show, NULL); static struct attribute *rbd_attrs[] = { &dev_attr_size.attr, @@ -2043,6 +2090,7 @@ static struct attribute *rbd_attrs[] = { &dev_attr_name.attr, &dev_attr_image_id.attr, &dev_attr_current_snap.attr, + &dev_attr_parent.attr, &dev_attr_refresh.attr, NULL }; @@ -2192,6 +2240,7 @@ struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, static void rbd_dev_destroy(struct rbd_device *rbd_dev) { + rbd_spec_put(rbd_dev->parent_spec); kfree(rbd_dev->header_name); rbd_put_client(rbd_dev->rbd_client); rbd_spec_put(rbd_dev->spec); @@ -2400,6 +2449,71 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev) &rbd_dev->header.features); } +static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) +{ + struct rbd_spec *parent_spec; + size_t size; + void *reply_buf = NULL; + __le64 snapid; + void *p; + void *end; + char *image_id; + u64 overlap; + size_t len = 0; + int ret; + + parent_spec = rbd_spec_alloc(); + if (!parent_spec) + return -ENOMEM; + + size = sizeof (__le64) + /* pool_id */ + sizeof (__le32) + RBD_IMAGE_ID_LEN_MAX + /* image_id */ + sizeof (__le64) + /* snap_id */ + sizeof (__le64); /* overlap */ + reply_buf = kmalloc(size, GFP_KERNEL); + if (!reply_buf) { + ret = -ENOMEM; + goto out_err; + } + + snapid = cpu_to_le64(CEPH_NOSNAP); + ret = rbd_req_sync_exec(rbd_dev, rbd_dev->header_name, + "rbd", "get_parent", + (char *) &snapid, sizeof (snapid), + (char *) reply_buf, size, + CEPH_OSD_FLAG_READ, NULL); + dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret); + if (ret < 0) + goto out_err; + + ret = -ERANGE; + p = reply_buf; + end = (char *) reply_buf + size; + ceph_decode_64_safe(&p, end, parent_spec->pool_id, out_err); + if (parent_spec->pool_id == CEPH_NOPOOL) + goto out; /* No parent? No problem. */ + + image_id = ceph_extract_encoded_string(&p, end, &len, GFP_KERNEL); + if (IS_ERR(image_id)) { + ret = PTR_ERR(image_id); + goto out_err; + } + parent_spec->image_id = image_id; + ceph_decode_64_safe(&p, end, parent_spec->snap_id, out_err); + ceph_decode_64_safe(&p, end, overlap, out_err); + + rbd_dev->parent_overlap = overlap; + rbd_dev->parent_spec = parent_spec; + parent_spec = NULL; /* rbd_dev now owns this */ +out: + ret = 0; +out_err: + kfree(reply_buf); + rbd_spec_put(parent_spec); + + return ret; +} + static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev, u64 *ver) { size_t size; @@ -3154,6 +3268,12 @@ static int rbd_dev_v1_probe(struct rbd_device *rbd_dev) ret = rbd_read_header(rbd_dev, &rbd_dev->header); if (ret < 0) goto out_err; + + /* Version 1 images have no parent (no layering) */ + + rbd_dev->parent_spec = NULL; + rbd_dev->parent_overlap = 0; + rbd_dev->image_format = 1; dout("discovered version 1 image, header name is %s\n", @@ -3205,6 +3325,14 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev) if (ret < 0) goto out_err; + /* If the image supports layering, get the parent info */ + + if (rbd_dev->header.features & RBD_FEATURE_LAYERING) { + ret = rbd_dev_v2_parent_info(rbd_dev); + if (ret < 0) + goto out_err; + } + /* crypto and compression type aren't (yet) supported for v2 images */ rbd_dev->header.crypt_type = 0; @@ -3224,6 +3352,9 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev) return 0; out_err: + rbd_dev->parent_overlap = 0; + rbd_spec_put(rbd_dev->parent_spec); + rbd_dev->parent_spec = NULL; kfree(rbd_dev->header_name); rbd_dev->header_name = NULL; kfree(rbd_dev->header.object_prefix); diff --git a/include/linux/ceph/rados.h b/include/linux/ceph/rados.h index 0a99099..15077db 100644 --- a/include/linux/ceph/rados.h +++ b/include/linux/ceph/rados.h @@ -87,6 +87,8 @@ struct ceph_pg { * * lpgp_num -- as above. */ +#define CEPH_NOPOOL ((__u64) (-1)) /* pool id not defined */ + #define CEPH_PG_TYPE_REP 1 #define CEPH_PG_TYPE_RAID4 2 #define CEPH_PG_POOL_VERSION 2 -- cgit v0.10.2 From 72afc71ffca0f444ee0e1ef8c7e34ab209bb48b3 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Oct 2012 19:40:33 -0500 Subject: libceph: define ceph_pg_pool_name_by_id() Define and export function ceph_pg_pool_name_by_id() to supply the name of a pg pool whose id is given. This will be used by the next patch. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/include/linux/ceph/osdmap.h b/include/linux/ceph/osdmap.h index e88a620..5ea57ba 100644 --- a/include/linux/ceph/osdmap.h +++ b/include/linux/ceph/osdmap.h @@ -123,6 +123,7 @@ extern int ceph_calc_pg_acting(struct ceph_osdmap *osdmap, struct ceph_pg pgid, extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid); +extern const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id); extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name); #endif diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index f552aa4..de73214 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -469,6 +469,22 @@ static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, int id) return NULL; } +const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id) +{ + struct ceph_pg_pool_info *pi; + + if (id == CEPH_NOPOOL) + return NULL; + + if (WARN_ON_ONCE(id > (u64) INT_MAX)) + return NULL; + + pi = __lookup_pg_pool(&map->pg_pools, (int) id); + + return pi ? pi->name : NULL; +} +EXPORT_SYMBOL(ceph_pg_pool_name_by_id); + int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name) { struct rb_node *rbp; -- cgit v0.10.2 From 9e15b77d9af3b63dfbff14e695336dfca88c22b2 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 30 Oct 2012 19:40:33 -0500 Subject: rbd: get additional info in parent spec When a layered rbd image has a parent, that parent is identified only by its pool id, image id, and snapshot id. Images that have been mapped also record *names* for those three id's. Add code to look up these names for parent images so they match mapped images more closely. Skip doing this for an image if it already has its pool name defined (this will be the case for images mapped by the user). It is possible that an the name of a parent image can't be determined, even if the image id is valid. If this occurs it does not preclude correct operation, so don't treat this as an error. On the other hand, defined pools will always have both an id and a name. And any snapshot of an image identified as a parent for a clone image will exist, and will have a name (if not it indicates some other internal error). So treat failure to get these bits of information as errors. Signed-off-by: Alex Elder Reviewed-by: Josh Durgin diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index bce1fcf..842caf4 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -70,7 +70,10 @@ #define RBD_SNAP_HEAD_NAME "-" +/* This allows a single page to hold an image name sent by OSD */ +#define RBD_IMAGE_NAME_LEN_MAX (PAGE_SIZE - sizeof (__le32) - 1) #define RBD_IMAGE_ID_LEN_MAX 64 + #define RBD_OBJ_PREFIX_LEN_MAX 64 /* Feature bits */ @@ -658,6 +661,20 @@ out_err: return -ENOMEM; } +static const char *rbd_snap_name(struct rbd_device *rbd_dev, u64 snap_id) +{ + struct rbd_snap *snap; + + if (snap_id == CEPH_NOSNAP) + return RBD_SNAP_HEAD_NAME; + + list_for_each_entry(snap, &rbd_dev->snaps, node) + if (snap_id == snap->id) + return snap->name; + + return NULL; +} + static int snap_by_name(struct rbd_device *rbd_dev, const char *snap_name) { @@ -2499,6 +2516,7 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) goto out_err; } parent_spec->image_id = image_id; + parent_spec->image_id_len = len; ceph_decode_64_safe(&p, end, parent_spec->snap_id, out_err); ceph_decode_64_safe(&p, end, overlap, out_err); @@ -2514,6 +2532,117 @@ out_err: return ret; } +static char *rbd_dev_image_name(struct rbd_device *rbd_dev) +{ + size_t image_id_size; + char *image_id; + void *p; + void *end; + size_t size; + void *reply_buf = NULL; + size_t len = 0; + char *image_name = NULL; + int ret; + + rbd_assert(!rbd_dev->spec->image_name); + + image_id_size = sizeof (__le32) + rbd_dev->spec->image_id_len; + image_id = kmalloc(image_id_size, GFP_KERNEL); + if (!image_id) + return NULL; + + p = image_id; + end = (char *) image_id + image_id_size; + ceph_encode_string(&p, end, rbd_dev->spec->image_id, + (u32) rbd_dev->spec->image_id_len); + + size = sizeof (__le32) + RBD_IMAGE_NAME_LEN_MAX; + reply_buf = kmalloc(size, GFP_KERNEL); + if (!reply_buf) + goto out; + + ret = rbd_req_sync_exec(rbd_dev, RBD_DIRECTORY, + "rbd", "dir_get_name", + image_id, image_id_size, + (char *) reply_buf, size, + CEPH_OSD_FLAG_READ, NULL); + if (ret < 0) + goto out; + p = reply_buf; + end = (char *) reply_buf + size; + image_name = ceph_extract_encoded_string(&p, end, &len, GFP_KERNEL); + if (IS_ERR(image_name)) + image_name = NULL; + else + dout("%s: name is %s len is %zd\n", __func__, image_name, len); +out: + kfree(reply_buf); + kfree(image_id); + + return image_name; +} + +/* + * When a parent image gets probed, we only have the pool, image, + * and snapshot ids but not the names of any of them. This call + * is made later to fill in those names. It has to be done after + * rbd_dev_snaps_update() has completed because some of the + * information (in particular, snapshot name) is not available + * until then. + */ +static int rbd_dev_probe_update_spec(struct rbd_device *rbd_dev) +{ + struct ceph_osd_client *osdc; + const char *name; + void *reply_buf = NULL; + int ret; + + if (rbd_dev->spec->pool_name) + return 0; /* Already have the names */ + + /* Look up the pool name */ + + osdc = &rbd_dev->rbd_client->client->osdc; + name = ceph_pg_pool_name_by_id(osdc->osdmap, rbd_dev->spec->pool_id); + if (!name) + return -EIO; /* pool id too large (>= 2^31) */ + + rbd_dev->spec->pool_name = kstrdup(name, GFP_KERNEL); + if (!rbd_dev->spec->pool_name) + return -ENOMEM; + + /* Fetch the image name; tolerate failure here */ + + name = rbd_dev_image_name(rbd_dev); + if (name) { + rbd_dev->spec->image_name_len = strlen(name); + rbd_dev->spec->image_name = (char *) name; + } else { + pr_warning(RBD_DRV_NAME "%d " + "unable to get image name for image id %s\n", + rbd_dev->major, rbd_dev->spec->image_id); + } + + /* Look up the snapshot name. */ + + name = rbd_snap_name(rbd_dev, rbd_dev->spec->snap_id); + if (!name) { + ret = -EIO; + goto out_err; + } + rbd_dev->spec->snap_name = kstrdup(name, GFP_KERNEL); + if(!rbd_dev->spec->snap_name) + goto out_err; + + return 0; +out_err: + kfree(reply_buf); + kfree(rbd_dev->spec->pool_name); + rbd_dev->spec->pool_name = NULL; + + return ret; +} + static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev, u64 *ver) { size_t size; @@ -3372,6 +3501,10 @@ static int rbd_dev_probe_finish(struct rbd_device *rbd_dev) if (ret) return ret; + ret = rbd_dev_probe_update_spec(rbd_dev); + if (ret) + goto err_out_snaps; + ret = rbd_dev_set_mapping(rbd_dev); if (ret) goto err_out_snaps; -- cgit v0.10.2 From 63e1ed2364050073770c085021377d7764969b85 Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Sat, 27 Oct 2012 14:49:57 +1300 Subject: pwm: vt8500: Update vt8500 PWM driver support This patch updates pwm-vt8500.c to support devicetree probing and make use of the common clock subsystem. A binding document describing the PWM controller found on arch-vt8500 is also included. Signed-off-by: Tony Prisk Acked-by: Arnd Bergmann Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt b/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt new file mode 100644 index 0000000..bcc6367 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt @@ -0,0 +1,17 @@ +VIA/Wondermedia VT8500/WM8xxx series SoC PWM controller + +Required properties: +- compatible: should be "via,vt8500-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: should be 2. The first cell specifies the per-chip index + of the PWM to use and the second cell is the period in nanoseconds. +- clocks: phandle to the PWM source clock + +Example: + +pwm1: pwm@d8220000 { + #pwm-cells = <2>; + compatible = "via,vt8500-pwm"; + reg = <0xd8220000 0x1000>; + clocks = <&clkpwm>; +}; diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index ad14389..970b0c6 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -1,7 +1,8 @@ /* * drivers/pwm/pwm-vt8500.c * - * Copyright (C) 2010 Alexey Charkov + * Copyright (C) 2012 Tony Prisk + * Copyright (C) 2010 Alexey Charkov * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -21,14 +22,24 @@ #include #include #include +#include #include -#define VT8500_NR_PWMS 4 +#include +#include +#include + +/* + * SoC architecture allocates register space for 4 PWMs but only + * 2 are currently implemented. + */ +#define VT8500_NR_PWMS 2 struct vt8500_chip { struct pwm_chip chip; void __iomem *base; + struct clk *clk; }; #define to_vt8500_chip(chip) container_of(chip, struct vt8500_chip, chip) @@ -52,7 +63,7 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, unsigned long long c; unsigned long period_cycles, prescale, pv, dc; - c = 25000000/2; /* wild guess --- need to implement clocks */ + c = clk_get_rate(vt8500->clk); c = c * period_ns; do_div(c, 1000000000); period_cycles = c; @@ -85,8 +96,15 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { + int err; struct vt8500_chip *vt8500 = to_vt8500_chip(chip); + err = clk_enable(vt8500->clk); + if (err < 0) + dev_err(chip->dev, "failed to enable clock\n"); + return err; + }; + pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); writel(5, vt8500->base + (pwm->hwpwm << 4)); return 0; @@ -98,6 +116,8 @@ static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); writel(0, vt8500->base + (pwm->hwpwm << 4)); + + clk_disable(vt8500->clk); } static struct pwm_ops vt8500_pwm_ops = { @@ -107,12 +127,24 @@ static struct pwm_ops vt8500_pwm_ops = { .owner = THIS_MODULE, }; -static int __devinit pwm_probe(struct platform_device *pdev) +static const struct of_device_id vt8500_pwm_dt_ids[] = { + { .compatible = "via,vt8500-pwm", }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids); + +static int vt8500_pwm_probe(struct platform_device *pdev) { struct vt8500_chip *chip; struct resource *r; + struct device_node *np = pdev->dev.of_node; int ret; + if (!np) { + dev_err(&pdev->dev, "invalid devicetree node\n"); + return -EINVAL; + } + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) { dev_err(&pdev->dev, "failed to allocate memory\n"); @@ -124,6 +156,12 @@ static int __devinit pwm_probe(struct platform_device *pdev) chip->chip.base = -1; chip->chip.npwm = VT8500_NR_PWMS; + chip->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(chip->clk)) { + dev_err(&pdev->dev, "clock source not specified\n"); + return PTR_ERR(chip->clk); + } + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) { dev_err(&pdev->dev, "no memory resource defined\n"); @@ -131,18 +169,26 @@ static int __devinit pwm_probe(struct platform_device *pdev) } chip->base = devm_request_and_ioremap(&pdev->dev, r); - if (chip->base == NULL) + if (!chip->base) return -EADDRNOTAVAIL; + ret = clk_prepare(chip->clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to prepare clock\n"); + return ret; + } + ret = pwmchip_add(&chip->chip); - if (ret < 0) + if (ret < 0) { + dev_err(&pdev->dev, "failed to add PWM chip\n"); return ret; + } platform_set_drvdata(pdev, chip); return ret; } -static int __devexit pwm_remove(struct platform_device *pdev) +static int vt8500_pwm_remove(struct platform_device *pdev) { struct vt8500_chip *chip; @@ -150,28 +196,22 @@ static int __devexit pwm_remove(struct platform_device *pdev) if (chip == NULL) return -ENODEV; + clk_unprepare(chip->clk); + return pwmchip_remove(&chip->chip); } -static struct platform_driver pwm_driver = { +static struct platform_driver vt8500_pwm_driver = { + .probe = vt8500_pwm_probe, + .remove = vt8500_pwm_remove, .driver = { .name = "vt8500-pwm", .owner = THIS_MODULE, + .of_match_table = vt8500_pwm_dt_ids, }, - .probe = pwm_probe, - .remove = __devexit_p(pwm_remove), }; +module_platform_driver(vt8500_pwm_driver); -static int __init pwm_init(void) -{ - return platform_driver_register(&pwm_driver); -} -arch_initcall(pwm_init); - -static void __exit pwm_exit(void) -{ - platform_driver_unregister(&pwm_driver); -} -module_exit(pwm_exit); - -MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VT8500 PWM Driver"); +MODULE_AUTHOR("Tony Prisk "); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From d56a289be2ce01d1aa426a6cf45dede14a8db41e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Sat, 3 Nov 2012 12:05:52 -0700 Subject: Input: pwm-beeper - add devicetree probing support A very simple binding, the only property is the phandle to the PWM. Signed-off-by: Sascha Hauer Reviewed-by: Thierry Reding Signed-off-by: Dmitry Torokhov diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.txt b/Documentation/devicetree/bindings/input/pwm-beeper.txt new file mode 100644 index 0000000..be332ae --- /dev/null +++ b/Documentation/devicetree/bindings/input/pwm-beeper.txt @@ -0,0 +1,7 @@ +* PWM beeper device tree bindings + +Registers a PWM device as beeper. + +Required properties: +- compatible: should be "pwm-beeper" +- pwms: phandle to the physical PWM device diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index c835357..0f959d7 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -441,7 +441,7 @@ config INPUT_PCF8574 config INPUT_PWM_BEEPER tristate "PWM beeper support" - depends on HAVE_PWM + depends on HAVE_PWM || PWM help Say Y here to get support for PWM based beeper devices. diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index fc84c8a..502544c 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -75,7 +75,11 @@ static int __devinit pwm_beeper_probe(struct platform_device *pdev) if (!beeper) return -ENOMEM; - beeper->pwm = pwm_request(pwm_id, "pwm beeper"); + beeper->pwm = pwm_get(&pdev->dev, NULL); + if (IS_ERR(beeper->pwm)) { + dev_dbg(&pdev->dev, "unable to request PWM, trying legacy API\n"); + beeper->pwm = pwm_request(pwm_id, "pwm beeper"); + } if (IS_ERR(beeper->pwm)) { error = PTR_ERR(beeper->pwm); @@ -171,6 +175,13 @@ static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops, #define PWM_BEEPER_PM_OPS NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id pwm_beeper_match[] = { + { .compatible = "pwm-beeper", }, + { }, +}; +#endif + static struct platform_driver pwm_beeper_driver = { .probe = pwm_beeper_probe, .remove = __devexit_p(pwm_beeper_remove), @@ -178,6 +189,7 @@ static struct platform_driver pwm_beeper_driver = { .name = "pwm-beeper", .owner = THIS_MODULE, .pm = PWM_BEEPER_PM_OPS, + .of_match_table = of_match_ptr(pwm_beeper_match), }, }; module_platform_driver(pwm_beeper_driver); -- cgit v0.10.2 From 4d1d0534f53863108fdea496288cb3310f88118d Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Sat, 3 Nov 2012 10:32:37 +0800 Subject: ceph: Hold caps_list_lock when adjusting caps_{use, total}_count Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 3251e9c..2d0141e 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -236,8 +236,10 @@ static struct ceph_cap *get_cap(struct ceph_mds_client *mdsc, if (!ctx) { cap = kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS); if (cap) { + spin_lock(&mdsc->caps_list_lock); mdsc->caps_use_count++; mdsc->caps_total_count++; + spin_unlock(&mdsc->caps_list_lock); } return cap; } -- cgit v0.10.2 From 168e4b39d1afb79a7e3ea6c3bb246b4c82c6bdb9 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 30 Oct 2012 17:01:40 -0400 Subject: SUNRPC: add WARN_ON_ONCE for potential deadlock rpc_shutdown_client should never be called from a workqueue context. If it is, it could deadlock looping forever trying to kill tasks that are assigned to the same kworker thread (and will never run rpc_exit_task). Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index cdc7564..dd2532c 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -607,6 +607,13 @@ EXPORT_SYMBOL_GPL(rpc_killall_tasks); */ void rpc_shutdown_client(struct rpc_clnt *clnt) { + /* + * To avoid deadlock, never call rpc_shutdown_client from a + * workqueue context! + */ + WARN_ON_ONCE(current->flags & PF_WQ_WORKER); + might_sleep(); + dprintk_rcu("RPC: shutting down %s client for %s\n", clnt->cl_protname, rcu_dereference(clnt->cl_xprt)->servername); -- cgit v0.10.2 From 1fea73a86527d7ec463af6ff04b0830e1425ff6c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 11:24:57 -0400 Subject: NFS: Get rid of unnecessary asserts If the nfs_client fails to initialise correctly, then it will return an error condition. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 8b39a42..c285e0a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -277,7 +277,7 @@ void nfs_put_client(struct nfs_client *clp) nfs_cb_idr_remove_locked(clp); spin_unlock(&nn->nfs_client_lock); - BUG_ON(!list_empty(&clp->cl_superblocks)); + WARN_ON_ONCE(!list_empty(&clp->cl_superblocks)); clp->rpc_ops->free_client(clp); } @@ -1061,10 +1061,6 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info, if (error < 0) goto error; - BUG_ON(!server->nfs_client); - BUG_ON(!server->nfs_client->rpc_ops); - BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); - /* Probe the root fh to retrieve its FSID */ error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr); if (error < 0) diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 6bacfde..72717e6 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -713,10 +713,6 @@ static int nfs4_server_common_setup(struct nfs_server *server, struct nfs_fattr *fattr; int error; - BUG_ON(!server->nfs_client); - BUG_ON(!server->nfs_client->rpc_ops); - BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); - /* data servers support only a subset of NFSv4.1 */ if (is_ds_only_client(server->nfs_client)) return -EPROTONOSUPPORT; -- cgit v0.10.2 From 7fc388460e8479c5b3120cb2fcf0e0daec70b93f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 11:51:21 -0400 Subject: NFS: Remove asserts from the NFS XDR code Convert the ones that are not trivial to check into WARN_ON_ONCE(). Remove checks for things such as NFS2_MAXPATHLEN, which are trivially done by the caller. Add a comment to the case of nfs3_xdr_enc_setacl3args. What is being done there is just wrong... Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index d04f0df..06b9df4 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -195,7 +195,6 @@ static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh) { __be32 *p; - BUG_ON(fh->size != NFS2_FHSIZE); p = xdr_reserve_space(xdr, NFS2_FHSIZE); memcpy(p, fh->data, NFS2_FHSIZE); } @@ -388,7 +387,7 @@ static void encode_filename(struct xdr_stream *xdr, { __be32 *p; - BUG_ON(length > NFS2_MAXNAMLEN); + WARN_ON_ONCE(length > NFS2_MAXNAMLEN); p = xdr_reserve_space(xdr, 4 + length); xdr_encode_opaque(p, name, length); } @@ -428,7 +427,6 @@ static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length) { __be32 *p; - BUG_ON(length > NFS2_MAXPATHLEN); p = xdr_reserve_space(xdr, 4); *p = cpu_to_be32(length); xdr_write_pages(xdr, pages, 0, length); diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 6cbe894..bffc324 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -198,7 +198,7 @@ static void encode_filename3(struct xdr_stream *xdr, { __be32 *p; - BUG_ON(length > NFS3_MAXNAMLEN); + WARN_ON_ONCE(length > NFS3_MAXNAMLEN); p = xdr_reserve_space(xdr, 4 + length); xdr_encode_opaque(p, name, length); } @@ -238,7 +238,6 @@ out_overflow: static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages, const u32 length) { - BUG_ON(length > NFS3_MAXPATHLEN); encode_uint32(xdr, length); xdr_write_pages(xdr, pages, 0, length); } @@ -388,7 +387,6 @@ out_overflow: */ static void encode_ftype3(struct xdr_stream *xdr, const u32 type) { - BUG_ON(type > NF3FIFO); encode_uint32(xdr, type); } @@ -443,7 +441,7 @@ static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh) { __be32 *p; - BUG_ON(fh->size > NFS3_FHSIZE); + WARN_ON_ONCE(fh->size > NFS3_FHSIZE); p = xdr_reserve_space(xdr, 4 + fh->size); xdr_encode_opaque(p, fh->data, fh->size); } @@ -1339,6 +1337,7 @@ static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, error = nfsacl_encode(xdr->buf, base, args->inode, (args->mask & NFS_ACL) ? args->acl_access : NULL, 1, 0); + /* FIXME: this is just broken */ BUG_ON(error < 0); error = nfsacl_encode(xdr->buf, base + error, args->inode, (args->mask & NFS_DFACL) ? diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 40836ee..672d9b0 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -936,7 +936,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr, * but this is not required as a MUST for the server to do so. */ hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen; - BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); + WARN_ON_ONCE(hdr->taglen > NFS4_MAXTAGLEN); encode_string(xdr, hdr->taglen, hdr->tag); p = reserve_space(xdr, 8); *p++ = cpu_to_be32(hdr->minorversion); @@ -955,7 +955,7 @@ static void encode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 op, static void encode_nops(struct compound_hdr *hdr) { - BUG_ON(hdr->nops > NFS4_MAX_OPS); + WARN_ON_ONCE(hdr->nops > NFS4_MAX_OPS); *hdr->nops_p = htonl(hdr->nops); } @@ -1403,7 +1403,6 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a *p = cpu_to_be32(NFS4_OPEN_NOCREATE); break; default: - BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL); *p = cpu_to_be32(NFS4_OPEN_CREATE); encode_createmode(xdr, arg); } @@ -1621,7 +1620,6 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun p = reserve_space(xdr, 2*4); *p++ = cpu_to_be32(1); *p = cpu_to_be32(FATTR4_WORD0_ACL); - BUG_ON(arg->acl_len % 4); p = reserve_space(xdr, 4); *p = cpu_to_be32(arg->acl_len); xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); -- cgit v0.10.2 From d3edcf96141a7729b12ef5ecab6d5f634e24c61a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 13:14:43 -0400 Subject: NFSv4: Remove the BUG_ON() from nfs4_get_lease_time_prepare()... An EAGAIN return value would be unexpected, but there is no reason to BUG... Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5eec442..14d86ef 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5581,8 +5581,8 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task, &data->args->la_seq_args, &data->res->lr_seq_res, task); - BUG_ON(ret == -EAGAIN); - rpc_call_start(task); + if (ret != -EAGAIN) + rpc_call_start(task); dprintk("<-- %s\n", __func__); } -- cgit v0.10.2 From eba24e1fe57df4e4cdee58af940f762eb336a113 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 14:47:33 -0400 Subject: NFSv4.1: Remove unused function last_byte_offset Signed-off-by: Trond Myklebust diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c index 8746135..a9ebd81 100644 --- a/fs/nfs/objlayout/objlayout.c +++ b/fs/nfs/objlayout/objlayout.c @@ -148,17 +148,6 @@ end_offset(u64 start, u64 len) return end >= start ? end : NFS4_MAX_UINT64; } -/* last octet in a range */ -static inline u64 -last_byte_offset(u64 start, u64 len) -{ - u64 end; - - BUG_ON(!len); - end = start + len; - return end > start ? end - 1 : NFS4_MAX_UINT64; -} - static void _fix_verify_io_params(struct pnfs_layout_segment *lseg, struct page ***p_pages, unsigned *p_pgbase, u64 offset, unsigned long count) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 2878f97..dcbc9b2 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -369,17 +369,6 @@ end_offset(u64 start, u64 len) return end >= start ? end : NFS4_MAX_UINT64; } -/* last octet in a range */ -static inline u64 -last_byte_offset(u64 start, u64 len) -{ - u64 end; - - BUG_ON(!len); - end = start + len; - return end > start ? end - 1 : NFS4_MAX_UINT64; -} - /* * is l2 fully contained in l1? * start1 end1 -- cgit v0.10.2 From bc5a89b337ee4b2fa6f577e7e1220d8c1ece71fc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 14:58:04 -0400 Subject: NFSv4.1: Remove assertion BUG_ON()s from the files and generic layout code Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 2e45fd9..bfb28fa 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -512,7 +512,6 @@ filelayout_read_pagelist(struct nfs_read_data *data) loff_t offset = data->args.offset; u32 j, idx; struct nfs_fh *fh; - int status; dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n", __func__, hdr->inode->i_ino, @@ -538,9 +537,8 @@ filelayout_read_pagelist(struct nfs_read_data *data) data->mds_offset = offset; /* Perform an asynchronous read to ds */ - status = nfs_initiate_read(ds->ds_clp->cl_rpcclient, data, + nfs_initiate_read(ds->ds_clp->cl_rpcclient, data, &filelayout_read_call_ops, RPC_TASK_SOFTCONN); - BUG_ON(status != 0); return PNFS_ATTEMPTED; } @@ -554,7 +552,6 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) loff_t offset = data->args.offset; u32 j, idx; struct nfs_fh *fh; - int status; /* Retrieve the correct rpc_client for the byte range */ j = nfs4_fl_calc_j_index(lseg, offset); @@ -579,10 +576,9 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) data->args.offset = filelayout_get_dserver_offset(lseg, offset); /* Perform an asynchronous write */ - status = nfs_initiate_write(ds->ds_clp->cl_rpcclient, data, + nfs_initiate_write(ds->ds_clp->cl_rpcclient, data, &filelayout_write_call_ops, sync, RPC_TASK_SOFTCONN); - BUG_ON(status != 0); return PNFS_ATTEMPTED; } @@ -909,7 +905,7 @@ static void filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) { - BUG_ON(pgio->pg_lseg != NULL); + WARN_ON_ONCE(pgio->pg_lseg != NULL); if (req->wb_offset != req->wb_pgbase) { /* @@ -939,7 +935,7 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_commit_info cinfo; int status; - BUG_ON(pgio->pg_lseg != NULL); + WARN_ON_ONCE(pgio->pg_lseg != NULL); if (req->wb_offset != req->wb_pgbase) goto out_mds; @@ -1187,7 +1183,6 @@ static void filelayout_recover_commit_reqs(struct list_head *dst, */ for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) { if (transfer_commit_list(&b->written, dst, cinfo, 0)) { - BUG_ON(!list_empty(&b->written)); pnfs_put_lseg(b->wlseg); b->wlseg = NULL; } diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index a8eaa9b..93e2530 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c @@ -162,8 +162,6 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) dprintk("--> %s DS %s au_flavor %d\n", __func__, ds->ds_remotestr, mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor); - BUG_ON(list_empty(&ds->ds_addrs)); - list_for_each_entry(da, &ds->ds_addrs, da_node) { dprintk("%s: DS %s: trying address %s\n", __func__, ds->ds_remotestr, da->da_remotestr); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index dcbc9b2..e7165d9 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -634,7 +634,6 @@ send_layoutget(struct pnfs_layout_hdr *lo, dprintk("--> %s\n", __func__); - BUG_ON(ctx == NULL); lgp = kzalloc(sizeof(*lgp), gfp_flags); if (lgp == NULL) return NULL; @@ -1115,7 +1114,6 @@ pnfs_update_layout(struct inode *ino, * chance of a CB_LAYOUTRECALL(FILE) coming in. */ spin_lock(&clp->cl_lock); - BUG_ON(!list_empty(&lo->plh_layouts)); list_add_tail(&lo->plh_layouts, &server->layouts); spin_unlock(&clp->cl_lock); } @@ -1211,7 +1209,7 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r { u64 rd_size = req->wb_bytes; - BUG_ON(pgio->pg_lseg != NULL); + WARN_ON_ONCE(pgio->pg_lseg != NULL); if (req->wb_offset != req->wb_pgbase) { nfs_pageio_reset_read_mds(pgio); @@ -1240,7 +1238,7 @@ void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req, u64 wb_size) { - BUG_ON(pgio->pg_lseg != NULL); + WARN_ON_ONCE(pgio->pg_lseg != NULL); if (req->wb_offset != req->wb_pgbase) { nfs_pageio_reset_write_mds(pgio); -- cgit v0.10.2 From deed85e760c8c88cd984c5921dd8cb6b697b6134 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 15:02:01 -0400 Subject: NFS: Remove BUG_ON() calls from the generic writeback code ...and ensure that we set the return value for nfs_page_async_flush() to zero! (Reported-by: Dros Adamson) Signed-off-by: Trond Myklebust diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 9347ab7..f5bc8e1 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -239,21 +239,18 @@ int nfs_congestion_kb; #define NFS_CONGESTION_OFF_THRESH \ (NFS_CONGESTION_ON_THRESH - (NFS_CONGESTION_ON_THRESH >> 2)) -static int nfs_set_page_writeback(struct page *page) +static void nfs_set_page_writeback(struct page *page) { + struct nfs_server *nfss = NFS_SERVER(page_file_mapping(page)->host); int ret = test_set_page_writeback(page); - if (!ret) { - struct inode *inode = page_file_mapping(page)->host; - struct nfs_server *nfss = NFS_SERVER(inode); + WARN_ON_ONCE(ret != 0); - if (atomic_long_inc_return(&nfss->writeback) > - NFS_CONGESTION_ON_THRESH) { - set_bdi_congested(&nfss->backing_dev_info, - BLK_RW_ASYNC); - } + if (atomic_long_inc_return(&nfss->writeback) > + NFS_CONGESTION_ON_THRESH) { + set_bdi_congested(&nfss->backing_dev_info, + BLK_RW_ASYNC); } - return ret; } static void nfs_end_page_writeback(struct page *page) @@ -315,10 +312,10 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, if (IS_ERR(req)) goto out; - ret = nfs_set_page_writeback(page); - BUG_ON(ret != 0); - BUG_ON(test_bit(PG_CLEAN, &req->wb_flags)); + nfs_set_page_writeback(page); + WARN_ON_ONCE(test_bit(PG_CLEAN, &req->wb_flags)); + ret = 0; if (!nfs_pageio_add_request(pgio, req)) { nfs_redirty_request(req); ret = pgio->pg_error; @@ -451,8 +448,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) struct inode *inode = req->wb_context->dentry->d_inode; struct nfs_inode *nfsi = NFS_I(inode); - BUG_ON (!NFS_WBACK_BUSY(req)); - spin_lock(&inode->i_lock); if (likely(!PageSwapCache(req->wb_page))) { set_page_private(req->wb_page, 0); @@ -1727,7 +1722,6 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page) struct nfs_page *req; int ret = 0; - BUG_ON(!PageLocked(page)); for (;;) { wait_on_page_writeback(page); req = nfs_page_find_request(page); -- cgit v0.10.2 From 4ea8fed593218b658927b763f02941cd16c2ed9d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 15:47:41 -0400 Subject: NFSv4: Get rid of unnecessary BUG_ON()s Signed-off-by: Trond Myklebust diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c index dded263..862a2f1 100644 --- a/fs/nfs/cache_lib.c +++ b/fs/nfs/cache_lib.c @@ -118,7 +118,6 @@ int nfs_cache_register_sb(struct super_block *sb, struct cache_detail *cd) struct dentry *dir; dir = rpc_d_lookup_sb(sb, "cache"); - BUG_ON(dir == NULL); ret = sunrpc_cache_register_pipefs(dir, cd->name, 0600, cd); dput(dir); return ret; diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 76b4a7a..0be08b9 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -216,7 +216,6 @@ static u32 initiate_bulk_draining(struct nfs_client *clp, } pnfs_get_layout_hdr(lo); spin_unlock(&ino->i_lock); - BUG_ON(!list_empty(&lo->plh_bulk_recall)); list_add(&lo->plh_bulk_recall, &recall_list); } } diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index afddd66..e769930 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -20,7 +20,6 @@ nfs4_file_open(struct inode *inode, struct file *filp) struct iattr attr; int err; - BUG_ON(inode != dentry->d_inode); /* * If no cached dentry exists or if it's negative, NFSv4 handled the * opens in ->lookup() or ->create(). diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 14d86ef..6300cdd 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -206,7 +206,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent { __be32 *start, *p; - BUG_ON(readdir->count < 80); if (cookie > 2) { readdir->cookie = cookie; memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier)); @@ -415,7 +414,6 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp static void nfs4_free_slot(struct nfs4_slot_table *tbl, u32 slotid) { - BUG_ON(slotid >= NFS4_MAX_SLOT_TABLE); /* clear used bit in bitmap */ __clear_bit(slotid, tbl->used_slots); @@ -2533,7 +2531,8 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS]; len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array)); - BUG_ON(len < 0); + if (len < 0) + return len; for (i = 0; i < len; i++) { /* AUTH_UNIX is the default flavor if none was specified, @@ -3362,9 +3361,6 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, int mode = sattr->ia_mode; int status = -ENOMEM; - BUG_ON(!(sattr->ia_valid & ATTR_MODE)); - BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode)); - data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK); if (data == NULL) goto out; @@ -3380,10 +3376,13 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, data->arg.ftype = NF4CHR; data->arg.u.device.specdata1 = MAJOR(rdev); data->arg.u.device.specdata2 = MINOR(rdev); + } else if (!S_ISSOCK(mode)) { + status = -EINVAL; + goto out_free; } status = nfs4_do_create(dir, dentry, data); - +out_free: nfs4_free_createdata(data); out: return status; @@ -5357,7 +5356,6 @@ int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred }; dprintk("--> %s\n", __func__); - BUG_ON(clp == NULL); res.session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS); if (unlikely(res.session == NULL)) { diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index c351e6b..e0a28df 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1086,7 +1086,6 @@ void nfs_free_seqid(struct nfs_seqid *seqid) */ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) { - BUG_ON(list_first_entry(&seqid->sequence->list, struct nfs_seqid, list) != seqid); switch (status) { case 0: break; -- cgit v0.10.2 From f48407ddd46bd215a7b4e1af3940e759a93640c5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 16:19:30 -0400 Subject: NFS: Remove BUG_ON()s in the fs/nfs/inode.c Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6fa01ae..117183b 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -112,8 +112,8 @@ void nfs_clear_inode(struct inode *inode) /* * The following should never happen... */ - BUG_ON(nfs_have_writebacks(inode)); - BUG_ON(!list_empty(&NFS_I(inode)->open_files)); + WARN_ON_ONCE(nfs_have_writebacks(inode)); + WARN_ON_ONCE(!list_empty(&NFS_I(inode)->open_files)); nfs_zap_acl_cache(inode); nfs_access_zap_cache(inode); nfs_fscache_release_inode_cookie(inode); -- cgit v0.10.2 From 28d79ea33f52cae1ea04808e1ec52b8657b5d804 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 16:25:42 -0400 Subject: NFS: Remove the BUG_ON() in the mount code Signed-off-by: Trond Myklebust diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 015f71f..91a6faf 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -169,6 +169,9 @@ int nfs_mount(struct nfs_mount_request *info) (info->hostname ? info->hostname : "server"), info->dirpath); + if (strlen(info->dirpath) > MNTPATHLEN) + return -ENAMETOOLONG; + if (info->noresvport) args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; @@ -242,6 +245,9 @@ void nfs_umount(const struct nfs_mount_request *info) struct rpc_clnt *clnt; int status; + if (strlen(info->dirpath) > MNTPATHLEN) + return; + if (info->noresvport) args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; @@ -283,7 +289,6 @@ static void encode_mntdirpath(struct xdr_stream *xdr, const char *pathname) const u32 pathname_len = strlen(pathname); __be32 *p; - BUG_ON(pathname_len > MNTPATHLEN); p = xdr_reserve_space(xdr, 4 + pathname_len); xdr_encode_opaque(p, pathname, pathname_len); } -- cgit v0.10.2 From aad56de378b4c675e964a1ab44cf2e55d44d2865 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 17:14:38 -0400 Subject: lockd: Remove unnecessary BUG_ON()s in the xdr client code - Offset bound checks are done in the NFS client code. - So are filehandle size checks - The cookie length is a constant - The utsname()->nodename is already bounded Signed-off-by: Trond Myklebust diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c index 13ad153..00ec0b9 100644 --- a/fs/lockd/clnt4xdr.c +++ b/fs/lockd/clnt4xdr.c @@ -64,10 +64,6 @@ static void nlm4_compute_offsets(const struct nlm_lock *lock, { const struct file_lock *fl = &lock->fl; - BUG_ON(fl->fl_start > NLM4_OFFSET_MAX); - BUG_ON(fl->fl_end > NLM4_OFFSET_MAX && - fl->fl_end != OFFSET_MAX); - *l_offset = loff_t_to_s64(fl->fl_start); if (fl->fl_end == OFFSET_MAX) *l_len = 0; @@ -122,7 +118,6 @@ static void encode_netobj(struct xdr_stream *xdr, { __be32 *p; - BUG_ON(length > XDR_MAX_NETOBJ); p = xdr_reserve_space(xdr, 4 + length); xdr_encode_opaque(p, data, length); } @@ -156,7 +151,6 @@ out_overflow: static void encode_cookie(struct xdr_stream *xdr, const struct nlm_cookie *cookie) { - BUG_ON(cookie->len > NLM_MAXCOOKIELEN); encode_netobj(xdr, (u8 *)&cookie->data, cookie->len); } @@ -198,7 +192,6 @@ out_overflow: */ static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh) { - BUG_ON(fh->size > NFS3_FHSIZE); encode_netobj(xdr, (u8 *)&fh->data, fh->size); } @@ -336,7 +329,6 @@ static void encode_caller_name(struct xdr_stream *xdr, const char *name) u32 length = strlen(name); __be32 *p; - BUG_ON(length > NLM_MAXSTRLEN); p = xdr_reserve_space(xdr, 4 + length); xdr_encode_opaque(p, name, length); } diff --git a/fs/lockd/clntxdr.c b/fs/lockd/clntxdr.c index 982d267..9a55797 100644 --- a/fs/lockd/clntxdr.c +++ b/fs/lockd/clntxdr.c @@ -60,10 +60,6 @@ static void nlm_compute_offsets(const struct nlm_lock *lock, { const struct file_lock *fl = &lock->fl; - BUG_ON(fl->fl_start > NLM_OFFSET_MAX); - BUG_ON(fl->fl_end > NLM_OFFSET_MAX && - fl->fl_end != OFFSET_MAX); - *l_offset = loff_t_to_s32(fl->fl_start); if (fl->fl_end == OFFSET_MAX) *l_len = 0; @@ -119,7 +115,6 @@ static void encode_netobj(struct xdr_stream *xdr, { __be32 *p; - BUG_ON(length > XDR_MAX_NETOBJ); p = xdr_reserve_space(xdr, 4 + length); xdr_encode_opaque(p, data, length); } @@ -153,7 +148,6 @@ out_overflow: static void encode_cookie(struct xdr_stream *xdr, const struct nlm_cookie *cookie) { - BUG_ON(cookie->len > NLM_MAXCOOKIELEN); encode_netobj(xdr, (u8 *)&cookie->data, cookie->len); } @@ -195,7 +189,6 @@ out_overflow: */ static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh) { - BUG_ON(fh->size != NFS2_FHSIZE); encode_netobj(xdr, (u8 *)&fh->data, NFS2_FHSIZE); } @@ -330,7 +323,6 @@ static void encode_caller_name(struct xdr_stream *xdr, const char *name) u32 length = strlen(name); __be32 *p; - BUG_ON(length > NLM_MAXSTRLEN); p = xdr_reserve_space(xdr, 4 + length); xdr_encode_opaque(p, name, length); } -- cgit v0.10.2 From 326ce0a6da64df3eb8f13a623304ab8033d38c12 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 17:21:04 -0400 Subject: lockd: Remove trivial BUG_ON()s from the NSM code Signed-off-by: Trond Myklebust diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 3d7e09b..3c2cfc6 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -154,8 +154,6 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, .rpc_resp = res, }; - BUG_ON(clnt == NULL); - memset(res, 0, sizeof(*res)); msg.rpc_proc = &clnt->cl_procinfo[proc]; @@ -466,7 +464,6 @@ static void encode_nsm_string(struct xdr_stream *xdr, const char *string) const u32 len = strlen(string); __be32 *p; - BUG_ON(len > SM_MAXSTRLEN); p = xdr_reserve_space(xdr, 4 + len); xdr_encode_opaque(p, string, len); } -- cgit v0.10.2 From a2d30a54df968c01fff4a412ac23f55832f45fe6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 17:26:20 -0400 Subject: lockd: Remove BUG_ON()s in fs/lockd/host.c - Convert the non-trivial ones into WARN_ON_ONCE(). - Remove the trivial refcounting BUGs Signed-off-by: Trond Myklebust diff --git a/fs/lockd/host.c b/fs/lockd/host.c index f9b22e5..0e17090 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -177,9 +177,6 @@ static void nlm_destroy_host_locked(struct nlm_host *host) dprintk("lockd: destroy host %s\n", host->h_name); - BUG_ON(!list_empty(&host->h_lockowners)); - BUG_ON(atomic_read(&host->h_count)); - hlist_del_init(&host->h_hash); nsm_unmonitor(host); @@ -289,13 +286,12 @@ void nlmclnt_release_host(struct nlm_host *host) dprintk("lockd: release client host %s\n", host->h_name); - BUG_ON(atomic_read(&host->h_count) < 0); - BUG_ON(host->h_server); + WARN_ON_ONCE(host->h_server); if (atomic_dec_and_test(&host->h_count)) { - BUG_ON(!list_empty(&host->h_lockowners)); - BUG_ON(!list_empty(&host->h_granted)); - BUG_ON(!list_empty(&host->h_reclaim)); + WARN_ON_ONCE(!list_empty(&host->h_lockowners)); + WARN_ON_ONCE(!list_empty(&host->h_granted)); + WARN_ON_ONCE(!list_empty(&host->h_reclaim)); mutex_lock(&nlm_host_mutex); nlm_destroy_host_locked(host); @@ -412,8 +408,7 @@ void nlmsvc_release_host(struct nlm_host *host) dprintk("lockd: release server host %s\n", host->h_name); - BUG_ON(atomic_read(&host->h_count) < 0); - BUG_ON(!host->h_server); + WARN_ON_ONCE(!host->h_server); atomic_dec(&host->h_count); } -- cgit v0.10.2 From 262693482cd56f887174ad1c0c2bb4f94ffad0ee Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 15 Oct 2012 17:28:45 -0400 Subject: lockd: Remove BUG_ON()s from fs/lockd/clntproc.c Signed-off-by: Trond Myklebust diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 05d2912..54f9e6c 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -141,7 +141,7 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) static void nlmclnt_release_lockargs(struct nlm_rqst *req) { - BUG_ON(req->a_args.lock.fl.fl_ops != NULL); + WARN_ON_ONCE(req->a_args.lock.fl.fl_ops != NULL); } /** @@ -465,7 +465,6 @@ static const struct file_lock_operations nlmclnt_lock_ops = { static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host) { - BUG_ON(fl->fl_ops != NULL); fl->fl_u.nfs_fl.state = 0; fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner); INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list); -- cgit v0.10.2 From 922eeac30d8456b8e4462cfb94ddbb6846790ad4 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:25 -0400 Subject: SUNRPC: remove BUG_ON in __rpc_clnt_handle_event Print a KERN_INFO message before rpc_d_lookup_sb returns NULL, like other error paths in that function. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index dd2532c..245de1a 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -132,8 +132,10 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, int error; dir = rpc_d_lookup_sb(sb, dir_name); - if (dir == NULL) + if (dir == NULL) { + pr_info("RPC: pipefs directory doesn't exist: %s\n", dir_name); return dir; + } for (;;) { q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); name[sizeof(name) - 1] = '\0'; @@ -192,7 +194,8 @@ static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event, case RPC_PIPEFS_MOUNT: dentry = rpc_setup_pipedir_sb(sb, clnt, clnt->cl_program->pipe_dir_name); - BUG_ON(dentry == NULL); + if (!dentry) + return -ENOENT; if (IS_ERR(dentry)) return PTR_ERR(dentry); clnt->cl_dentry = dentry; -- cgit v0.10.2 From 9a6478f6cccbd15af30f02368e68b47390360485 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:27 -0400 Subject: SUNRPC: remove BUG_ON from rpc_run_bc_task Replace BUG_ON() with WARN_ON_ONCE() - rpc_run_bc_task calls rpc_init_task() then increments the tk_count, so this is a simple sanity check that if hit once would hit every time this code path is executed. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 245de1a..32aea0b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -918,7 +918,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, task->tk_action = call_bc_transmit; atomic_inc(&task->tk_count); - BUG_ON(atomic_read(&task->tk_count) != 2); + WARN_ON_ONCE(atomic_read(&task->tk_count) != 2); rpc_execute(task); out: -- cgit v0.10.2 From 576e613d2111036a075b7c4f7cafdf29a0021c29 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:28 -0400 Subject: SUNRPC: remove BUG_ON from call_transmit Remove unneeded BUG_ON() Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 32aea0b..f1ab4a8 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1664,7 +1664,6 @@ call_transmit(struct rpc_task *task) task->tk_action = call_transmit_status; /* Encode here so that rpcsec_gss can use correct sequence number. */ if (rpc_task_need_encode(task)) { - BUG_ON(task->tk_rqstp->rq_bytes_sent != 0); rpc_xdr_encode(task); /* Did the encode result in an error condition? */ if (task->tk_status != 0) { -- cgit v0.10.2 From 1facf4c4a486d515759edc0b2ece927942dd8167 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:30 -0400 Subject: SUNRPC: remove BUG_ON from call_bc_transmit Replace BUG_ON() with WARN_ON_ONCE(). Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f1ab4a8..9131401 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1794,7 +1794,7 @@ call_bc_transmit(struct rpc_task *task) * We were unable to reply and will have to drop the * request. The server should reconnect and retransmit. */ - BUG_ON(task->tk_status == -EAGAIN); + WARN_ON_ONCE(task->tk_status == -EAGAIN); printk(KERN_NOTICE "RPC: Could not send backchannel reply " "error: %d\n", task->tk_status); break; -- cgit v0.10.2 From 8b827e1f1e46c45a4c9c389676f622e569d8a8ea Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:31 -0400 Subject: SUNRPC: remove BUG_ON from call_bc_transmit Remove redundant BUG_ON(). Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 9131401..a9dd1e8 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1747,7 +1747,6 @@ call_bc_transmit(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; - BUG_ON(task->tk_status != 0); task->tk_status = xprt_prepare_transmit(task); if (task->tk_status == -EAGAIN) { /* -- cgit v0.10.2 From e454a7a83d20cc5ec338ad0e3abae85f10d5a0c4 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:32 -0400 Subject: SUNRPC: remove BUG_ON from rpc_sleep_on* Replace BUG_ON() with WARN_ON_ONCE() and clean up after inactive task. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 6357fcb..f494b35 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -343,7 +343,12 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, rpc_action action) { /* We shouldn't ever put an inactive task to sleep */ - BUG_ON(!RPC_IS_ACTIVATED(task)); + WARN_ON_ONCE(!RPC_IS_ACTIVATED(task)); + if (!RPC_IS_ACTIVATED(task)) { + task->tk_status = -EIO; + rpc_put_task_async(task); + return; + } /* * Protect the queue operations. @@ -358,7 +363,12 @@ void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task, rpc_action action, int priority) { /* We shouldn't ever put an inactive task to sleep */ - BUG_ON(!RPC_IS_ACTIVATED(task)); + WARN_ON_ONCE(!RPC_IS_ACTIVATED(task)); + if (!RPC_IS_ACTIVATED(task)) { + task->tk_status = -EIO; + rpc_put_task_async(task); + return; + } /* * Protect the queue operations. -- cgit v0.10.2 From c4ded8d9771c8e8d5d7a202d58af9c70591dd675 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:34 -0400 Subject: SUNRPC: remove BUG_ON from xprt_destroy_backchannel If max_reqs is 0, do nothing besides the usual dprintks. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index a9c0bbc..80aa881 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -191,7 +191,9 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs) dprintk("RPC: destroy backchannel transport\n"); - BUG_ON(max_reqs == 0); + if (max_reqs == 0) + goto out; + spin_lock_bh(&xprt->bc_pa_lock); xprt_dec_alloc_count(xprt, max_reqs); list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) { @@ -202,6 +204,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs) } spin_unlock_bh(&xprt->bc_pa_lock); +out: dprintk("RPC: backchannel list empty= %s\n", list_empty(&xprt->bc_pa_list) ? "true" : "false"); } -- cgit v0.10.2 From 4c9c52e479f493ccfc3f513e870912115b49058f Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:35 -0400 Subject: SUNRPC: remove BUG_ON from bc_send Replace BUG_ON() with WARN_ON_ONCE(). The error condition is a simple ref counting sanity check and the following code will not free anything until final put. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/bc_svc.c b/net/sunrpc/bc_svc.c index 0b2eb38..15c7a8a 100644 --- a/net/sunrpc/bc_svc.c +++ b/net/sunrpc/bc_svc.c @@ -53,7 +53,7 @@ int bc_send(struct rpc_rqst *req) if (IS_ERR(task)) ret = PTR_ERR(task); else { - BUG_ON(atomic_read(&task->tk_count) != 1); + WARN_ON_ONCE(atomic_read(&task->tk_count) != 1); ret = task->tk_status; rpc_put_task(task); } -- cgit v0.10.2 From 0db74d9a2d2b312dd2cff066c5b97b8e626e403a Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:36 -0400 Subject: SUNRPC: remove BUG_ON calls from cache_read Replace BUG_ON() with WARN_ON_ONCE() in two parts of cache_read(). Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index fc2f7aa..9afa439 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -775,11 +775,11 @@ static ssize_t cache_read(struct file *filp, char __user *buf, size_t count, if (rp->q.list.next == &cd->queue) { spin_unlock(&queue_lock); mutex_unlock(&inode->i_mutex); - BUG_ON(rp->offset); + WARN_ON_ONCE(rp->offset); return 0; } rq = container_of(rp->q.list.next, struct cache_request, q.list); - BUG_ON(rq->q.reader); + WARN_ON_ONCE(rq->q.reader); if (rp->offset == 0) rq->readers++; spin_unlock(&queue_lock); -- cgit v0.10.2 From 749386e906e76e3244030c35aeccfcb19c3357b8 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:37 -0400 Subject: SUNRPC: remove BUG_ON in rpc_put_sb_net Replace BUG_ON() with WARN_ON() - the condition is definitely a misuse of the API, but shouldn't cause a crash. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 80f5dd2..3128a15 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1093,7 +1093,7 @@ void rpc_put_sb_net(const struct net *net) { struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); - BUG_ON(sn->pipefs_sb == NULL); + WARN_ON(sn->pipefs_sb == NULL); mutex_unlock(&sn->pipefs_sb_lock); } EXPORT_SYMBOL_GPL(rpc_put_sb_net); -- cgit v0.10.2 From f30dfbba1682fde22f5a728f23d97a7a59a39fa0 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:33 -0400 Subject: SUNRPC: remove two BUG_ON asserts Replace two BUG_ON() calls checking the RPC_BC_PA_IN_USE flag with WARN_ON_ONCE(). Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 80aa881..890a299 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -59,7 +59,7 @@ static void xprt_free_allocation(struct rpc_rqst *req) struct xdr_buf *xbufp; dprintk("RPC: free allocations for req= %p\n", req); - BUG_ON(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); + WARN_ON_ONCE(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); xbufp = &req->rq_private_buf; free_page((unsigned long)xbufp->head[0].iov_base); xbufp = &req->rq_snd_buf; @@ -258,7 +258,7 @@ void xprt_free_bc_request(struct rpc_rqst *req) dprintk("RPC: free backchannel req=%p\n", req); smp_mb__before_clear_bit(); - BUG_ON(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); + WARN_ON_ONCE(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); smp_mb__after_clear_bit(); -- cgit v0.10.2 From 1bd58aaff44485ec9e3640af350f6ba1b33e2bec Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:38 -0400 Subject: SUNRPC: remove BUG_ON from svc_pool_map_set_cpumask Replace BUG_ON() with a WARN() and early return. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 3ee7461..664979b 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -324,7 +324,9 @@ svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx) * The caller checks for sv_nrpools > 1, which * implies that we've been initialized. */ - BUG_ON(m->count == 0); + WARN_ON_ONCE(m->count == 0); + if (m->count == 0) + return; switch (m->mode) { case SVC_POOL_PERCPU: -- cgit v0.10.2 From 1b7a1819078c68c4df4bba90f76b8113a08460de Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:39 -0400 Subject: SUNRPC: remove BUG_ONs from *_reclassify_socket* Replace multiple BUG_ON() calls with WARN_ON_ONCE() and early return when sanity checking socket ownership (lock). The bind call will fail if the socket was unsuccessfully reclassified. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 03827ce..cc3020d 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -84,7 +84,11 @@ static struct lock_class_key svc_slock_key[2]; static void svc_reclassify_socket(struct socket *sock) { struct sock *sk = sock->sk; - BUG_ON(sock_owned_by_user(sk)); + + WARN_ON_ONCE(sock_owned_by_user(sk)); + if (sock_owned_by_user(sk)) + return; + switch (sk->sk_family) { case AF_INET: sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD", diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 75853ca..46c1a879 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1746,7 +1746,6 @@ static inline void xs_reclassify_socketu(struct socket *sock) { struct sock *sk = sock->sk; - BUG_ON(sock_owned_by_user(sk)); sock_lock_init_class_and_name(sk, "slock-AF_LOCAL-RPC", &xs_slock_key[1], "sk_lock-AF_LOCAL-RPC", &xs_key[1]); } @@ -1755,7 +1754,6 @@ static inline void xs_reclassify_socket4(struct socket *sock) { struct sock *sk = sock->sk; - BUG_ON(sock_owned_by_user(sk)); sock_lock_init_class_and_name(sk, "slock-AF_INET-RPC", &xs_slock_key[0], "sk_lock-AF_INET-RPC", &xs_key[0]); } @@ -1764,13 +1762,16 @@ static inline void xs_reclassify_socket6(struct socket *sock) { struct sock *sk = sock->sk; - BUG_ON(sock_owned_by_user(sk)); sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC", &xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]); } static inline void xs_reclassify_socket(int family, struct socket *sock) { + WARN_ON_ONCE(sock_owned_by_user(sock->sk)); + if (sock_owned_by_user(sock->sk)) + return; + switch (family) { case AF_LOCAL: xs_reclassify_socketu(sock); -- cgit v0.10.2 From ff1fdb9b805fc03fb51c7b061604360af92d0c9e Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:40 -0400 Subject: SUNRPC: remove BUG_ON in svc_xprt_received Replace BUG_ON() with a WARN_ON_ONCE() and early return. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 194d865..be89bb6 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -218,7 +218,9 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, */ static void svc_xprt_received(struct svc_xprt *xprt) { - BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); + WARN_ON_ONCE(!test_bit(XPT_BUSY, &xprt->xpt_flags)); + if (!test_bit(XPT_BUSY, &xprt->xpt_flags)) + return; /* As soon as we clear busy, the xprt could be closed and * 'put', so we need a reference to call svc_xprt_enqueue with: */ -- cgit v0.10.2 From b25cd058f25ea2054351bbe501956002cd8ed4c5 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:41 -0400 Subject: SUNRPC: remove BUG_ONs checking RPCSVC_MAXPAGES Replace two bounds checking BUG_ON() calls with WARN_ON_ONCE() and resetting the requested size to RPCSVC_MAXPAGES. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 664979b..3bf5a54 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -587,7 +587,9 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node) * We assume one is at most one page */ arghi = 0; - BUG_ON(pages > RPCSVC_MAXPAGES); + WARN_ON_ONCE(pages > RPCSVC_MAXPAGES); + if (pages > RPCSVC_MAXPAGES) + pages = RPCSVC_MAXPAGES; while (pages) { struct page *p = alloc_pages_node(node, GFP_KERNEL, 0); if (!p) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index be89bb6..35fa74b 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -579,7 +579,10 @@ int svc_alloc_arg(struct svc_rqst *rqstp) /* now allocate needed pages. If we get a failure, sleep briefly */ pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE; - BUG_ON(pages >= RPCSVC_MAXPAGES); + WARN_ON_ONCE(pages >= RPCSVC_MAXPAGES); + if (pages >= RPCSVC_MAXPAGES) + /* use as many pages as possible */ + pages = RPCSVC_MAXPAGES - 1; for (i = 0; i < pages ; i++) while (rqstp->rq_pages[i] == NULL) { struct page *p = alloc_page(GFP_KERNEL); -- cgit v0.10.2 From 18e624ad0374f3b1092530f978301611f88e45b3 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:42 -0400 Subject: SUNRPC: remove BUG_ON in xdr_shrink_bufhead Replace bounds checking BUG_ON() with a WARN_ON_ONCE() and resetting the requested len to the max. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 08f50af..5605563 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -318,7 +318,10 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len) tail = buf->tail; head = buf->head; - BUG_ON (len > head->iov_len); + + WARN_ON_ONCE(len > head->iov_len); + if (len > head->iov_len) + len = head->iov_len; /* Shift the tail first */ if (tail->iov_len != 0) { -- cgit v0.10.2 From b8a13d039cbf7aec3b486fc0ae3996a5449afed2 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:43 -0400 Subject: SUNRPC: remove BUG_ON from bc_malloc Replace BUG_ON() with WARN_ON_ONCE() and NULL return - the caller will handle this like a memory allocation failure. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 46c1a879..6db26e5 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2330,9 +2330,11 @@ static void *bc_malloc(struct rpc_task *task, size_t size) struct page *page; struct rpc_buffer *buf; - BUG_ON(size > PAGE_SIZE - sizeof(struct rpc_buffer)); - page = alloc_page(GFP_KERNEL); + WARN_ON_ONCE(size > PAGE_SIZE - sizeof(struct rpc_buffer)); + if (size > PAGE_SIZE - sizeof(struct rpc_buffer)) + return NULL; + page = alloc_page(GFP_KERNEL); if (!page) return NULL; -- cgit v0.10.2 From 332e008a44d1ab6ca85b2214578f2f89af04a2fc Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:44 -0400 Subject: SUNRPC: remove BUG_ON from encode_rpcb_string Replace BUG_ON() with WARN_ON_ONCE() and truncate the encoded string if len > max. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index a70acae..411f332 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -884,7 +884,10 @@ static void encode_rpcb_string(struct xdr_stream *xdr, const char *string, u32 len; len = strlen(string); - BUG_ON(len > maxstrlen); + WARN_ON_ONCE(len > maxstrlen); + if (len > maxstrlen) + /* truncate and hope for the best */ + len = maxstrlen; p = xdr_reserve_space(xdr, 4 + len); xdr_encode_opaque(p, string, len); } -- cgit v0.10.2 From 0af39507f60ee9f98b20f24af09c1a60655417ac Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:45 -0400 Subject: SUNRPC: remove BUG_ON in svc_register Instead of calling BUG_ON(), do a WARN_ON_ONCE() and return -EINVAL. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 3bf5a54..dfa4ba6 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -950,7 +950,9 @@ int svc_register(const struct svc_serv *serv, struct net *net, unsigned int i; int error = 0; - BUG_ON(proto == 0 && port == 0); + WARN_ON_ONCE(proto == 0 && port == 0); + if (proto == 0 && port == 0) + return -EINVAL; for (progp = serv->sv_program; progp; progp = progp->pg_next) { for (i = 0; i < progp->pg_nvers; i++) { -- cgit v0.10.2 From f50ad42837eb874c1a0cd7cca2001364b06f7ac4 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:46 -0400 Subject: SUNRPC: remove BUG_ON from __rpc_sleep_on_priority Replace BUG_ON() with WARN_ON_ONCE(). Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index f494b35..e6db496 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -334,7 +334,7 @@ static void __rpc_sleep_on_priority(struct rpc_wait_queue *q, __rpc_add_wait_queue(q, task, queue_priority); - BUG_ON(task->tk_callback != NULL); + WARN_ON_ONCE(task->tk_callback != NULL); task->tk_callback = action; __rpc_add_timer(q, task); } -- cgit v0.10.2 From 2bd4eef87bc169f1baf5d1518ba939897cc32471 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:47 -0400 Subject: SUNRPC: remove BUG_ONs checking RPC_IS_QUEUED Replace two BUG_ON() calls with WARN_ON_ONCE() and early returns. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index e6db496..6904917 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -133,7 +133,9 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task, unsigned char queue_priority) { - BUG_ON (RPC_IS_QUEUED(task)); + WARN_ON_ONCE(RPC_IS_QUEUED(task)); + if (RPC_IS_QUEUED(task)) + return; if (RPC_IS_PRIORITY(queue)) __rpc_add_wait_queue_priority(queue, task, queue_priority); @@ -707,7 +709,9 @@ static void __rpc_execute(struct rpc_task *task) dprintk("RPC: %5u __rpc_execute flags=0x%x\n", task->tk_pid, task->tk_flags); - BUG_ON(RPC_IS_QUEUED(task)); + WARN_ON_ONCE(RPC_IS_QUEUED(task)); + if (RPC_IS_QUEUED(task)) + return; for (;;) { void (*do_action)(struct rpc_task *); -- cgit v0.10.2 From 010472980724ed7bbabf818b4232bf3b182b94c5 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:48 -0400 Subject: SUNRPC: remove BUG_ON in svc_delete_xprt Replace BUG_ON() with WARN_ON_ONCE(). Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 35fa74b..b8e47fa 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -931,7 +931,7 @@ static void svc_delete_xprt(struct svc_xprt *xprt) spin_lock_bh(&serv->sv_lock); if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags)) list_del_init(&xprt->xpt_list); - BUG_ON(!list_empty(&xprt->xpt_ready)); + WARN_ON_ONCE(!list_empty(&xprt->xpt_ready)); if (test_bit(XPT_TEMP, &xprt->xpt_flags)) serv->sv_tmpcnt--; spin_unlock_bh(&serv->sv_lock); -- cgit v0.10.2 From 0a0c2a57bc9a47ae876077fdc4678eca33c26ae4 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Tue, 23 Oct 2012 10:43:49 -0400 Subject: SUNRPC: remove BUG_ON in rpc_release_task Replace BUG_ON() with WARN_ON_ONCE(). Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 6904917..8529026 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -995,7 +995,7 @@ static void rpc_release_task(struct rpc_task *task) { dprintk("RPC: %5u release task\n", task->tk_pid); - BUG_ON (RPC_IS_QUEUED(task)); + WARN_ON_ONCE(RPC_IS_QUEUED(task)); rpc_release_resources_task(task); -- cgit v0.10.2 From 50d2bdb19734f9e9f21e63881a9b6c8db4cc0eb7 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Thu, 1 Nov 2012 16:04:40 -0400 Subject: SUNRPC: remove BUG_ON from rpc_call_sync Use WARN_ON_ONCE instead of calling BUG_ON and return -EINVAL when RPC_TASK_ASYNC flag is passed to rpc_call_sync. Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index a9dd1e8..50bc9db 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -842,7 +842,12 @@ int rpc_call_sync(struct rpc_clnt *clnt, const struct rpc_message *msg, int flag }; int status; - BUG_ON(flags & RPC_TASK_ASYNC); + WARN_ON_ONCE(flags & RPC_TASK_ASYNC); + if (flags & RPC_TASK_ASYNC) { + rpc_release_calldata(task_setup_data.callback_ops, + task_setup_data.callback_data); + return -EINVAL; + } task = rpc_run_task(&task_setup_data); if (IS_ERR(task)) -- cgit v0.10.2 From f994c43d19a9116727d4c228d3f13db595bff562 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 1 Nov 2012 12:14:14 -0400 Subject: SUNRPC: Clean up rpc_bind_new_program We can and should use the rpc_create_args and __rpc_clone_client() to change the program and version number on the resulting rpc_client. Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 50bc9db..c69e199 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -703,21 +703,19 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, const struct rpc_program *program, u32 vers) { + struct rpc_create_args args = { + .program = program, + .prognumber = program->number, + .version = vers, + .authflavor = old->cl_auth->au_flavor, + .client_name = old->cl_principal, + }; struct rpc_clnt *clnt; - const struct rpc_version *version; int err; - BUG_ON(vers >= program->nrvers || !program->version[vers]); - version = program->version[vers]; - clnt = rpc_clone_client(old); + clnt = __rpc_clone_client(&args, old); if (IS_ERR(clnt)) goto out; - clnt->cl_procinfo = version->procs; - clnt->cl_maxproc = version->nrprocs; - clnt->cl_protname = program->name; - clnt->cl_prog = program->number; - clnt->cl_vers = version->number; - clnt->cl_stats = program->stats; err = rpc_ping(clnt); if (err != 0) { rpc_shutdown_client(clnt); -- cgit v0.10.2 From 22cddde104d715600a4c218bf9224923208afe90 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 5 Nov 2012 11:07:23 -0800 Subject: ceph: Fix i_size update race ceph_aio_write() has an optimization that marks cap EPH_CAP_FILE_WR dirty before data is copied to page cache and inode size is updated. If ceph_check_caps() flushes the dirty cap before the inode size is updated, MDS can miss the new inode size. The fix is move ceph_{get,put}_cap_refs() into ceph_write_{begin,end}() and call __ceph_mark_dirty_caps() after inode size is updated. Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 22b6e45..21a0718 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1078,23 +1078,51 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, struct page **pagep, void **fsdata) { struct inode *inode = file->f_dentry->d_inode; + struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_file_info *fi = file->private_data; struct page *page; pgoff_t index = pos >> PAGE_CACHE_SHIFT; - int r; + int r, want, got = 0; + + if (fi->fmode & CEPH_FILE_MODE_LAZY) + want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO; + else + want = CEPH_CAP_FILE_BUFFER; + + dout("write_begin %p %llx.%llx %llu~%u getting caps. i_size %llu\n", + inode, ceph_vinop(inode), pos, len, inode->i_size); + r = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, pos+len); + if (r < 0) + return r; + dout("write_begin %p %llx.%llx %llu~%u got cap refs on %s\n", + inode, ceph_vinop(inode), pos, len, ceph_cap_string(got)); + if (!(got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO))) { + ceph_put_cap_refs(ci, got); + return -EAGAIN; + } do { /* get a page */ page = grab_cache_page_write_begin(mapping, index, 0); - if (!page) - return -ENOMEM; - *pagep = page; + if (!page) { + r = -ENOMEM; + break; + } dout("write_begin file %p inode %p page %p %d~%d\n", file, inode, page, (int)pos, (int)len); r = ceph_update_writeable_page(file, pos, len, page); + if (r) + page_cache_release(page); } while (r == -EAGAIN); + if (r) { + ceph_put_cap_refs(ci, got); + } else { + *pagep = page; + *(int *)fsdata = got; + } return r; } @@ -1108,10 +1136,12 @@ static int ceph_write_end(struct file *file, struct address_space *mapping, struct page *page, void *fsdata) { struct inode *inode = file->f_dentry->d_inode; + struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_fs_client *fsc = ceph_inode_to_client(inode); struct ceph_mds_client *mdsc = fsc->mdsc; unsigned from = pos & (PAGE_CACHE_SIZE - 1); int check_cap = 0; + int got = (unsigned long)fsdata; dout("write_end file %p inode %p page %p %d~%d (%d)\n", file, inode, page, (int)pos, (int)copied, (int)len); @@ -1134,6 +1164,19 @@ static int ceph_write_end(struct file *file, struct address_space *mapping, up_read(&mdsc->snap_rwsem); page_cache_release(page); + if (copied > 0) { + int dirty; + spin_lock(&ci->i_ceph_lock); + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); + spin_unlock(&ci->i_ceph_lock); + if (dirty) + __mark_inode_dirty(inode, dirty); + } + + dout("write_end %p %llx.%llx %llu~%u dropping cap refs on %s\n", + inode, ceph_vinop(inode), pos, len, ceph_cap_string(got)); + ceph_put_cap_refs(ci, got); + if (check_cap) ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY, NULL); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 5840d2a..d415096 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -712,63 +712,53 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov, struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->client->osdc; loff_t endoff = pos + iov->iov_len; - int want, got = 0; - int ret, err; + int got = 0; + int ret, err, written; if (ceph_snap(inode) != CEPH_NOSNAP) return -EROFS; retry_snap: + written = 0; if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL)) return -ENOSPC; __ceph_do_pending_vmtruncate(inode); - dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n", - inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, - inode->i_size); - if (fi->fmode & CEPH_FILE_MODE_LAZY) - want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO; - else - want = CEPH_CAP_FILE_BUFFER; - ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, endoff); - if (ret < 0) - goto out_put; - - dout("aio_write %p %llx.%llx %llu~%u got cap refs on %s\n", - inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, - ceph_cap_string(got)); - - if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || - (iocb->ki_filp->f_flags & O_DIRECT) || - (inode->i_sb->s_flags & MS_SYNCHRONOUS) || - (fi->flags & CEPH_F_SYNC)) { - ret = ceph_sync_write(file, iov->iov_base, iov->iov_len, - &iocb->ki_pos); - } else { - /* - * buffered write; drop Fw early to avoid slow - * revocation if we get stuck on balance_dirty_pages - */ - int dirty; - - spin_lock(&ci->i_ceph_lock); - dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); - spin_unlock(&ci->i_ceph_lock); - ceph_put_cap_refs(ci, got); + /* + * try to do a buffered write. if we don't have sufficient + * caps, we'll get -EAGAIN from generic_file_aio_write, or a + * short write if we only get caps for some pages. + */ + if (!(iocb->ki_filp->f_flags & O_DIRECT) && + !(inode->i_sb->s_flags & MS_SYNCHRONOUS) && + !(fi->flags & CEPH_F_SYNC)) { ret = generic_file_aio_write(iocb, iov, nr_segs, pos); + if (ret >= 0) + written = ret; + if ((ret >= 0 || ret == -EIOCBQUEUED) && ((file->f_flags & O_SYNC) || IS_SYNC(file->f_mapping->host) || ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_NEARFULL))) { - err = vfs_fsync_range(file, pos, pos + ret - 1, 1); + err = vfs_fsync_range(file, pos, pos + written - 1, 1); if (err < 0) ret = err; } + if ((ret < 0 && ret != -EAGAIN) || pos + written >= endoff) + goto out; + } - if (dirty) - __mark_inode_dirty(inode, dirty); + dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n", + inode, ceph_vinop(inode), pos + written, + (unsigned)iov->iov_len - written, inode->i_size); + ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, 0, &got, endoff); + if (ret < 0) goto out; - } + dout("aio_write %p %llx.%llx %llu~%u got cap refs on %s\n", + inode, ceph_vinop(inode), pos + written, + (unsigned)iov->iov_len - written, ceph_cap_string(got)); + ret = ceph_sync_write(file, iov->iov_base + written, + iov->iov_len - written, &iocb->ki_pos); if (ret >= 0) { int dirty; spin_lock(&ci->i_ceph_lock); @@ -777,13 +767,10 @@ retry_snap: if (dirty) __mark_inode_dirty(inode, dirty); } - -out_put: dout("aio_write %p %llx.%llx %llu~%u dropping cap refs on %s\n", - inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, - ceph_cap_string(got)); + inode, ceph_vinop(inode), pos + written, + (unsigned)iov->iov_len - written, ceph_cap_string(got)); ceph_put_cap_refs(ci, got); - out: if (ret == -EOLDSNAPC) { dout("aio_write %p %llx.%llx %llu~%u got EOLDSNAPC, retrying\n", -- cgit v0.10.2 From 216b6cbdcbd86b1db0754d58886b466ae31f5a63 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 29 Aug 2012 10:10:10 -0400 Subject: exportfs: add FILEID_INVALID to indicate invalid fid_type This commit adds FILEID_INVALID = 0xff in fid_type to indicate invalid fid_type It avoids using magic number 255 Signed-off-by: Namjae Jeon Signed-off-by: Vivek Trivedi Signed-off-by: J. Bruce Fields diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 29ab099..f1f1c59 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -322,10 +322,10 @@ static int export_encode_fh(struct inode *inode, struct fid *fid, if (parent && (len < 4)) { *max_len = 4; - return 255; + return FILEID_INVALID; } else if (len < 2) { *max_len = 2; - return 255; + return FILEID_INVALID; } len = 2; diff --git a/fs/fhandle.c b/fs/fhandle.c index f775bfd..26f12b9 100644 --- a/fs/fhandle.c +++ b/fs/fhandle.c @@ -52,7 +52,7 @@ static long do_sys_name_to_handle(struct path *path, handle_bytes = handle_dwords * sizeof(u32); handle->handle_bytes = handle_bytes; if ((handle->handle_bytes > f_handle.handle_bytes) || - (retval == 255) || (retval == -ENOSPC)) { + (retval == FILEID_INVALID) || (retval == -ENOSPC)) { /* As per old exportfs_encode_fh documentation * we could return ENOSPC to indicate overflow * But file system returned 255 always. So handle diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 032af38..814afaa 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -572,7 +572,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, if (inode) _fh_update(fhp, exp, dentry); - if (fhp->fh_handle.fh_fileid_type == 255) { + if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) { fh_put(fhp); return nfserr_opnotsupp; } @@ -603,7 +603,7 @@ fh_update(struct svc_fh *fhp) goto out; _fh_update(fhp, fhp->fh_export, dentry); - if (fhp->fh_handle.fh_fileid_type == 255) + if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) return nfserr_opnotsupp; } out: diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h index 12291a7..0e14525 100644 --- a/include/linux/exportfs.h +++ b/include/linux/exportfs.h @@ -83,6 +83,11 @@ enum fid_type { * 64 bit parent inode number. */ FILEID_NILFS_WITH_PARENT = 0x62, + + /* + * Filesystems must not use 0xff file ID. + */ + FILEID_INVALID = 0xff, }; struct fid { -- cgit v0.10.2 From 01f6c8fd949f3a25a2617e6e1579a5c974b1cabf Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 18 Oct 2012 22:44:21 +0800 Subject: nfsd4: remove unused variable in nfsd4_delegreturn() The variable inode is initialized but never used otherwise, so remove the unused variable. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d0237f8..620ff81 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3807,12 +3807,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfs4_delegation *dp; stateid_t *stateid = &dr->dr_stateid; struct nfs4_stid *s; - struct inode *inode; __be32 status; if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) return status; - inode = cstate->current_fh.fh_dentry->d_inode; nfs4_lock_state(); status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion); -- cgit v0.10.2 From 3c40794b2dd0f355ef4e6bf8d85af5dcd7da7ece Mon Sep 17 00:00:00 2001 From: Yanchuan Nian Date: Wed, 24 Oct 2012 14:44:19 +0800 Subject: nfs: fix wrong object type in lockowner_slab The object type in the cache of lockowner_slab is wrong, and it is better to fix it. Cc: stable@vger.kernel.org Signed-off-by: Yanchuan Nian Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 620ff81..fba2996 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2340,7 +2340,7 @@ nfsd4_init_slabs(void) if (openowner_slab == NULL) goto out_nomem; lockowner_slab = kmem_cache_create("nfsd4_lockowners", - sizeof(struct nfs4_openowner), 0, 0, NULL); + sizeof(struct nfs4_lockowner), 0, 0, NULL); if (lockowner_slab == NULL) goto out_nomem; file_slab = kmem_cache_create("nfsd4_files", -- cgit v0.10.2 From ae7095a7c44b4cda963e3d4059788ff60e119684 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 1 Oct 2012 17:50:56 -0400 Subject: nfsd4: helper function for getting mounted_on ino Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index fd548d1..af65fda 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2014,6 +2014,22 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) return 0; } + +static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) +{ + struct path path = exp->ex_path; + int err; + + path_get(&path); + while (follow_up(&path)) { + if (path.dentry != path.mnt->mnt_root) + break; + } + err = vfs_getattr(path.mnt, path.dentry, stat); + path_put(&path); + return err; +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -2430,18 +2446,8 @@ out_acl: * and this is the root of a cross-mounted filesystem. */ if (ignore_crossmnt == 0 && - dentry == exp->ex_path.mnt->mnt_root) { - struct path path = exp->ex_path; - path_get(&path); - while (follow_up(&path)) { - if (path.dentry != path.mnt->mnt_root) - break; - } - err = vfs_getattr(path.mnt, path.dentry, &stat); - path_put(&path); - if (err) - goto out_nfserr; - } + dentry == exp->ex_path.mnt->mnt_root) + get_parent_attributes(exp, &stat); WRITE64(stat.ino); } if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { -- cgit v0.10.2 From 7c1f8b65af4bda8eb53cdfe4965cbcfd7fb20c7d Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 1 Nov 2012 16:54:01 -0400 Subject: nfsd4: remove unused init_session return Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index fba2996..bc8507c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -945,7 +945,7 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) return new; } -static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) +void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) { int idx; @@ -978,7 +978,6 @@ static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_s rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); } - return new; } /* caller must hold client_lock */ -- cgit v0.10.2 From 7032a3dd923f434132643321ad5faad128611f9e Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 9 Oct 2012 18:33:38 -0400 Subject: svcrpc: demote some printks to a dprintk In general I'd rather random bad behavior on the network won't trigger a printk. Signed-off-by: J. Bruce Fields diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 3ee7461..be301e1 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1035,7 +1035,7 @@ static void svc_unregister(const struct svc_serv *serv, struct net *net) } /* - * Printk the given error with the address of the client that caused it. + * dprintk the given error with the address of the client that caused it. */ static __printf(2, 3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) @@ -1049,8 +1049,7 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) vaf.fmt = fmt; vaf.va = &args; - net_warn_ratelimited("svc: %s: %pV", - svc_print_addr(rqstp, buf, sizeof(buf)), &vaf); + dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf); va_end(args); } -- cgit v0.10.2 From 7fa10cd12df3ec0873a5db0d8dc8e978423b87dc Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 16 Oct 2012 12:39:33 -0400 Subject: nfsd4: don't BUG in delegation break callback These conditions would indeed indicate bugs in the code, but if we want to hear about them we're likely better off warning and returning than immediately dying while holding file_lock_lock. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index bc8507c..db7258c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2554,9 +2554,14 @@ static void nfsd_break_deleg_cb(struct file_lock *fl) struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; struct nfs4_delegation *dp; - BUG_ON(!fp); - /* We assume break_lease is only called once per lease: */ - BUG_ON(fp->fi_had_conflict); + if (!fp) { + WARN(1, "(%p)->fl_owner NULL\n", fl); + return; + } + if (fp->fi_had_conflict) { + WARN(1, "duplicate break on %p\n", fp); + return; + } /* * We don't want the locks code to timeout the lease for us; * we'll remove it ourself if a delegation isn't returned -- cgit v0.10.2 From fae5096ad217db2e3368e980c1d86223f786856b Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 26 Oct 2012 16:04:08 -0400 Subject: nfsd: assume writeable exportabled filesystems have f_sync I don't really see how you could claim to support nfsd and not support fsync somehow. And in practice a quick look through the exportable filesystems suggests the only ones without an ->fsync are read-only (efs, isofs, squashfs) or in-memory (shmem). Also, performing a write and then returning an error if the sync fails (as we would do here in the wgather case) seems unhelpful to clients. Also remove an incorrect comment. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index c120b48..ed3eb59 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1020,21 +1020,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, inode = dentry->d_inode; exp = fhp->fh_export; - /* - * Request sync writes if - * - the sync export option has been set, or - * - the client requested O_SYNC behavior (NFSv3 feature). - * - The file system doesn't support fsync(). - * When NFSv2 gathered writes have been configured for this volume, - * flushing the data to disk is handled separately below. - */ use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp); - if (!file->f_op->fsync) {/* COMMIT3 cannot work */ - stable = 2; - *stablep = 2; /* FILE_SYNC */ - } - if (!EX_ISSYNC(exp)) stable = 0; if (stable && !use_wgather) { -- cgit v0.10.2 From face15025ffdf664de95e86ae831544154d26c9c Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 26 Oct 2012 16:12:31 -0400 Subject: nfsd: use vfs_fsync_range(), not O_SYNC, for stable writes NFSv4 shares the same struct file across multiple writes. (And we'd like NFSv2 and NFSv3 to do that as well some day.) So setting O_SYNC on the struct file as a way to request a synchronous write doesn't work. Instead, do a vfs_fsync_range() in that case. Reported-by: Peter Staubach Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index ed3eb59..b584205 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1024,11 +1024,6 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (!EX_ISSYNC(exp)) stable = 0; - if (stable && !use_wgather) { - spin_lock(&file->f_lock); - file->f_flags |= O_SYNC; - spin_unlock(&file->f_lock); - } /* Write the data. */ oldfs = get_fs(); set_fs(KERNEL_DS); @@ -1044,8 +1039,12 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (inode->i_mode & (S_ISUID | S_ISGID)) kill_suid(dentry); - if (stable && use_wgather) - host_err = wait_for_concurrent_writes(file); + if (stable) { + if (use_wgather) + host_err = wait_for_concurrent_writes(file); + else + host_err = vfs_fsync_range(file, offset, offset+*cnt, 0); + } out_nfserr: dprintk("nfsd: write complete host_err=%d\n", host_err); -- cgit v0.10.2 From acb2887e04c2140c2c63c8bf94e0b446efcc7001 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 27 Mar 2012 14:50:26 -0400 Subject: nfsd4: clean up callback security parsing Move the callback parsing into a separate function. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index af65fda..511f980 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -422,6 +422,67 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access DECODE_TAIL; } +static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) +{ + DECODE_HEAD; + u32 dummy; + char *machine_name; + int i; + int nr_secflavs; + + /* callback_sec_params4 */ + READ_BUF(4); + READ32(nr_secflavs); + for (i = 0; i < nr_secflavs; ++i) { + READ_BUF(4); + READ32(dummy); + switch (dummy) { + case RPC_AUTH_NULL: + /* Nothing to read */ + break; + case RPC_AUTH_UNIX: + READ_BUF(8); + /* stamp */ + READ32(dummy); + + /* machine name */ + READ32(dummy); + READ_BUF(dummy); + SAVEMEM(machine_name, dummy); + + /* uid, gid */ + READ_BUF(8); + READ32(cbs->uid); + READ32(cbs->gid); + + /* more gids */ + READ_BUF(4); + READ32(dummy); + READ_BUF(dummy * 4); + break; + case RPC_AUTH_GSS: + dprintk("RPC_AUTH_GSS callback secflavor " + "not supported!\n"); + READ_BUF(8); + /* gcbp_service */ + READ32(dummy); + /* gcbp_handle_from_server */ + READ32(dummy); + READ_BUF(dummy); + p += XDR_QUADLEN(dummy); + /* gcbp_handle_from_client */ + READ_BUF(4); + READ32(dummy); + READ_BUF(dummy); + break; + default: + dprintk("Illegal callback secflavor\n"); + return nfserr_inval; + } + } + DECODE_TAIL; +} + static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) { DECODE_HEAD; @@ -1237,11 +1298,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, struct nfsd4_create_session *sess) { DECODE_HEAD; - u32 dummy; - char *machine_name; - int i; - int nr_secflavs; READ_BUF(16); COPYMEM(&sess->clientid, 8); @@ -1282,58 +1339,9 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, goto xdr_error; } - READ_BUF(8); + READ_BUF(4); READ32(sess->callback_prog); - - /* callback_sec_params4 */ - READ32(nr_secflavs); - for (i = 0; i < nr_secflavs; ++i) { - READ_BUF(4); - READ32(dummy); - switch (dummy) { - case RPC_AUTH_NULL: - /* Nothing to read */ - break; - case RPC_AUTH_UNIX: - READ_BUF(8); - /* stamp */ - READ32(dummy); - - /* machine name */ - READ32(dummy); - READ_BUF(dummy); - SAVEMEM(machine_name, dummy); - - /* uid, gid */ - READ_BUF(8); - READ32(sess->uid); - READ32(sess->gid); - - /* more gids */ - READ_BUF(4); - READ32(dummy); - READ_BUF(dummy * 4); - break; - case RPC_AUTH_GSS: - dprintk("RPC_AUTH_GSS callback secflavor " - "not supported!\n"); - READ_BUF(8); - /* gcbp_service */ - READ32(dummy); - /* gcbp_handle_from_server */ - READ32(dummy); - READ_BUF(dummy); - p += XDR_QUADLEN(dummy); - /* gcbp_handle_from_client */ - READ_BUF(4); - READ32(dummy); - READ_BUF(dummy); - break; - default: - dprintk("Illegal callback secflavor\n"); - return nfserr_inval; - } - } + nfsd4_decode_cb_sec(argp, &sess->cb_sec); DECODE_TAIL; } diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index e036894..df33e78 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -150,6 +150,11 @@ struct nfsd4_channel_attrs { u32 rdma_attrs; }; +struct nfsd4_cb_sec { + u32 uid; + u32 gid; +}; + struct nfsd4_create_session { clientid_t clientid; struct nfs4_sessionid sessionid; @@ -158,8 +163,7 @@ struct nfsd4_create_session { struct nfsd4_channel_attrs fore_channel; struct nfsd4_channel_attrs back_channel; u32 callback_prog; - u32 uid; - u32 gid; + struct nfsd4_cb_sec cb_sec; }; struct nfsd4_bind_conn_to_session { @@ -192,6 +196,7 @@ struct nfsd4_session { struct nfs4_sessionid se_sessionid; struct nfsd4_channel_attrs se_fchannel; struct nfsd4_channel_attrs se_bchannel; + struct nfsd4_cb_sec se_cb_sec; struct list_head se_conns; u32 se_cb_prog; u32 se_cb_seq_nr; -- cgit v0.10.2 From c6bb3ca27d78b902baa143b931a8d9ef53298afa Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 1 Nov 2012 16:31:02 -0400 Subject: nfsd4: use callback security parameters in create_session We're currently ignoring the callback security parameters specified in create_session, and just assuming the client wants auth_sys, because that's all the current linux client happens to care about. But this could cause us callbacks to fail to a client that wanted something different. For now, all we're doing is no longer ignoring the uid and gid passed in the auth_sys case. Further patches will add support for auth_null and gss (and possibly use more of the auth_sys information; the spec wants us to use exactly the credential we're passed, though it's hard to imagine why a client would care). Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index bdf29c9..b32639e 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -630,6 +630,31 @@ static int max_cb_time(void) return max(nfsd4_lease/10, (time_t)1) * HZ; } +static struct rpc_cred *callback_cred; + +int set_callback_cred(void) +{ + if (callback_cred) + return 0; + callback_cred = rpc_lookup_machine_cred("nfs"); + if (!callback_cred) + return -ENOMEM; + return 0; +} + +struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses) +{ + if (clp->cl_minorversion == 0) { + return get_rpccred(callback_cred); + } else { + struct rpc_auth *auth = client->cl_auth; + struct auth_cred acred = {}; + + acred.uid = ses->se_cb_sec.uid; + acred.gid = ses->se_cb_sec.gid; + return auth->au_ops->lookup_cred(client->cl_auth, &acred, 0); + } +} static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) { @@ -648,6 +673,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), }; struct rpc_clnt *client; + struct rpc_cred *cred; if (clp->cl_minorversion == 0) { if (!clp->cl_cred.cr_principal && @@ -675,7 +701,13 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c PTR_ERR(client)); return PTR_ERR(client); } + cred = get_backchannel_cred(clp, client, ses); + if (IS_ERR(cred)) { + rpc_shutdown_client(client); + return PTR_ERR(cred); + } clp->cl_cb_client = client; + clp->cl_cb_cred = cred; return 0; } @@ -714,18 +746,6 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = { .rpc_call_done = nfsd4_cb_probe_done, }; -static struct rpc_cred *callback_cred; - -int set_callback_cred(void) -{ - if (callback_cred) - return 0; - callback_cred = rpc_lookup_machine_cred("nfs"); - if (!callback_cred) - return -ENOMEM; - return 0; -} - static struct workqueue_struct *callback_wq; static void run_nfsd4_cb(struct nfsd4_callback *cb) @@ -743,7 +763,6 @@ static void do_probe_callback(struct nfs4_client *clp) cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL]; cb->cb_msg.rpc_argp = NULL; cb->cb_msg.rpc_resp = NULL; - cb->cb_msg.rpc_cred = callback_cred; cb->cb_ops = &nfsd4_cb_probe_ops; @@ -962,6 +981,8 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) if (clp->cl_cb_client) { rpc_shutdown_client(clp->cl_cb_client); clp->cl_cb_client = NULL; + put_rpccred(clp->cl_cb_cred); + clp->cl_cb_cred = NULL; } if (clp->cl_cb_conn.cb_xprt) { svc_xprt_put(clp->cl_cb_conn.cb_xprt); @@ -1010,6 +1031,7 @@ void nfsd4_do_callback_rpc(struct work_struct *w) nfsd4_release_cb(cb); return; } + cb->cb_msg.rpc_cred = clp->cl_cb_cred; rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, cb->cb_ops, cb); } @@ -1025,7 +1047,6 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp) cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; cb->cb_msg.rpc_argp = cb; cb->cb_msg.rpc_resp = cb; - cb->cb_msg.rpc_cred = callback_cred; cb->cb_ops = &nfsd4_cb_recall_ops; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index db7258c..dbbbd2f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -957,6 +957,7 @@ void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4 new->se_cb_seq_nr = 1; new->se_flags = cses->flags; new->se_cb_prog = cses->callback_prog; + new->se_cb_sec = cses->cb_sec; kref_init(&new->se_ref); idx = hash_sessionid(&new->se_sessionid); spin_lock(&client_lock); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index df33e78..bff856c 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -250,6 +250,7 @@ struct nfs4_client { #define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \ 1 << NFSD4_CLIENT_CB_KILL) unsigned long cl_flags; + struct rpc_cred *cl_cb_cred; struct rpc_clnt *cl_cb_client; u32 cl_cb_ident; #define NFSD4_CB_UP 0 -- cgit v0.10.2 From cb73a9f4649bf63c0397e565a15abf8a91ecf56f Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 1 Nov 2012 18:09:48 -0400 Subject: nfsd4: implement backchannel_ctl operation This operation is mandatory for servers to implement. Signed-off-by: J. Bruce Fields diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt index 092fad9..f5ddff2 100644 --- a/Documentation/filesystems/nfs/nfs41-server.txt +++ b/Documentation/filesystems/nfs/nfs41-server.txt @@ -39,11 +39,6 @@ interoperability problems with future clients. Known issues: from a linux client are possible, but we aren't really conformant with the spec (for example, we don't use kerberos on the backchannel correctly). - - Incomplete backchannel support: incomplete backchannel gss - support and no support for BACKCHANNEL_CTL mean that - callbacks (hence delegations and layouts) may not be - available and clients confused by the incomplete - implementation may fail. - We do not support SSV, which provides security for shared client-server state (thus preventing unauthorized tampering with locks and opens, for example). It is mandatory for @@ -89,7 +84,7 @@ Operations | | MNI | or OPT) | | +----------------------+------------+--------------+----------------+ | ACCESS | REQ | | Section 18.1 | -NS | BACKCHANNEL_CTL | REQ | | Section 18.33 | +I | BACKCHANNEL_CTL | REQ | | Section 18.33 | I | BIND_CONN_TO_SESSION | REQ | | Section 18.34 | | CLOSE | REQ | | Section 18.2 | | COMMIT | REQ | | Section 18.3 | diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 6c9a4b2..f955176 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1666,6 +1666,12 @@ static struct nfsd4_operation nfsd4_ops[] = { .op_name = "OP_EXCHANGE_ID", .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize, }, + [OP_BACKCHANNEL_CTL] = { + .op_func = (nfsd4op_func)nfsd4_backchannel_ctl, + .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, + .op_name = "OP_BACKCHANNEL_CTL", + .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, + }, [OP_BIND_CONN_TO_SESSION] = { .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index dbbbd2f..4023e77 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1865,6 +1865,20 @@ static __be32 nfsd4_map_bcts_dir(u32 *dir) return nfserr_inval; } +__be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) +{ + struct nfsd4_session *session = cstate->session; + + spin_lock(&client_lock); + session->se_cb_prog = bc->bc_cb_program; + session->se_cb_sec = bc->bc_cb_sec; + spin_unlock(&client_lock); + + nfsd4_probe_callback(session->se_client); + + return nfs_ok; +} + __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_bind_conn_to_session *bcts) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 511f980..d7e7c11 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -483,6 +483,17 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_ DECODE_TAIL; } +static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) +{ + DECODE_HEAD; + + READ_BUF(4); + READ32(bc->bc_cb_program); + nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); + + DECODE_TAIL; +} + static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) { DECODE_HEAD; @@ -1536,7 +1547,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, /* new operations for NFSv4.1 */ - [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, + [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index bff856c..758bc9c 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -166,6 +166,11 @@ struct nfsd4_create_session { struct nfsd4_cb_sec cb_sec; }; +struct nfsd4_backchannel_ctl { + u32 bc_cb_program; + struct nfsd4_cb_sec bc_cb_sec; +}; + struct nfsd4_bind_conn_to_session { struct nfs4_sessionid sessionid; u32 dir; diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index acd127d..71c5c47 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -462,6 +462,7 @@ struct nfsd4_op { /* NFSv4.1 */ struct nfsd4_exchange_id exchange_id; + struct nfsd4_backchannel_ctl backchannel_ctl; struct nfsd4_bind_conn_to_session bind_conn_to_session; struct nfsd4_create_session create_session; struct nfsd4_destroy_session destroy_session; @@ -566,6 +567,7 @@ extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, struct nfsd4_sequence *seq); extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *, struct nfsd4_exchange_id *); +extern __be32 nfsd4_backchannel_ctl(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_backchannel_ctl *); extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *); extern __be32 nfsd4_create_session(struct svc_rqst *, struct nfsd4_compound_state *, -- cgit v0.10.2 From 57725155dc1b8c78b7a96886d5cdc69dc89e9c54 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 5 Nov 2012 15:10:26 -0500 Subject: nfsd4: common helper to initialize callback work I've found it confusing having the only references to nfsd4_do_callback_rpc() in a different file. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index b32639e..a1aa18d 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -1016,7 +1016,7 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) run_nfsd4_cb(cb); } -void nfsd4_do_callback_rpc(struct work_struct *w) +static void nfsd4_do_callback_rpc(struct work_struct *w) { struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work); struct nfs4_client *clp = cb->cb_clp; @@ -1036,6 +1036,11 @@ void nfsd4_do_callback_rpc(struct work_struct *w) cb->cb_ops, cb); } +void nfsd4_init_callback(struct nfsd4_callback *cb) +{ + INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc); +} + void nfsd4_cb_recall(struct nfs4_delegation *dp) { struct nfsd4_callback *cb = &dp->dl_recall; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 4023e77..13f3471 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -340,7 +340,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); dp->dl_time = 0; atomic_set(&dp->dl_count, 1); - INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); + nfsd4_init_callback(&dp->dl_recall); return dp; } @@ -1313,7 +1313,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, INIT_LIST_HEAD(&clp->cl_lru); INIT_LIST_HEAD(&clp->cl_callbacks); spin_lock_init(&clp->cl_lock); - INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); + nfsd4_init_callback(&clp->cl_cb_null); clp->cl_time = get_seconds(); clear_bit(0, &clp->cl_cb_slot_busy); rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 758bc9c..0fd342a 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -470,10 +470,10 @@ extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions); extern void nfs4_free_openowner(struct nfs4_openowner *); extern void nfs4_free_lockowner(struct nfs4_lockowner *); extern int set_callback_cred(void); +extern void nfsd4_init_callback(struct nfsd4_callback *); extern void nfsd4_probe_callback(struct nfs4_client *clp); extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); -extern void nfsd4_do_callback_rpc(struct work_struct *); extern void nfsd4_cb_recall(struct nfs4_delegation *dp); extern int nfsd4_create_callback_queue(void); extern void nfsd4_destroy_callback_queue(void); -- cgit v0.10.2 From 12fc3e92d4b18b4e99af624586e1696479ff36ce Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 5 Nov 2012 16:01:48 -0500 Subject: nfsd4: backchannel should use client-provided security flavor For now this only adds support for AUTH_NULL. (Previously we assumed AUTH_UNIX.) We'll also need AUTH_GSS, which is trickier. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index a1aa18d..7bb187a 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -692,7 +692,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c args.bc_xprt = conn->cb_xprt; args.prognumber = clp->cl_cb_session->se_cb_prog; args.protocol = XPRT_TRANSPORT_BC_TCP; - args.authflavor = RPC_AUTH_UNIX; + args.authflavor = ses->se_cb_sec.flavor; } /* Create RPC client */ client = rpc_create(&args); @@ -709,7 +709,6 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c clp->cl_cb_client = client; clp->cl_cb_cred = cred; return 0; - } static void warn_no_callback_path(struct nfs4_client *clp, int reason) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index d7e7c11..406d0c4 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -425,7 +425,7 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) { DECODE_HEAD; - u32 dummy; + u32 dummy, uid, gid; char *machine_name; int i; int nr_secflavs; @@ -433,12 +433,15 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_ /* callback_sec_params4 */ READ_BUF(4); READ32(nr_secflavs); + cbs->flavor = (u32)(-1); for (i = 0; i < nr_secflavs; ++i) { READ_BUF(4); READ32(dummy); switch (dummy) { case RPC_AUTH_NULL: /* Nothing to read */ + if (cbs->flavor == (u32)(-1)) + cbs->flavor = RPC_AUTH_NULL; break; case RPC_AUTH_UNIX: READ_BUF(8); @@ -452,13 +455,18 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_ /* uid, gid */ READ_BUF(8); - READ32(cbs->uid); - READ32(cbs->gid); + READ32(uid); + READ32(gid); /* more gids */ READ_BUF(4); READ32(dummy); READ_BUF(dummy * 4); + if (cbs->flavor == (u32)(-1)) { + cbs->uid = uid; + cbs->gid = gid; + cbs->flavor = RPC_AUTH_UNIX; + } break; case RPC_AUTH_GSS: dprintk("RPC_AUTH_GSS callback secflavor " diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 0fd342a..0498053 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -151,6 +151,7 @@ struct nfsd4_channel_attrs { }; struct nfsd4_cb_sec { + u32 flavor; /* (u32)(-1) used to mean "no valid flavor" */ u32 uid; u32 gid; }; -- cgit v0.10.2 From e4bc6522d53b7b8eb02cfac35fd18275fd86269d Mon Sep 17 00:00:00 2001 From: Li Wang Date: Tue, 30 Oct 2012 19:52:40 +0800 Subject: eCryptfs: Avoid unnecessary disk read and data decryption during writing ecryptfs_write_begin grabs a page from page cache for writing. If the page contains invalid data, or data older than the counterpart on the disk, eCryptfs will read out the corresponing data from the disk into the page, decrypt them, then perform writing. However, for this page, if the length of the data to be written into is equal to page size, that means the whole page of data will be overwritten, in which case, it does not matter whatever the data were before, it is beneficial to perform writing directly rather than bothering to read and decrypt first. With this optimization, according to our test on a machine with Intel Core 2 Duo processor, iozone 'write' operation on an existing file with write size being multiple of page size will enjoy a steady 3x speedup. Signed-off-by: Li Wang Signed-off-by: Yunchuan Wen Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index bd1d57f..564a1fa 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -338,7 +338,8 @@ static int ecryptfs_write_begin(struct file *file, if (prev_page_end_size >= i_size_read(page->mapping->host)) { zero_user(page, 0, PAGE_CACHE_SIZE); - } else { + SetPageUptodate(page); + } else if (len < PAGE_CACHE_SIZE) { rc = ecryptfs_decrypt_page(page); if (rc) { printk(KERN_ERR "%s: Error decrypting " @@ -348,8 +349,8 @@ static int ecryptfs_write_begin(struct file *file, ClearPageUptodate(page); goto out; } + SetPageUptodate(page); } - SetPageUptodate(page); } } /* If creating a page or more of holes, zero them out via truncate. @@ -499,6 +500,13 @@ static int ecryptfs_write_end(struct file *file, } goto out; } + if (!PageUptodate(page)) { + if (copied < PAGE_CACHE_SIZE) { + rc = 0; + goto out; + } + SetPageUptodate(page); + } /* Fills in zeros if 'to' goes beyond inode size */ rc = fill_zeros_to_end_of_page(page, to); if (rc) { -- cgit v0.10.2 From 8eb2ffbf7be94c546a873540ff952140465125e5 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 15 Oct 2012 23:43:29 +0200 Subject: random: fix debug format strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warnings in formatting debug output: drivers/char/random.c: In function ‘xfer_secondary_pool’: drivers/char/random.c:827: warning: format ‘%d’ expects type ‘int’, but argument 7 has type ‘size_t’ drivers/char/random.c: In function ‘account’: drivers/char/random.c:859: warning: format ‘%d’ expects type ‘int’, but argument 5 has type ‘size_t’ drivers/char/random.c:881: warning: format ‘%d’ expects type ‘int’, but argument 5 has type ‘size_t’ drivers/char/random.c: In function ‘random_read’: drivers/char/random.c:1141: warning: format ‘%d’ expects type ‘int’, but argument 5 has type ‘ssize_t’ drivers/char/random.c:1145: warning: format ‘%d’ expects type ‘int’, but argument 5 has type ‘ssize_t’ drivers/char/random.c:1145: warning: format ‘%d’ expects type ‘int’, but argument 6 has type ‘long unsigned int’ by using '%zd' instead of '%d' to properly denote ssize_t/size_t conversion. Signed-off-by: Jiri Kosina Signed-off-by: Theodore Ts'o diff --git a/drivers/char/random.c b/drivers/char/random.c index 9ac4443..a1af183 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -825,7 +825,7 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) bytes = min_t(int, bytes, sizeof(tmp)); DEBUG_ENT("going to reseed %s with %d bits " - "(%d of %d requested)\n", + "(%zu of %d requested)\n", r->name, bytes * 8, nbytes * 8, r->entropy_count); bytes = extract_entropy(r->pull, tmp, bytes, @@ -856,7 +856,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, spin_lock_irqsave(&r->lock, flags); BUG_ON(r->entropy_count > r->poolinfo->POOLBITS); - DEBUG_ENT("trying to extract %d bits from %s\n", + DEBUG_ENT("trying to extract %zu bits from %s\n", nbytes * 8, r->name); /* Can we pull enough? */ @@ -878,7 +878,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, } } - DEBUG_ENT("debiting %d entropy credits from %s%s\n", + DEBUG_ENT("debiting %zu entropy credits from %s%s\n", nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); spin_unlock_irqrestore(&r->lock, flags); @@ -1138,11 +1138,16 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) if (n > SEC_XFER_SIZE) n = SEC_XFER_SIZE; - DEBUG_ENT("reading %d bits\n", n*8); + DEBUG_ENT("reading %zu bits\n", n*8); n = extract_entropy_user(&blocking_pool, buf, n); - DEBUG_ENT("read got %d bits (%d still needed)\n", + if (n < 0) { + retval = n; + break; + } + + DEBUG_ENT("read got %zd bits (%zd still needed)\n", n*8, (nbytes-n)*8); if (n == 0) { @@ -1167,10 +1172,6 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) continue; } - if (n < 0) { - retval = n; - break; - } count += n; buf += n; nbytes -= n; -- cgit v0.10.2 From ec8f02da9ea500474417d1d31fa3d46a562ab366 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 6 Nov 2012 10:42:42 -0500 Subject: random: prime last_data value per fips requirements The value stored in last_data must be primed for FIPS 140-2 purposes. Upon first use, either on system startup or after an RNDCLEARPOOL ioctl, we need to take an initial random sample, store it internally in last_data, then pass along the value after that to the requester, so that consistency checks aren't being run against stale and possibly known data. CC: Herbert Xu CC: "David S. Miller" CC: Matt Mackall CC: linux-crypto@vger.kernel.org Acked-by: Neil Horman Signed-off-by: Jarod Wilson Signed-off-by: "Theodore Ts'o" diff --git a/drivers/char/random.c b/drivers/char/random.c index a1af183..85e81ec 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -433,6 +433,7 @@ struct entropy_store { int entropy_count; int entropy_total; unsigned int initialized:1; + bool last_data_init; __u8 last_data[EXTRACT_SIZE]; }; @@ -953,6 +954,10 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, ssize_t ret = 0, i; __u8 tmp[EXTRACT_SIZE]; + /* if last_data isn't primed, we need EXTRACT_SIZE extra bytes */ + if (fips_enabled && !r->last_data_init) + nbytes += EXTRACT_SIZE; + trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_); xfer_secondary_pool(r, nbytes); nbytes = account(r, nbytes, min, reserved); @@ -963,6 +968,17 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, if (fips_enabled) { unsigned long flags; + + /* prime last_data value if need be, per fips 140-2 */ + if (!r->last_data_init) { + spin_lock_irqsave(&r->lock, flags); + memcpy(r->last_data, tmp, EXTRACT_SIZE); + r->last_data_init = true; + nbytes -= EXTRACT_SIZE; + spin_unlock_irqrestore(&r->lock, flags); + extract_buf(r, tmp); + } + spin_lock_irqsave(&r->lock, flags); if (!memcmp(tmp, r->last_data, EXTRACT_SIZE)) panic("Hardware RNG duplicated output!\n"); @@ -1082,6 +1098,7 @@ static void init_std_data(struct entropy_store *r) r->entropy_count = 0; r->entropy_total = 0; + r->last_data_init = false; mix_pool_bytes(r, &now, sizeof(now), NULL); for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) { if (!arch_get_random_long(&rv)) -- cgit v0.10.2 From 2be975c6d920de989ff5e4bc09ffe87e59d94662 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 3 Nov 2012 12:16:12 -0700 Subject: Input: introduce managed input devices (add devres support) There is a demand from driver's writers to use managed devices framework for their drivers. Unfortunately up to this moment input devices did not provide support for managed devices and that lead to mixing two styles of resource management which usually introduced more bugs, such as manually unregistering input device but relying in devres to free interrupt handler which (unless device is properly shut off) can cause ISR to reference already freed memory. This change introduces devm_input_allocate_device() that will allocate managed instance of input device so that driver writers who prefer using devm_* framework do not have to mix 2 styles. Reviewed-by: Henrik Rydberg Reviewed-by: Tejun Heo Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/input.c b/drivers/input/input.c index f1be1a7..ce01332f 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1726,7 +1726,7 @@ EXPORT_SYMBOL_GPL(input_class); /** * input_allocate_device - allocate memory for new input device * - * Returns prepared struct input_dev or NULL. + * Returns prepared struct input_dev or %NULL. * * NOTE: Use input_free_device() to free devices that have not been * registered; input_unregister_device() should be used for already @@ -1753,6 +1753,70 @@ struct input_dev *input_allocate_device(void) } EXPORT_SYMBOL(input_allocate_device); +struct input_devres { + struct input_dev *input; +}; + +static int devm_input_device_match(struct device *dev, void *res, void *data) +{ + struct input_devres *devres = res; + + return devres->input == data; +} + +static void devm_input_device_release(struct device *dev, void *res) +{ + struct input_devres *devres = res; + struct input_dev *input = devres->input; + + dev_dbg(dev, "%s: dropping reference to %s\n", + __func__, dev_name(&input->dev)); + input_put_device(input); +} + +/** + * devm_input_allocate_device - allocate managed input device + * @dev: device owning the input device being created + * + * Returns prepared struct input_dev or %NULL. + * + * Managed input devices do not need to be explicitly unregistered or + * freed as it will be done automatically when owner device unbinds from + * its driver (or binding fails). Once managed input device is allocated, + * it is ready to be set up and registered in the same fashion as regular + * input device. There are no special devm_input_device_[un]register() + * variants, regular ones work with both managed and unmanaged devices. + * + * NOTE: the owner device is set up as parent of input device and users + * should not override it. + */ + +struct input_dev *devm_input_allocate_device(struct device *dev) +{ + struct input_dev *input; + struct input_devres *devres; + + devres = devres_alloc(devm_input_device_release, + sizeof(struct input_devres), GFP_KERNEL); + if (!devres) + return NULL; + + input = input_allocate_device(); + if (!input) { + devres_free(devres); + return NULL; + } + + input->dev.parent = dev; + input->devres_managed = true; + + devres->input = input; + devres_add(dev, devres); + + return input; +} +EXPORT_SYMBOL(devm_input_allocate_device); + /** * input_free_device - free memory occupied by input_dev structure * @dev: input device to free @@ -1769,8 +1833,14 @@ EXPORT_SYMBOL(input_allocate_device); */ void input_free_device(struct input_dev *dev) { - if (dev) + if (dev) { + if (dev->devres_managed) + WARN_ON(devres_destroy(dev->dev.parent, + devm_input_device_release, + devm_input_device_match, + dev)); input_put_device(dev); + } } EXPORT_SYMBOL(input_free_device); @@ -1891,6 +1961,38 @@ static void input_cleanse_bitmasks(struct input_dev *dev) INPUT_CLEANSE_BITMASK(dev, SW, sw); } +static void __input_unregister_device(struct input_dev *dev) +{ + struct input_handle *handle, *next; + + input_disconnect_device(dev); + + mutex_lock(&input_mutex); + + list_for_each_entry_safe(handle, next, &dev->h_list, d_node) + handle->handler->disconnect(handle); + WARN_ON(!list_empty(&dev->h_list)); + + del_timer_sync(&dev->timer); + list_del_init(&dev->node); + + input_wakeup_procfs_readers(); + + mutex_unlock(&input_mutex); + + device_del(&dev->dev); +} + +static void devm_input_device_unregister(struct device *dev, void *res) +{ + struct input_devres *devres = res; + struct input_dev *input = devres->input; + + dev_dbg(dev, "%s: unregistering device %s\n", + __func__, dev_name(&input->dev)); + __input_unregister_device(input); +} + /** * input_register_device - register device with input core * @dev: device to be registered @@ -1906,11 +2008,21 @@ static void input_cleanse_bitmasks(struct input_dev *dev) int input_register_device(struct input_dev *dev) { static atomic_t input_no = ATOMIC_INIT(0); + struct input_devres *devres = NULL; struct input_handler *handler; unsigned int packet_size; const char *path; int error; + if (dev->devres_managed) { + devres = devres_alloc(devm_input_device_unregister, + sizeof(struct input_devres), GFP_KERNEL); + if (!devres) + return -ENOMEM; + + devres->input = dev; + } + /* Every input device generates EV_SYN/SYN_REPORT events. */ __set_bit(EV_SYN, dev->evbit); @@ -1926,8 +2038,10 @@ int input_register_device(struct input_dev *dev) dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2; dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL); - if (!dev->vals) - return -ENOMEM; + if (!dev->vals) { + error = -ENOMEM; + goto err_devres_free; + } /* * If delay and period are pre-set by the driver, then autorepeating @@ -1952,7 +2066,7 @@ int input_register_device(struct input_dev *dev) error = device_add(&dev->dev); if (error) - return error; + goto err_free_vals; path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); pr_info("%s as %s\n", @@ -1961,10 +2075,8 @@ int input_register_device(struct input_dev *dev) kfree(path); error = mutex_lock_interruptible(&input_mutex); - if (error) { - device_del(&dev->dev); - return error; - } + if (error) + goto err_device_del; list_add_tail(&dev->node, &input_dev_list); @@ -1975,7 +2087,21 @@ int input_register_device(struct input_dev *dev) mutex_unlock(&input_mutex); + if (dev->devres_managed) { + dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n", + __func__, dev_name(&dev->dev)); + devres_add(dev->dev.parent, devres); + } return 0; + +err_device_del: + device_del(&dev->dev); +err_free_vals: + kfree(dev->vals); + dev->vals = NULL; +err_devres_free: + devres_free(devres); + return error; } EXPORT_SYMBOL(input_register_device); @@ -1988,24 +2114,20 @@ EXPORT_SYMBOL(input_register_device); */ void input_unregister_device(struct input_dev *dev) { - struct input_handle *handle, *next; - - input_disconnect_device(dev); - - mutex_lock(&input_mutex); - - list_for_each_entry_safe(handle, next, &dev->h_list, d_node) - handle->handler->disconnect(handle); - WARN_ON(!list_empty(&dev->h_list)); - - del_timer_sync(&dev->timer); - list_del_init(&dev->node); - - input_wakeup_procfs_readers(); - - mutex_unlock(&input_mutex); - - device_unregister(&dev->dev); + if (dev->devres_managed) { + WARN_ON(devres_destroy(dev->dev.parent, + devm_input_device_unregister, + devm_input_device_match, + dev)); + __input_unregister_device(dev); + /* + * We do not do input_put_device() here because it will be done + * when 2nd devres fires up. + */ + } else { + __input_unregister_device(dev); + input_put_device(dev); + } } EXPORT_SYMBOL(input_unregister_device); diff --git a/include/linux/input.h b/include/linux/input.h index cab994b..5538cc0 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -112,6 +112,8 @@ struct input_value { * @h_list: list of input handles associated with the device. When * accessing the list dev->mutex must be held * @node: used to place the device onto input_dev_list + * @devres_managed: indicates that devices is managed with devres framework + * and needs not be explicitly unregistered or freed. */ struct input_dev { const char *name; @@ -180,6 +182,8 @@ struct input_dev { unsigned int num_vals; unsigned int max_vals; struct input_value *vals; + + bool devres_managed; }; #define to_input_dev(d) container_of(d, struct input_dev, dev) @@ -323,7 +327,8 @@ struct input_handle { struct list_head h_node; }; -struct input_dev *input_allocate_device(void); +struct input_dev __must_check *input_allocate_device(void); +struct input_dev __must_check *devm_input_allocate_device(struct device *); void input_free_device(struct input_dev *dev); static inline struct input_dev *input_get_device(struct input_dev *dev) -- cgit v0.10.2 From 3699dd7e16a9f68586a44e1efeb9708359f9c2a6 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 3 Nov 2012 12:16:13 -0700 Subject: Input: wacom - clean up device type code Use switch instead of if statement to verify device types Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 858ad44..67442f4 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -386,23 +386,36 @@ static int wacom_parse_hid(struct usb_interface *intf, if (usage == WCM_DESKTOP) { if (finger) { features->device_type = BTN_TOOL_FINGER; - if (features->type == TABLETPC2FG) { - /* need to reset back */ + + switch (features->type) { + case TABLETPC2FG: features->pktlen = WACOM_PKGLEN_TPC2FG; - } + break; - if (features->type == MTSCREEN || features->type == WACOM_24HDT) + case MTSCREEN: + case WACOM_24HDT: features->pktlen = WACOM_PKGLEN_MTOUCH; + break; - if (features->type == BAMBOO_PT) { - /* need to reset back */ + case BAMBOO_PT: features->pktlen = WACOM_PKGLEN_BBTOUCH; + break; + + default: + features->pktlen = WACOM_PKGLEN_GRAPHIRE; + break; + } + + switch (features->type) { + case BAMBOO_PT: features->x_phy = get_unaligned_le16(&report[i + 5]); features->x_max = get_unaligned_le16(&report[i + 8]); i += 15; - } else if (features->type == WACOM_24HDT) { + break; + + case WACOM_24HDT: features->x_max = get_unaligned_le16(&report[i + 3]); features->x_phy = @@ -410,7 +423,9 @@ static int wacom_parse_hid(struct usb_interface *intf, features->unit = report[i - 1]; features->unitExpo = report[i - 3]; i += 12; - } else { + break; + + default: features->x_max = get_unaligned_le16(&report[i + 3]); features->x_phy = @@ -418,10 +433,11 @@ static int wacom_parse_hid(struct usb_interface *intf, features->unit = report[i + 9]; features->unitExpo = report[i + 11]; i += 12; + break; } } else if (pen) { /* penabled only accepts exact bytes of data */ - if (features->type == TABLETPC2FG) + if (features->type >= TABLETPC) features->pktlen = WACOM_PKGLEN_GRAPHIRE; features->device_type = BTN_TOOL_PEN; features->x_max = @@ -434,32 +450,39 @@ static int wacom_parse_hid(struct usb_interface *intf, case HID_USAGE_Y: if (usage == WCM_DESKTOP) { if (finger) { - int type = features->type; - - if (type == TABLETPC2FG || type == MTSCREEN) { + switch (features->type) { + case TABLETPC2FG: + case MTSCREEN: features->y_max = get_unaligned_le16(&report[i + 3]); features->y_phy = get_unaligned_le16(&report[i + 6]); i += 7; - } else if (type == WACOM_24HDT) { + break; + + case WACOM_24HDT: features->y_max = get_unaligned_le16(&report[i + 3]); features->y_phy = get_unaligned_le16(&report[i - 2]); i += 7; - } else if (type == BAMBOO_PT) { + break; + + case BAMBOO_PT: features->y_phy = get_unaligned_le16(&report[i + 3]); features->y_max = get_unaligned_le16(&report[i + 6]); i += 12; - } else { + break; + + default: features->y_max = features->x_max; features->y_phy = get_unaligned_le16(&report[i + 3]); i += 4; + break; } } else if (pen) { features->y_max = -- cgit v0.10.2 From 6afdc289c984451a6202a687fe6af727e051a784 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 3 Nov 2012 12:16:15 -0700 Subject: Input: wacom - add support for 2 new multi-touch tablets (0x100 and 0x101) This adds support for the two new multi-touch tablets. Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 67442f4..f92d34f 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -397,6 +397,10 @@ static int wacom_parse_hid(struct usb_interface *intf, features->pktlen = WACOM_PKGLEN_MTOUCH; break; + case MTTPC: + features->pktlen = WACOM_PKGLEN_MTTPC; + break; + case BAMBOO_PT: features->pktlen = WACOM_PKGLEN_BBTOUCH; break; @@ -453,6 +457,7 @@ static int wacom_parse_hid(struct usb_interface *intf, switch (features->type) { case TABLETPC2FG: case MTSCREEN: + case MTTPC: features->y_max = get_unaligned_le16(&report[i + 3]); features->y_phy = diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 0a67031..7554a04 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -877,6 +877,11 @@ static int wacom_mt_touch(struct wacom_wac *wacom) int i; int current_num_contacts = data[2]; int contacts_to_send = 0; + int x_offset = 0; + + /* MTTPC does not support Height and Width */ + if (wacom->features.type == MTTPC) + x_offset = -4; /* * First packet resets the counter since only the first @@ -889,7 +894,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom) contacts_to_send = min(5, wacom->num_contacts_left); for (i = 0; i < contacts_to_send; i++) { - int offset = (WACOM_BYTES_PER_MT_PACKET * i) + 3; + int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3; bool touch = data[offset] & 0x1; int id = le16_to_cpup((__le16 *)&data[offset + 1]); int slot = find_slot_from_contactid(wacom, id); @@ -900,8 +905,8 @@ static int wacom_mt_touch(struct wacom_wac *wacom) input_mt_slot(input, slot); input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); if (touch) { - int x = le16_to_cpup((__le16 *)&data[offset + 7]); - int y = le16_to_cpup((__le16 *)&data[offset + 9]); + int x = le16_to_cpup((__le16 *)&data[offset + x_offset + 7]); + int y = le16_to_cpup((__le16 *)&data[offset + x_offset + 9]); input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); } @@ -1336,6 +1341,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) case TABLETPCE: case TABLETPC2FG: case MTSCREEN: + case MTTPC: sync = wacom_tpc_irq(wacom_wac, len); break; @@ -1657,6 +1663,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, /* fall through */ case MTSCREEN: + case MTTPC: if (features->device_type == BTN_TOOL_FINGER) { wacom_wac->slots = kmalloc(features->touch_max * sizeof(int), @@ -2018,6 +2025,12 @@ static const struct wacom_features wacom_features_0xED = static const struct wacom_features wacom_features_0xEF = { "Wacom ISDv4 EF", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x100 = + { "Wacom ISDv4 100", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, + 0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x101 = + { "Wacom ISDv4 101", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, + 0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x47 = { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -2194,6 +2207,8 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xEC) }, { USB_DEVICE_WACOM(0xED) }, { USB_DEVICE_WACOM(0xEF) }, + { USB_DEVICE_WACOM(0x100) }, + { USB_DEVICE_WACOM(0x101) }, { USB_DEVICE_WACOM(0x47) }, { USB_DEVICE_WACOM(0xF4) }, { USB_DEVICE_WACOM(0xF8) }, diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index 345f1e7..9396d77 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -26,6 +26,7 @@ #define WACOM_PKGLEN_BBPEN 10 #define WACOM_PKGLEN_WIRELESS 32 #define WACOM_PKGLEN_MTOUCH 62 +#define WACOM_PKGLEN_MTTPC 40 /* wacom data size per MT contact */ #define WACOM_BYTES_PER_MT_PACKET 11 @@ -88,6 +89,7 @@ enum { TABLETPCE, TABLETPC2FG, MTSCREEN, + MTTPC, MAX_TYPE }; -- cgit v0.10.2 From 4e99aab78ab2adf7645b7f58b2b549e6ea205dd7 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Sat, 3 Nov 2012 12:16:51 -0700 Subject: Input: nomadik-ske-keypad - fixup use of clk Do proper error handling for clk and make sure clocks are being prepared|unprepared as well as enabled|disabled. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 49f5fa6..95dcc9b 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -287,14 +287,19 @@ static int __init ske_keypad_probe(struct platform_device *pdev) keypad->keymap, input); if (error) { dev_err(&pdev->dev, "Failed to build keymap\n"); - goto err_iounmap; + goto err_clk; } input_set_capability(input, EV_MSC, MSC_SCAN); if (!plat->no_autorepeat) __set_bit(EV_REP, input->evbit); - clk_enable(keypad->clk); + error = clk_prepare_enable(keypad->clk); + if (error) { + dev_err(&pdev->dev, "Failed to prepare/enable clk\n"); + goto err_clk; + } + /* go through board initialization helpers */ if (keypad->board->init) @@ -330,7 +335,8 @@ static int __init ske_keypad_probe(struct platform_device *pdev) err_free_irq: free_irq(keypad->irq, keypad); err_clk_disable: - clk_disable(keypad->clk); + clk_disable_unprepare(keypad->clk); +err_clk: clk_put(keypad->clk); err_iounmap: iounmap(keypad->reg_base); @@ -351,7 +357,7 @@ static int __devexit ske_keypad_remove(struct platform_device *pdev) input_unregister_device(keypad->input); - clk_disable(keypad->clk); + clk_disable_unprepare(keypad->clk); clk_put(keypad->clk); if (keypad->board->exit) -- cgit v0.10.2 From 642fe4d00db56d65060ce2fd4c105884414acb16 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 8 Nov 2012 10:01:26 -0500 Subject: SUNRPC: Fix validity issues with rpc_pipefs sb->s_fs_info rpc_kill_sb() must defer calling put_net() until after the notifier has been called, since most (all?) of the notifier callbacks assume that sb->s_fs_info points to a valid net namespace. It also must not call put_net() if the call to rpc_fill_super was unsuccessful. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=48421 Signed-off-by: Trond Myklebust Cc: Stanislav Kinsbursky Cc: stable@vger.kernel.org [>= v3.4] diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 80f5dd2..e659def 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1152,14 +1152,19 @@ static void rpc_kill_sb(struct super_block *sb) struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); mutex_lock(&sn->pipefs_sb_lock); + if (sn->pipefs_sb != sb) { + mutex_unlock(&sn->pipefs_sb_lock); + goto out; + } sn->pipefs_sb = NULL; mutex_unlock(&sn->pipefs_sb_lock); - put_net(net); dprintk("RPC: sending pipefs UMOUNT notification for net %p%s\n", net, NET_NAME(net)); blocking_notifier_call_chain(&rpc_pipefs_notifier_list, RPC_PIPEFS_UMOUNT, sb); + put_net(net); +out: kill_litter_super(sb); } -- cgit v0.10.2 From d852f9597359babcc3f6b328cefc151ab6995d00 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Sat, 3 Nov 2012 12:16:55 -0700 Subject: Input: nomadik-ske-keypad - start using the apb_pclk Previously this clock was handled internally by the clockdriver, but now this is separate clk. So we need take care of it. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 95dcc9b..a1a9375 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -67,6 +67,7 @@ struct ske_keypad { const struct ske_keypad_platform_data *board; unsigned short keymap[SKE_KPD_NUM_ROWS * SKE_KPD_NUM_COLS]; struct clk *clk; + struct clk *pclk; spinlock_t ske_keypad_lock; }; @@ -271,11 +272,18 @@ static int __init ske_keypad_probe(struct platform_device *pdev) goto err_free_mem_region; } + keypad->pclk = clk_get(&pdev->dev, "apb_pclk"); + if (IS_ERR(keypad->pclk)) { + dev_err(&pdev->dev, "failed to get pclk\n"); + error = PTR_ERR(keypad->pclk); + goto err_iounmap; + } + keypad->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(keypad->clk)) { dev_err(&pdev->dev, "failed to get clk\n"); error = PTR_ERR(keypad->clk); - goto err_iounmap; + goto err_pclk; } input->id.bustype = BUS_HOST; @@ -294,10 +302,16 @@ static int __init ske_keypad_probe(struct platform_device *pdev) if (!plat->no_autorepeat) __set_bit(EV_REP, input->evbit); + error = clk_prepare_enable(keypad->pclk); + if (error) { + dev_err(&pdev->dev, "Failed to prepare/enable pclk\n"); + goto err_clk; + } + error = clk_prepare_enable(keypad->clk); if (error) { dev_err(&pdev->dev, "Failed to prepare/enable clk\n"); - goto err_clk; + goto err_pclk_disable; } @@ -336,8 +350,12 @@ err_free_irq: free_irq(keypad->irq, keypad); err_clk_disable: clk_disable_unprepare(keypad->clk); +err_pclk_disable: + clk_disable_unprepare(keypad->pclk); err_clk: clk_put(keypad->clk); +err_pclk: + clk_put(keypad->pclk); err_iounmap: iounmap(keypad->reg_base); err_free_mem_region: -- cgit v0.10.2 From 1eee4af30e9261114e6e4e3576f130780124d7be Mon Sep 17 00:00:00 2001 From: Deepak Sikri Date: Thu, 8 Nov 2012 16:35:27 -0800 Subject: Input: spear-keyboard - fix for balancing the enable_irq_wake This patch handles the fix for unbalanced irq for the cases when enable_irq_wake fails, and a warning related to same is displayed on the console. The workaround is handled at the driver level. Signed-off-by: Deepak Sikri Signed-off-by: Viresh Kumar Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index c7ca97f..7685b47 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -60,10 +60,11 @@ struct spear_kbd { struct clk *clk; unsigned int irq; unsigned int mode; + unsigned int suspended_rate; unsigned short last_key; unsigned short keycodes[NUM_ROWS * NUM_COLS]; bool rep; - unsigned int suspended_rate; + bool irq_wake_enabled; u32 mode_ctl_reg; }; @@ -333,7 +334,8 @@ static int spear_kbd_suspend(struct device *dev) mode_ctl_reg = readl_relaxed(kbd->io_base + MODE_CTL_REG); if (device_may_wakeup(&pdev->dev)) { - enable_irq_wake(kbd->irq); + if (!enable_irq_wake(kbd->irq)) + kbd->irq_wake_enabled = true; /* * reprogram the keyboard operating frequency as on some @@ -379,7 +381,10 @@ static int spear_kbd_resume(struct device *dev) mutex_lock(&input_dev->mutex); if (device_may_wakeup(&pdev->dev)) { - disable_irq_wake(kbd->irq); + if (kbd->irq_wake_enabled) { + kbd->irq_wake_enabled = false; + disable_irq_wake(kbd->irq); + } } else { if (input_dev->users) clk_enable(kbd->clk); -- cgit v0.10.2 From 6102752eb354cca8fb751d8bace2c1ad4efffdde Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 8 Nov 2012 21:41:24 -0800 Subject: Input: spear-keyboard - switch to using managed resources This patch frees spear-keyboard driver from burden of freeing resources :) devm_* derivatives of multiple routines are used while allocating resources, which would be freed automatically by kernel. Signed-off-by: Viresh Kumar Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index 7685b47..da914fe 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -55,7 +55,6 @@ struct spear_kbd { struct input_dev *input; - struct resource *res; void __iomem *io_base; struct clk *clk; unsigned int irq; @@ -204,12 +203,16 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev) return irq; } - kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!kbd || !input_dev) { - dev_err(&pdev->dev, "out of memory\n"); - error = -ENOMEM; - goto err_free_mem; + kbd = devm_kzalloc(&pdev->dev, sizeof(*kbd), GFP_KERNEL); + if (!kbd) { + dev_err(&pdev->dev, "not enough memory for driver data\n"); + return -ENOMEM; + } + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) { + dev_err(&pdev->dev, "unable to allocate input device\n"); + return -ENOMEM; } kbd->input = input_dev; @@ -218,37 +221,25 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev) if (!pdata) { error = spear_kbd_parse_dt(pdev, kbd); if (error) - goto err_free_mem; + return error; } else { kbd->mode = pdata->mode; kbd->rep = pdata->rep; kbd->suspended_rate = pdata->suspended_rate; } - kbd->res = request_mem_region(res->start, resource_size(res), - pdev->name); - if (!kbd->res) { - dev_err(&pdev->dev, "keyboard region already claimed\n"); - error = -EBUSY; - goto err_free_mem; - } - - kbd->io_base = ioremap(res->start, resource_size(res)); + kbd->io_base = devm_request_and_ioremap(&pdev->dev, res); if (!kbd->io_base) { - dev_err(&pdev->dev, "ioremap failed for kbd_region\n"); - error = -ENOMEM; - goto err_release_mem_region; + dev_err(&pdev->dev, "request-ioremap failed for kbd_region\n"); + return -ENOMEM; } - kbd->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(kbd->clk)) { - error = PTR_ERR(kbd->clk); - goto err_iounmap; - } + kbd->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(kbd->clk)) + return PTR_ERR(kbd->clk); input_dev->name = "Spear Keyboard"; input_dev->phys = "keyboard/input0"; - input_dev->dev.parent = &pdev->dev; input_dev->id.bustype = BUS_HOST; input_dev->id.vendor = 0x0001; input_dev->id.product = 0x0001; @@ -260,7 +251,7 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev) kbd->keycodes, input_dev); if (error) { dev_err(&pdev->dev, "Failed to build keymap\n"); - goto err_put_clk; + return error; } if (kbd->rep) @@ -269,49 +260,27 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev) input_set_drvdata(input_dev, kbd); - error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd); + error = devm_request_irq(&pdev->dev, irq, spear_kbd_interrupt, 0, + "keyboard", kbd); if (error) { - dev_err(&pdev->dev, "request_irq fail\n"); - goto err_put_clk; + dev_err(&pdev->dev, "request_irq failed\n"); + return error; } error = input_register_device(input_dev); if (error) { dev_err(&pdev->dev, "Unable to register keyboard device\n"); - goto err_free_irq; + return error; } device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, kbd); return 0; - -err_free_irq: - free_irq(kbd->irq, kbd); -err_put_clk: - clk_put(kbd->clk); -err_iounmap: - iounmap(kbd->io_base); -err_release_mem_region: - release_mem_region(res->start, resource_size(res)); -err_free_mem: - input_free_device(input_dev); - kfree(kbd); - - return error; } static int __devexit spear_kbd_remove(struct platform_device *pdev) { - struct spear_kbd *kbd = platform_get_drvdata(pdev); - - free_irq(kbd->irq, kbd); - input_unregister_device(kbd->input); - clk_put(kbd->clk); - iounmap(kbd->io_base); - release_mem_region(kbd->res->start, resource_size(kbd->res)); - kfree(kbd); - device_init_wakeup(&pdev->dev, 0); platform_set_drvdata(pdev, NULL); -- cgit v0.10.2 From aaa4f2a7f6cce4485dc60063a56e210761f5a0c8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 10 Nov 2012 00:11:10 -0800 Subject: Input: stmpe-keyboard - switch to using managed resources This patch frees stmpe-keyboard driver from burden of freeing resources :) devm_* derivatives of multiple routines are used while allocating resources, which would be freed automatically by kernel. Signed-off-by: Viresh Kumar Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index 470a877..d3d2eaa 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -260,10 +260,10 @@ static int __devinit stmpe_keypad_chip_init(struct stmpe_keypad *keypad) static int __devinit stmpe_keypad_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); - struct stmpe_keypad_platform_data *plat; + const struct stmpe_keypad_platform_data *plat; struct stmpe_keypad *keypad; struct input_dev *input; - int ret; + int error; int irq; int i; @@ -275,26 +275,25 @@ static int __devinit stmpe_keypad_probe(struct platform_device *pdev) if (irq < 0) return irq; - keypad = kzalloc(sizeof(struct stmpe_keypad), GFP_KERNEL); + keypad = devm_kzalloc(&pdev->dev, sizeof(struct stmpe_keypad), + GFP_KERNEL); if (!keypad) return -ENOMEM; - input = input_allocate_device(); - if (!input) { - ret = -ENOMEM; - goto out_freekeypad; - } + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; input->name = "STMPE keypad"; input->id.bustype = BUS_I2C; input->dev.parent = &pdev->dev; - ret = matrix_keypad_build_keymap(plat->keymap_data, NULL, - STMPE_KEYPAD_MAX_ROWS, - STMPE_KEYPAD_MAX_COLS, - keypad->keymap, input); - if (ret) - goto out_freeinput; + error = matrix_keypad_build_keymap(plat->keymap_data, NULL, + STMPE_KEYPAD_MAX_ROWS, + STMPE_KEYPAD_MAX_COLS, + keypad->keymap, input); + if (error) + return error; input_set_capability(input, EV_MSC, MSC_SCAN); if (!plat->no_autorepeat) @@ -312,50 +311,35 @@ static int __devinit stmpe_keypad_probe(struct platform_device *pdev) keypad->input = input; keypad->variant = &stmpe_keypad_variants[stmpe->partnum]; - ret = stmpe_keypad_chip_init(keypad); - if (ret < 0) - goto out_freeinput; + error = stmpe_keypad_chip_init(keypad); + if (error < 0) + return error; - ret = input_register_device(input); - if (ret) { - dev_err(&pdev->dev, - "unable to register input device: %d\n", ret); - goto out_freeinput; + error = devm_request_threaded_irq(&pdev->dev, irq, + NULL, stmpe_keypad_irq, + IRQF_ONESHOT, "stmpe-keypad", keypad); + if (error) { + dev_err(&pdev->dev, "unable to get irq: %d\n", error); + return error; } - ret = request_threaded_irq(irq, NULL, stmpe_keypad_irq, IRQF_ONESHOT, - "stmpe-keypad", keypad); - if (ret) { - dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_unregisterinput; + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, + "unable to register input device: %d\n", error); + return error; } platform_set_drvdata(pdev, keypad); return 0; - -out_unregisterinput: - input_unregister_device(input); - input = NULL; -out_freeinput: - input_free_device(input); -out_freekeypad: - kfree(keypad); - return ret; } static int __devexit stmpe_keypad_remove(struct platform_device *pdev) { struct stmpe_keypad *keypad = platform_get_drvdata(pdev); - struct stmpe *stmpe = keypad->stmpe; - int irq = platform_get_irq(pdev, 0); - - stmpe_disable(stmpe, STMPE_BLOCK_KEYPAD); - free_irq(irq, keypad); - input_unregister_device(keypad->input); - platform_set_drvdata(pdev, NULL); - kfree(keypad); + stmpe_disable(keypad->stmpe, STMPE_BLOCK_KEYPAD); return 0; } -- cgit v0.10.2 From 2bd942f90a6021d5d9f49c28663f38f5b575a818 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 9 Nov 2012 23:56:59 -0800 Subject: Input: stmpe-ts - switch to using managed resources This patch frees stmpe-ts driver from burden of freeing resources :) devm_* derivatives of multiple routines are used while allocating resources, which would be freed automatically by kernel. Signed-off-by: Viresh Kumar Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 692b685..7d9aadc 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -1,4 +1,5 @@ -/* STMicroelectronics STMPE811 Touchscreen Driver +/* + * STMicroelectronics STMPE811 Touchscreen Driver * * (C) 2010 Luotao Fu * All rights reserved. @@ -264,28 +265,24 @@ static void stmpe_ts_close(struct input_dev *dev) static int __devinit stmpe_input_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); - struct stmpe_platform_data *pdata = stmpe->pdata; + const struct stmpe_platform_data *pdata = stmpe->pdata; + const struct stmpe_ts_platform_data *ts_pdata = NULL; struct stmpe_touch *ts; struct input_dev *idev; - struct stmpe_ts_platform_data *ts_pdata = NULL; - int ret; + int error; int ts_irq; ts_irq = platform_get_irq_byname(pdev, "FIFO_TH"); if (ts_irq < 0) return ts_irq; - ts = kzalloc(sizeof(*ts), GFP_KERNEL); - if (!ts) { - ret = -ENOMEM; - goto err_out; - } + ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; - idev = input_allocate_device(); - if (!idev) { - ret = -ENOMEM; - goto err_free_ts; - } + idev = devm_input_allocate_device(&pdev->dev); + if (!idev) + return -ENOMEM; platform_set_drvdata(pdev, ts); ts->stmpe = stmpe; @@ -309,16 +306,17 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&ts->work, stmpe_work); - ret = request_threaded_irq(ts_irq, NULL, stmpe_ts_handler, - IRQF_ONESHOT, STMPE_TS_NAME, ts); - if (ret) { + error = devm_request_threaded_irq(&pdev->dev, ts_irq, + NULL, stmpe_ts_handler, + IRQF_ONESHOT, STMPE_TS_NAME, ts); + if (error) { dev_err(&pdev->dev, "Failed to request IRQ %d\n", ts_irq); - goto err_free_input; + return error; } - ret = stmpe_init_hw(ts); - if (ret) - goto err_free_irq; + error = stmpe_init_hw(ts); + if (error) + return error; idev->name = STMPE_TS_NAME; idev->id.bustype = BUS_I2C; @@ -334,40 +332,21 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev) input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0); input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0); - ret = input_register_device(idev); - if (ret) { + error = input_register_device(idev); + if (error) { dev_err(&pdev->dev, "Could not register input device\n"); - goto err_free_irq; + return error; } - return ret; - -err_free_irq: - free_irq(ts_irq, ts); -err_free_input: - input_free_device(idev); - platform_set_drvdata(pdev, NULL); -err_free_ts: - kfree(ts); -err_out: - return ret; + return 0; } static int __devexit stmpe_ts_remove(struct platform_device *pdev) { struct stmpe_touch *ts = platform_get_drvdata(pdev); - unsigned int ts_irq = platform_get_irq_byname(pdev, "FIFO_TH"); stmpe_disable(ts->stmpe, STMPE_BLOCK_TOUCHSCREEN); - free_irq(ts_irq, ts); - - platform_set_drvdata(pdev, NULL); - - input_unregister_device(ts->idev); - - kfree(ts); - return 0; } -- cgit v0.10.2 From b8d52e2b9f7eb43075e6ef4e23f5e51e70548f11 Mon Sep 17 00:00:00 2001 From: Vipul Kumar Samar Date: Sat, 10 Nov 2012 00:08:20 -0800 Subject: Input: stmpe-ts - initialize the phys field in input device Signed-off-by: Vipul Kumar Samar Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 7d9aadc..b3f7503 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -319,6 +319,7 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev) return error; idev->name = STMPE_TS_NAME; + idev->phys = STMPE_TS_NAME"/input0"; idev->id.bustype = BUS_I2C; idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); -- cgit v0.10.2 From 800963fd598e2acbcd3a21a17e3ab3c185ad0d6a Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 10 Nov 2012 00:32:36 -0800 Subject: Input: document new members of struct input_dev Fixes kernel-doc warnings for the members added in 3.7-rc1. Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov diff --git a/include/linux/input.h b/include/linux/input.h index 5538cc0..82ce323 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -112,6 +112,9 @@ struct input_value { * @h_list: list of input handles associated with the device. When * accessing the list dev->mutex must be held * @node: used to place the device onto input_dev_list + * @num_vals: number of values queued in the current frame + * @max_vals: maximum number of values queued in a frame + * @vals: array of values queued in the current frame * @devres_managed: indicates that devices is managed with devres framework * and needs not be explicitly unregistered or freed. */ -- cgit v0.10.2 From 71a129fb6153ca7a972c31dddb09c2f097262e6e Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Sat, 10 Nov 2012 00:47:13 -0800 Subject: Input: HIL - remove one goto This goto is only used to skip the next instruction, which can easily be done without a goto. Signed-off-by: Rolf Eike Beer Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index bfd3865..0280167 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -686,13 +686,12 @@ static int hilse_donode(hil_mlc *mlc) write_lock_irqsave(&mlc->lock, flags); pack = node->object.packet; out: - if (mlc->istarted) - goto out2; - /* Prepare to receive input */ - if ((node + 1)->act & HILSE_IN) - hilse_setup_input(mlc, node + 1); + if (!mlc->istarted) { + /* Prepare to receive input */ + if ((node + 1)->act & HILSE_IN) + hilse_setup_input(mlc, node + 1); + } - out2: write_unlock_irqrestore(&mlc->lock, flags); if (down_trylock(&mlc->osem)) { -- cgit v0.10.2 From 544a46c917fcf0a439cc0c428d76ba731a380cae Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sat, 10 Nov 2012 00:50:25 -0800 Subject: Input: add Retu power button driver. Signed-off-by: Aaro Koskinen Acked-by: Felipe Balbi Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 0f959d7..2a1647e 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -364,6 +364,16 @@ config INPUT_CM109 To compile this driver as a module, choose M here: the module will be called cm109. +config INPUT_RETU_PWRBUTTON + tristate "Retu Power button Driver" + depends on MFD_RETU + help + Say Y here if you want to enable power key reporting via the + Retu chips found in Nokia Internet Tablets (770, N800, N810). + + To compile this driver as a module, choose M here. The module will + be called retu-pwrbutton. + config INPUT_TWL4030_PWRBUTTON tristate "TWL4030 Power button Driver" depends on TWL4030_CORE diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 23347e3..1f874af 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o +obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o diff --git a/drivers/input/misc/retu-pwrbutton.c b/drivers/input/misc/retu-pwrbutton.c new file mode 100644 index 0000000..3767f43 --- /dev/null +++ b/drivers/input/misc/retu-pwrbutton.c @@ -0,0 +1,99 @@ +/* + * Retu power button driver. + * + * Copyright (C) 2004-2010 Nokia Corporation + * + * Original code written by Ari Saastamoinen, Juha Yrjölä and Felipe Balbi. + * Rewritten by Aaro Koskinen. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RETU_STATUS_PWRONX (1 << 5) + +static irqreturn_t retu_pwrbutton_irq(int irq, void *_pwr) +{ + struct input_dev *idev = _pwr; + struct retu_dev *rdev = input_get_drvdata(idev); + bool state; + + state = !(retu_read(rdev, RETU_REG_STATUS) & RETU_STATUS_PWRONX); + input_report_key(idev, KEY_POWER, state); + input_sync(idev); + + return IRQ_HANDLED; +} + +static int __devinit retu_pwrbutton_probe(struct platform_device *pdev) +{ + struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent); + struct input_dev *idev; + int irq; + int error; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + idev = devm_input_allocate_device(&pdev->dev); + if (!idev) + return -ENOMEM; + + idev->name = "retu-pwrbutton"; + idev->dev.parent = &pdev->dev; + + input_set_capability(idev, EV_KEY, KEY_POWER); + input_set_drvdata(idev, rdev); + + error = devm_request_threaded_irq(&pdev->dev, irq, + NULL, retu_pwrbutton_irq, 0, + "retu-pwrbutton", idev); + if (error) + return error; + + error = input_register_device(idev); + if (error) + return error; + + return 0; +} + +static int __devexit retu_pwrbutton_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver retu_pwrbutton_driver = { + .probe = retu_pwrbutton_probe, + .remove = __devexit_p(retu_pwrbutton_remove), + .driver = { + .name = "retu-pwrbutton", + .owner = THIS_MODULE, + }, +}; +module_platform_driver(retu_pwrbutton_driver); + +MODULE_ALIAS("platform:retu-pwrbutton"); +MODULE_DESCRIPTION("Retu Power Button"); +MODULE_AUTHOR("Ari Saastamoinen"); +MODULE_AUTHOR("Felipe Balbi"); +MODULE_AUTHOR("Aaro Koskinen "); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 292a41716a4ad3e93c57155f99786abe8a8d386a Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 7 Nov 2012 19:41:51 -0500 Subject: nfsd4: update documentation on 4.1 progress Signed-off-by: J. Bruce Fields diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt index f5ddff2..392ef63 100644 --- a/Documentation/filesystems/nfs/nfs41-server.txt +++ b/Documentation/filesystems/nfs/nfs41-server.txt @@ -43,12 +43,6 @@ interoperability problems with future clients. Known issues: client-server state (thus preventing unauthorized tampering with locks and opens, for example). It is mandatory for servers to support this, though no clients use it yet. - - Mandatory operations which we do not support, such as - DESTROY_CLIENTID, are not currently used by clients, but will be - (and the spec recommends their uses in common cases), and - clients should not be expected to know how to recover from the - case where they are not supported. This will eventually cause - interoperability failures. In addition, some limitations are inherited from the current NFSv4 implementation: @@ -94,7 +88,7 @@ NS*| DELEGPURGE | OPT | FDELG (REQ) | Section 18.5 | | DELEGRETURN | OPT | FDELG, | Section 18.6 | | | | DDELG, pNFS | | | | | (REQ) | | -NS | DESTROY_CLIENTID | REQ | | Section 18.50 | +I | DESTROY_CLIENTID | REQ | | Section 18.50 | I | DESTROY_SESSION | REQ | | Section 18.37 | I | EXCHANGE_ID | REQ | | Section 18.35 | I | FREE_STATEID | REQ | | Section 18.38 | @@ -187,7 +181,6 @@ EXCHANGE_ID: CREATE_SESSION: * backchannel attributes are ignored -* backchannel security parameters are ignored SEQUENCE: * no support for dynamic slot table renegotiation (optional) -- cgit v0.10.2 From 698d8d875a0593f65092f6619d97de49bc5caa45 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 9 Nov 2012 15:31:53 -0500 Subject: nfsd: fix error handling in nfsd4_remove_clid_dir If the credential save fails, then we'll leak our mnt_want_write_file reference. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 43295d4..0f1e2e2 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -301,12 +301,13 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) status = nfs4_save_creds(&original_cred); if (status < 0) - goto out; + goto out_drop_write; status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); nfs4_reset_creds(original_cred); if (status == 0) vfs_fsync(rec_file, 0); +out_drop_write: mnt_drop_write_file(rec_file); out: if (status) -- cgit v0.10.2 From a0af710a6510213672d28f83681c391d36a7555e Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 9 Nov 2012 15:06:38 -0500 Subject: nfsd: remove unused argument to nfs4_has_reclaimed_state Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 0f1e2e2..151921b 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -320,7 +320,7 @@ purge_old(struct dentry *parent, struct dentry *child) { int status; - if (nfs4_has_reclaimed_state(child->d_name.name, false)) + if (nfs4_has_reclaimed_state(child->d_name.name)) return 0; status = vfs_rmdir(parent->d_inode, child); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 13f3471..d6b602a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4484,7 +4484,7 @@ alloc_reclaim(void) } int -nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) +nfs4_has_reclaimed_state(const char *name) { unsigned int strhashval = clientstr_hashval(name); struct nfs4_client *clp; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 0498053..8053b57 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -482,7 +482,7 @@ extern void nfsd4_shutdown_callback(struct nfs4_client *); extern void nfs4_put_delegation(struct nfs4_delegation *dp); extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); extern int nfs4_client_to_reclaim(const char *name); -extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id); +extern int nfs4_has_reclaimed_state(const char *name); extern void release_session_client(struct nfsd4_session *); extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); -- cgit v0.10.2 From cf7505ef9cd1349dfff0b2aeb9bc62f54c14e03d Mon Sep 17 00:00:00 2001 From: Chuansheng Liu Date: Wed, 7 Nov 2012 01:18:37 +0800 Subject: i2c: nomadik: Fix the usage of wait_for_completion_timeout The return value of wait_for_completion_timeout() is always >= 0 with unsigned int type. So the condition "ret < 0" or "ret >= 0" is pointless. Signed-off-by: liu chuansheng Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 02c3115..8b2ffcf 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -435,13 +435,6 @@ static int read_i2c(struct nmk_i2c_dev *dev, u16 flags) timeout = wait_for_completion_timeout( &dev->xfer_complete, dev->adap.timeout); - if (timeout < 0) { - dev_err(&dev->adev->dev, - "wait_for_completion_timeout " - "returned %d waiting for event\n", timeout); - status = timeout; - } - if (timeout == 0) { /* Controller timed out */ dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n", @@ -523,13 +516,6 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) timeout = wait_for_completion_timeout( &dev->xfer_complete, dev->adap.timeout); - if (timeout < 0) { - dev_err(&dev->adev->dev, - "wait_for_completion_timeout " - "returned %d waiting for event\n", timeout); - status = timeout; - } - if (timeout == 0) { /* Controller timed out */ dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n", -- cgit v0.10.2 From 2873d2147e1e14b82367bde14354a011ffda0496 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:48 -0500 Subject: nfsd: add a usermodehelper upcall for NFSv4 client ID tracking Add a new client tracker upcall type that uses call_usermodehelper to call out to a program. This seems to be the preferred method of calling out to usermode these days for seldom-called upcalls. It's simple and doesn't require a running daemon, so it should "just work" as long as the binary is installed. The client tracking exit operation is also changed to check for a NULL pointer before running. The UMH upcall doesn't need to do anything at module teardown time. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 151921b..2fc2f6c 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -927,6 +927,137 @@ static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { .grace_done = nfsd4_cld_grace_done, }; +/* upcall via usermodehelper */ +static char cltrack_prog[PATH_MAX] = "/sbin/nfsdcltrack"; +module_param_string(cltrack_prog, cltrack_prog, sizeof(cltrack_prog), + S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(cltrack_prog, "Path to the nfsdcltrack upcall program"); + +static int +nfsd4_umh_cltrack_upcall(char *cmd, char *arg) +{ + char *envp[] = { NULL }; + char *argv[4]; + int ret; + + if (unlikely(!cltrack_prog[0])) { + dprintk("%s: cltrack_prog is disabled\n", __func__); + return -EACCES; + } + + dprintk("%s: cmd: %s\n", __func__, cmd); + dprintk("%s: arg: %s\n", __func__, arg ? arg : "(null)"); + + argv[0] = (char *)cltrack_prog; + argv[1] = cmd; + argv[2] = arg; + argv[3] = NULL; + + ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); + /* + * Disable the upcall mechanism if we're getting an ENOENT or EACCES + * error. The admin can re-enable it on the fly by using sysfs + * once the problem has been fixed. + */ + if (ret == -ENOENT || ret == -EACCES) { + dprintk("NFSD: %s was not found or isn't executable (%d). " + "Setting cltrack_prog to blank string!", + cltrack_prog, ret); + cltrack_prog[0] = '\0'; + } + dprintk("%s: %s return value: %d\n", __func__, cltrack_prog, ret); + + return ret; +} + +static char * +bin_to_hex_dup(const unsigned char *src, int srclen) +{ + int i; + char *buf, *hex; + + /* +1 for terminating NULL */ + buf = kmalloc((srclen * 2) + 1, GFP_KERNEL); + if (!buf) + return buf; + + hex = buf; + for (i = 0; i < srclen; i++) { + sprintf(hex, "%2.2x", *src++); + hex += 2; + } + return buf; +} + +static int +nfsd4_umh_cltrack_init(struct net __attribute__((unused)) *net) +{ + return nfsd4_umh_cltrack_upcall("init", NULL); +} + +static void +nfsd4_umh_cltrack_create(struct nfs4_client *clp) +{ + char *hexid; + + hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len); + if (!hexid) { + dprintk("%s: can't allocate memory for upcall!\n", __func__); + return; + } + nfsd4_umh_cltrack_upcall("create", hexid); + kfree(hexid); +} + +static void +nfsd4_umh_cltrack_remove(struct nfs4_client *clp) +{ + char *hexid; + + hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len); + if (!hexid) { + dprintk("%s: can't allocate memory for upcall!\n", __func__); + return; + } + nfsd4_umh_cltrack_upcall("remove", hexid); + kfree(hexid); +} + +static int +nfsd4_umh_cltrack_check(struct nfs4_client *clp) +{ + int ret; + char *hexid; + + hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len); + if (!hexid) { + dprintk("%s: can't allocate memory for upcall!\n", __func__); + return -ENOMEM; + } + ret = nfsd4_umh_cltrack_upcall("check", hexid); + kfree(hexid); + return ret; +} + +static void +nfsd4_umh_cltrack_grace_done(struct net __attribute__((unused)) *net, + time_t boot_time) +{ + char timestr[22]; /* FIXME: better way to determine max size? */ + + sprintf(timestr, "%ld", boot_time); + nfsd4_umh_cltrack_upcall("gracedone", timestr); +} + +static struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = { + .init = nfsd4_umh_cltrack_init, + .exit = NULL, + .create = nfsd4_umh_cltrack_create, + .remove = nfsd4_umh_cltrack_remove, + .check = nfsd4_umh_cltrack_check, + .grace_done = nfsd4_umh_cltrack_grace_done, +}; + int nfsd4_client_tracking_init(struct net *net) { @@ -957,7 +1088,8 @@ void nfsd4_client_tracking_exit(struct net *net) { if (client_tracking_ops) { - client_tracking_ops->exit(net); + if (client_tracking_ops->exit) + client_tracking_ops->exit(net); client_tracking_ops = NULL; } } -- cgit v0.10.2 From 2d77bf0a55d64559adb2d48a37bc7e876d6adc11 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:49 -0500 Subject: nfsd: change heuristic for selecting the client_tracking_ops First, try to use the new usermodehelper upcall. It should succeed or fail quickly, so there's little cost to doing so. If it fails, and the legacy tracking dir exists, use that. If it doesn't exist then fall back to using nfsdcld. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 2fc2f6c..e71f713 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -1064,17 +1064,35 @@ nfsd4_client_tracking_init(struct net *net) int status; struct path path; - if (!client_tracking_ops) { - client_tracking_ops = &nfsd4_cld_tracking_ops; - status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path); - if (!status) { - if (S_ISDIR(path.dentry->d_inode->i_mode)) - client_tracking_ops = - &nfsd4_legacy_tracking_ops; - path_put(&path); - } + /* just run the init if it the method is already decided */ + if (client_tracking_ops) + goto do_init; + + /* + * First, try a UMH upcall. It should succeed or fail quickly, so + * there's little harm in trying that first. + */ + client_tracking_ops = &nfsd4_umh_tracking_ops; + status = client_tracking_ops->init(net); + if (!status) + return status; + + /* + * See if the recoverydir exists and is a directory. If it is, + * then use the legacy ops. + */ + client_tracking_ops = &nfsd4_legacy_tracking_ops; + status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path); + if (!status) { + status = S_ISDIR(path.dentry->d_inode->i_mode); + path_put(&path); + if (status) + goto do_init; } + /* Finally, try to use nfsdcld */ + client_tracking_ops = &nfsd4_cld_tracking_ops; +do_init: status = client_tracking_ops->init(net); if (status) { printk(KERN_WARNING "NFSD: Unable to initialize client " -- cgit v0.10.2 From f3aa7e24c91ee3fd387150c2c5a9934b09f44ec5 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:50 -0500 Subject: nfsd: pass info about the legacy recoverydir in environment variables The usermodehelper upcall program can then decide to use this info as a (one-way) transition mechanism to the new scheme. When a "check" upcall occurs and the client doesn't exist in the database, we can look to see whether the directory exists. If it does, then we'd add the client to the database, remove the legacy recdir, and return success to the kernel to allow the recovery to proceed. For gracedone, we simply pass the v4recovery "topdir" so that the upcall can clean it out prior to returning to the kernel. A module parm is also added to disable the legacy conversion if the admin chooses. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index e71f713..38af615 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -933,10 +933,75 @@ module_param_string(cltrack_prog, cltrack_prog, sizeof(cltrack_prog), S_IRUGO|S_IWUSR); MODULE_PARM_DESC(cltrack_prog, "Path to the nfsdcltrack upcall program"); +static bool cltrack_legacy_disable; +module_param(cltrack_legacy_disable, bool, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(cltrack_legacy_disable, + "Disable legacy recoverydir conversion. Default: false"); + +#define LEGACY_TOPDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_TOPDIR=" +#define LEGACY_RECDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_RECDIR=" + +static char * +nfsd4_cltrack_legacy_topdir(void) +{ + int copied; + size_t len; + char *result; + + if (cltrack_legacy_disable) + return NULL; + + len = strlen(LEGACY_TOPDIR_ENV_PREFIX) + + strlen(nfs4_recoverydir()) + 1; + + result = kmalloc(len, GFP_KERNEL); + if (!result) + return result; + + copied = snprintf(result, len, LEGACY_TOPDIR_ENV_PREFIX "%s", + nfs4_recoverydir()); + if (copied >= len) { + /* just return nothing if output was truncated */ + kfree(result); + return NULL; + } + + return result; +} + +static char * +nfsd4_cltrack_legacy_recdir(const char *recdir) +{ + int copied; + size_t len; + char *result; + + if (cltrack_legacy_disable) + return NULL; + + /* +1 is for '/' between "topdir" and "recdir" */ + len = strlen(LEGACY_RECDIR_ENV_PREFIX) + + strlen(nfs4_recoverydir()) + 1 + HEXDIR_LEN; + + result = kmalloc(len, GFP_KERNEL); + if (!result) + return result; + + copied = snprintf(result, len, LEGACY_RECDIR_ENV_PREFIX "%s/%s", + nfs4_recoverydir(), recdir); + if (copied >= len) { + /* just return nothing if output was truncated */ + kfree(result); + return NULL; + } + + return result; +} + static int -nfsd4_umh_cltrack_upcall(char *cmd, char *arg) +nfsd4_umh_cltrack_upcall(char *cmd, char *arg, char *legacy) { - char *envp[] = { NULL }; + char *envp[2]; char *argv[4]; int ret; @@ -947,6 +1012,10 @@ nfsd4_umh_cltrack_upcall(char *cmd, char *arg) dprintk("%s: cmd: %s\n", __func__, cmd); dprintk("%s: arg: %s\n", __func__, arg ? arg : "(null)"); + dprintk("%s: legacy: %s\n", __func__, legacy ? legacy : "(null)"); + + envp[0] = legacy; + envp[1] = NULL; argv[0] = (char *)cltrack_prog; argv[1] = cmd; @@ -992,7 +1061,7 @@ bin_to_hex_dup(const unsigned char *src, int srclen) static int nfsd4_umh_cltrack_init(struct net __attribute__((unused)) *net) { - return nfsd4_umh_cltrack_upcall("init", NULL); + return nfsd4_umh_cltrack_upcall("init", NULL, NULL); } static void @@ -1005,7 +1074,7 @@ nfsd4_umh_cltrack_create(struct nfs4_client *clp) dprintk("%s: can't allocate memory for upcall!\n", __func__); return; } - nfsd4_umh_cltrack_upcall("create", hexid); + nfsd4_umh_cltrack_upcall("create", hexid, NULL); kfree(hexid); } @@ -1019,7 +1088,7 @@ nfsd4_umh_cltrack_remove(struct nfs4_client *clp) dprintk("%s: can't allocate memory for upcall!\n", __func__); return; } - nfsd4_umh_cltrack_upcall("remove", hexid); + nfsd4_umh_cltrack_upcall("remove", hexid, NULL); kfree(hexid); } @@ -1027,14 +1096,16 @@ static int nfsd4_umh_cltrack_check(struct nfs4_client *clp) { int ret; - char *hexid; + char *hexid, *legacy; hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len); if (!hexid) { dprintk("%s: can't allocate memory for upcall!\n", __func__); return -ENOMEM; } - ret = nfsd4_umh_cltrack_upcall("check", hexid); + legacy = nfsd4_cltrack_legacy_recdir(clp->cl_recdir); + ret = nfsd4_umh_cltrack_upcall("check", hexid, legacy); + kfree(legacy); kfree(hexid); return ret; } @@ -1043,10 +1114,13 @@ static void nfsd4_umh_cltrack_grace_done(struct net __attribute__((unused)) *net, time_t boot_time) { + char *legacy; char timestr[22]; /* FIXME: better way to determine max size? */ sprintf(timestr, "%ld", boot_time); - nfsd4_umh_cltrack_upcall("gracedone", timestr); + legacy = nfsd4_cltrack_legacy_topdir(); + nfsd4_umh_cltrack_upcall("gracedone", timestr, legacy); + kfree(legacy); } static struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = { -- cgit v0.10.2 From 8b0554e9a24298c91de89a779a714c87073380a2 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:51 -0500 Subject: nfsd: warn about impending removal of nfsdcld upcall Let's shoot for removing the nfsdcld upcall in 3.10. Most likely, no one is actually using it so I don't expect this warning to fire often (except maybe on misconfigured systems). Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 38af615..6aaf5d9 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -1166,6 +1166,9 @@ nfsd4_client_tracking_init(struct net *net) /* Finally, try to use nfsdcld */ client_tracking_ops = &nfsd4_cld_tracking_ops; + printk(KERN_WARNING "NFSD: the nfsdcld client tracking upcall will be " + "removed in 3.10. Please transition to using " + "nfsdcltrack.\n"); do_init: status = client_tracking_ops->init(net); if (status) { -- cgit v0.10.2 From 278c931cb05ae624df8c82b6bdfbb0e03392cde7 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:52 -0500 Subject: nfsd: have nfsd4_find_reclaim_client take a char * argument Currently, it takes a client pointer, but later we're going to need to search for these records without knowing whether a matching client even exists. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 6aaf5d9..4e92fb3 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -486,7 +486,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp) return 0; /* look for it in the reclaim hashtable otherwise */ - if (nfsd4_find_reclaim_client(clp)) { + if (nfsd4_find_reclaim_client(clp->cl_recdir)) { set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); return 0; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d6b602a..18e5549 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4537,19 +4537,16 @@ nfs4_release_reclaim(void) /* * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ struct nfs4_client_reclaim * -nfsd4_find_reclaim_client(struct nfs4_client *clp) +nfsd4_find_reclaim_client(const char *recdir) { unsigned int strhashval; struct nfs4_client_reclaim *crp = NULL; - dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n", - clp->cl_name.len, clp->cl_name.data, - clp->cl_recdir); + dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); - /* find clp->cl_name in reclaim_str_hashtbl */ - strhashval = clientstr_hashval(clp->cl_recdir); + strhashval = clientstr_hashval(recdir); list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { - if (same_name(crp->cr_recdir, clp->cl_recdir)) { + if (same_name(crp->cr_recdir, recdir)) { return crp; } } diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 8053b57..c41c280 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -466,7 +466,7 @@ extern void nfs4_lock_state(void); extern void nfs4_unlock_state(void); extern int nfs4_in_grace(void); extern void nfs4_release_reclaim(void); -extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp); +extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir); extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions); extern void nfs4_free_openowner(struct nfs4_openowner *); extern void nfs4_free_lockowner(struct nfs4_lockowner *); -- cgit v0.10.2 From ce30e5392fcb26b6aa53bb16d06da1d7d8bb0863 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:53 -0500 Subject: nfsd: break out reclaim record removal into separate function We'll need to be able to call this from nfs4recover.c eventually. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 18e5549..24dcda2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4517,6 +4517,14 @@ nfs4_client_to_reclaim(const char *name) } void +nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp) +{ + list_del(&crp->cr_strhash); + kfree(crp); + reclaim_str_hashtbl_size--; +} + +void nfs4_release_reclaim(void) { struct nfs4_client_reclaim *crp = NULL; @@ -4526,9 +4534,7 @@ nfs4_release_reclaim(void) while (!list_empty(&reclaim_str_hashtbl[i])) { crp = list_entry(reclaim_str_hashtbl[i].next, struct nfs4_client_reclaim, cr_strhash); - list_del(&crp->cr_strhash); - kfree(crp); - reclaim_str_hashtbl_size--; + nfs4_remove_reclaim_record(crp); } } BUG_ON(reclaim_str_hashtbl_size); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index c41c280..3528616 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -465,6 +465,7 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net, extern void nfs4_lock_state(void); extern void nfs4_unlock_state(void); extern int nfs4_in_grace(void); +void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *); extern void nfs4_release_reclaim(void); extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir); extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions); -- cgit v0.10.2 From 772a9bbbb5769c646c74452ef21df538bbe2ebf0 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:54 -0500 Subject: nfsd: make nfs4_client_to_reclaim return a pointer to the reclaim record Later callers will need to make changes to the record. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 24dcda2..1c6f82e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4498,22 +4498,22 @@ nfs4_has_reclaimed_state(const char *name) /* * failure => all reset bets are off, nfserr_no_grace... */ -int +struct nfs4_client_reclaim * nfs4_client_to_reclaim(const char *name) { unsigned int strhashval; - struct nfs4_client_reclaim *crp = NULL; + struct nfs4_client_reclaim *crp; dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); crp = alloc_reclaim(); - if (!crp) - return 0; - strhashval = clientstr_hashval(name); - INIT_LIST_HEAD(&crp->cr_strhash); - list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); - memcpy(crp->cr_recdir, name, HEXDIR_LEN); - reclaim_str_hashtbl_size++; - return 1; + if (crp) { + strhashval = clientstr_hashval(name); + INIT_LIST_HEAD(&crp->cr_strhash); + list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); + memcpy(crp->cr_recdir, name, HEXDIR_LEN); + reclaim_str_hashtbl_size++; + } + return crp; } void diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 3528616..3f8b26b 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -482,7 +482,7 @@ extern void nfsd4_destroy_callback_queue(void); extern void nfsd4_shutdown_callback(struct nfs4_client *); extern void nfs4_put_delegation(struct nfs4_delegation *dp); extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); -extern int nfs4_client_to_reclaim(const char *name); +extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name); extern int nfs4_has_reclaimed_state(const char *name); extern void release_session_client(struct nfsd4_session *); extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); -- cgit v0.10.2 From 0ce0c2b5d23080eec39ccc52354be1eea326ed5f Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:55 -0500 Subject: nfsd: don't search for client by hash on legacy reboot recovery gracedone When nfsd starts, the legacy reboot recovery code creates a tracking struct for each directory in the v4recoverydir. When the grace period ends, it basically does a "readdir" on the directory again, and matches each dentry in there to an existing client id to see if it should be removed or not. If the matching client doesn't exist, or hasn't reclaimed its state then it will remove that dentry. This is pretty inefficient since it involves doing a lot of hash-bucket searching. It also means that we have to keep relying on being able to search for a nfs4_client by md5 hashed cl_recdir name. Instead, add a pointer to the nfs4_client that indicates the association between the nfs4_client_reclaim and nfs4_client. When a reclaim operation comes in, we set the pointer to make that association. On gracedone, the legacy client tracker will keep the recdir around iff: 1/ there is a reclaim record for the directory ...and... 2/ there's an association between the reclaim record and a client record -- that is, a create or check operation was performed on the client that matches that directory. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 4e92fb3..3048c01 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -65,6 +65,7 @@ struct nfsd4_client_tracking_ops { static struct file *rec_file; static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; static struct nfsd4_client_tracking_ops *client_tracking_ops; +static bool in_grace; static int nfs4_save_creds(const struct cred **original_creds) @@ -142,6 +143,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) const struct cred *original_cred; char *dname = clp->cl_recdir; struct dentry *dir, *dentry; + struct nfs4_client_reclaim *crp; int status; dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); @@ -182,13 +184,19 @@ out_put: dput(dentry); out_unlock: mutex_unlock(&dir->d_inode->i_mutex); - if (status == 0) + if (status == 0) { + if (in_grace) { + crp = nfs4_client_to_reclaim(clp->cl_recdir); + if (crp) + crp->cr_clp = clp; + } vfs_fsync(rec_file, 0); - else + } else { printk(KERN_ERR "NFSD: failed to write recovery record" " (err %d); please check that %s exists" " and is writeable", status, user_recovery_dirname); + } mnt_drop_write_file(rec_file); nfs4_reset_creds(original_cred); } @@ -289,6 +297,7 @@ static void nfsd4_remove_clid_dir(struct nfs4_client *clp) { const struct cred *original_cred; + struct nfs4_client_reclaim *crp; int status; if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) @@ -305,8 +314,15 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); nfs4_reset_creds(original_cred); - if (status == 0) + if (status == 0) { vfs_fsync(rec_file, 0); + if (in_grace) { + /* remove reclaim record */ + crp = nfsd4_find_reclaim_client(clp->cl_recdir); + if (crp) + nfs4_remove_reclaim_record(crp); + } + } out_drop_write: mnt_drop_write_file(rec_file); out: @@ -336,6 +352,7 @@ nfsd4_recdir_purge_old(struct net *net, time_t boot_time) { int status; + in_grace = false; if (!rec_file) return; status = mnt_want_write_file(rec_file); @@ -410,6 +427,8 @@ nfsd4_init_recdir(void) } nfs4_reset_creds(original_cred); + if (!status) + in_grace = true; return status; } @@ -481,13 +500,17 @@ nfs4_recoverydir(void) static int nfsd4_check_legacy_client(struct nfs4_client *clp) { + struct nfs4_client_reclaim *crp; + /* did we already find that this client is stable? */ if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) return 0; /* look for it in the reclaim hashtable otherwise */ - if (nfsd4_find_reclaim_client(clp->cl_recdir)) { + crp = nfsd4_find_reclaim_client(clp->cl_recdir); + if (crp) { set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); + crp->cr_clp = clp; return 0; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 1c6f82e..559ab57 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4483,16 +4483,13 @@ alloc_reclaim(void) return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); } -int +bool nfs4_has_reclaimed_state(const char *name) { - unsigned int strhashval = clientstr_hashval(name); - struct nfs4_client *clp; + struct nfs4_client_reclaim *crp; - clp = find_confirmed_client_by_str(name, strhashval); - if (!clp) - return 0; - return test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); + crp = nfsd4_find_reclaim_client(name); + return (crp && crp->cr_clp); } /* @@ -4511,6 +4508,7 @@ nfs4_client_to_reclaim(const char *name) INIT_LIST_HEAD(&crp->cr_strhash); list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); memcpy(crp->cr_recdir, name, HEXDIR_LEN); + crp->cr_clp = NULL; reclaim_str_hashtbl_size++; } return crp; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 3f8b26b..cf9f7ba 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -304,6 +304,7 @@ is_client_expired(struct nfs4_client *clp) */ struct nfs4_client_reclaim { struct list_head cr_strhash; /* hash by cr_name */ + struct nfs4_client *cr_clp; /* pointer to associated clp */ char cr_recdir[HEXDIR_LEN]; /* recover dir */ }; @@ -464,7 +465,6 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net, stateid_t *stateid, int flags, struct file **filp); extern void nfs4_lock_state(void); extern void nfs4_unlock_state(void); -extern int nfs4_in_grace(void); void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *); extern void nfs4_release_reclaim(void); extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir); @@ -483,7 +483,7 @@ extern void nfsd4_shutdown_callback(struct nfs4_client *); extern void nfs4_put_delegation(struct nfs4_delegation *dp); extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name); -extern int nfs4_has_reclaimed_state(const char *name); +extern bool nfs4_has_reclaimed_state(const char *name); extern void release_session_client(struct nfsd4_session *); extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); -- cgit v0.10.2 From ac55fdc408039b425a2fa3cbcaed7444e5339f9a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:56 -0500 Subject: nfsd: move the confirmed and unconfirmed hlists to a rbtree The current code requires that we md5 hash the name in order to store the client in the confirmed and unconfirmed trees. Change it instead to store the clients in a pair of rbtrees, and simply compare the cl_names directly instead of hashing them. This also necessitates that we add a new flag to the clp->cl_flags field to indicate which tree the client is currently in. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 559ab57..99998a1 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -412,10 +412,10 @@ static unsigned int clientstr_hashval(const char *name) * reclaim_str_hashtbl[] holds known client info from previous reset/reboot * used in reboot/reset lease grace period processing * - * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed + * conf_id_hashtbl[], and conf_name_tree hold confirmed * setclientid_confirmed info. * - * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed + * unconf_id_hashtbl[] and unconf_name_tree hold unconfirmed * setclientid info. * * client_lru holds client queue ordered by nfs4_client.cl_time @@ -423,13 +423,15 @@ static unsigned int clientstr_hashval(const char *name) * * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time * for last close replay. + * + * All of the above fields are protected by the client_mutex. */ static struct list_head reclaim_str_hashtbl[CLIENT_HASH_SIZE]; static int reclaim_str_hashtbl_size = 0; static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; -static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE]; -static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE]; static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; +static struct rb_root conf_name_tree; +static struct rb_root unconf_name_tree; static struct list_head client_lru; static struct list_head close_lru; @@ -1144,7 +1146,10 @@ destroy_client(struct nfs4_client *clp) if (clp->cl_cb_conn.cb_xprt) svc_xprt_put(clp->cl_cb_conn.cb_xprt); list_del(&clp->cl_idhash); - list_del(&clp->cl_strhash); + if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) + rb_erase(&clp->cl_namenode, &conf_name_tree); + else + rb_erase(&clp->cl_namenode, &unconf_name_tree); spin_lock(&client_lock); unhash_client_locked(clp); if (atomic_read(&clp->cl_refcount) == 0) @@ -1187,6 +1192,17 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source) return 0; } +static long long +compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) +{ + long long res; + + res = o1->len - o2->len; + if (res) + return res; + return (long long)memcmp(o1->data, o2->data, o1->len); +} + static int same_name(const char *n1, const char *n2) { return 0 == memcmp(n1, n2, HEXDIR_LEN); @@ -1307,7 +1323,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, atomic_set(&clp->cl_refcount, 0); clp->cl_cb_state = NFSD4_CB_UNKNOWN; INIT_LIST_HEAD(&clp->cl_idhash); - INIT_LIST_HEAD(&clp->cl_strhash); INIT_LIST_HEAD(&clp->cl_openowners); INIT_LIST_HEAD(&clp->cl_delegations); INIT_LIST_HEAD(&clp->cl_lru); @@ -1325,11 +1340,52 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, } static void -add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) +add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) +{ + struct rb_node **new = &(root->rb_node), *parent = NULL; + struct nfs4_client *clp; + + while (*new) { + clp = rb_entry(*new, struct nfs4_client, cl_namenode); + parent = *new; + + if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) + new = &((*new)->rb_left); + else + new = &((*new)->rb_right); + } + + rb_link_node(&new_clp->cl_namenode, parent, new); + rb_insert_color(&new_clp->cl_namenode, root); +} + +static struct nfs4_client * +find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) +{ + long long cmp; + struct rb_node *node = root->rb_node; + struct nfs4_client *clp; + + while (node) { + clp = rb_entry(node, struct nfs4_client, cl_namenode); + cmp = compare_blob(&clp->cl_name, name); + if (cmp > 0) + node = node->rb_left; + else if (cmp < 0) + node = node->rb_right; + else + return clp; + } + return NULL; +} + +static void +add_to_unconfirmed(struct nfs4_client *clp) { unsigned int idhashval; - list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); + clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); + add_clp_to_name_tree(clp, &unconf_name_tree); idhashval = clientid_hashval(clp->cl_clientid.cl_id); list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); renew_client(clp); @@ -1339,12 +1395,12 @@ static void move_to_confirmed(struct nfs4_client *clp) { unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); - unsigned int strhashval; dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); - strhashval = clientstr_hashval(clp->cl_recdir); - list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); + rb_erase(&clp->cl_namenode, &unconf_name_tree); + add_clp_to_name_tree(clp, &conf_name_tree); + set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); renew_client(clp); } @@ -1387,27 +1443,15 @@ static bool clp_used_exchangeid(struct nfs4_client *clp) } static struct nfs4_client * -find_confirmed_client_by_str(const char *dname, unsigned int hashval) +find_confirmed_client_by_name(struct xdr_netobj *name) { - struct nfs4_client *clp; - - list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { - if (same_name(clp->cl_recdir, dname)) - return clp; - } - return NULL; + return find_clp_in_name_tree(name, &conf_name_tree); } static struct nfs4_client * -find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) +find_unconfirmed_client_by_name(struct xdr_netobj *name) { - struct nfs4_client *clp; - - list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { - if (same_name(clp->cl_recdir, dname)) - return clp; - } - return NULL; + return find_clp_in_name_tree(name, &unconf_name_tree); } static void @@ -1572,7 +1616,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, { struct nfs4_client *unconf, *conf, *new; __be32 status; - unsigned int strhashval; char dname[HEXDIR_LEN]; char addr_str[INET6_ADDRSTRLEN]; nfs4_verifier verf = exid->verifier; @@ -1605,11 +1648,9 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, if (status) return status; - strhashval = clientstr_hashval(dname); - /* Cases below refer to rfc 5661 section 18.35.4: */ nfs4_lock_state(); - conf = find_confirmed_client_by_str(dname, strhashval); + conf = find_confirmed_client_by_name(&exid->clname); if (conf) { bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); bool verfs_match = same_verf(&verf, &conf->cl_verifier); @@ -1654,7 +1695,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, goto out; } - unconf = find_unconfirmed_client_by_str(dname, strhashval); + unconf = find_unconfirmed_client_by_name(&exid->clname); if (unconf) /* case 4, possible retry or client restart */ expire_client(unconf); @@ -1668,7 +1709,7 @@ out_new: new->cl_minorversion = 1; gen_clid(new); - add_to_unconfirmed(new, strhashval); + add_to_unconfirmed(new); out_copy: exid->clientid.cl_boot = new->cl_clientid.cl_boot; exid->clientid.cl_id = new->cl_clientid.cl_id; @@ -1789,7 +1830,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, goto out_free_conn; } } else if (unconf) { - unsigned int hash; struct nfs4_client *old; if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { @@ -1803,8 +1843,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, status = nfserr_seq_misordered; goto out_free_conn; } - hash = clientstr_hashval(unconf->cl_recdir); - old = find_confirmed_client_by_str(unconf->cl_recdir, hash); + old = find_confirmed_client_by_name(&unconf->cl_name); if (old) expire_client(old); move_to_confirmed(unconf); @@ -2195,7 +2234,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, { struct xdr_netobj clname = setclid->se_name; nfs4_verifier clverifier = setclid->se_verf; - unsigned int strhashval; struct nfs4_client *conf, *unconf, *new; __be32 status; char dname[HEXDIR_LEN]; @@ -2204,11 +2242,9 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (status) return status; - strhashval = clientstr_hashval(dname); - /* Cases below refer to rfc 3530 section 14.2.33: */ nfs4_lock_state(); - conf = find_confirmed_client_by_str(dname, strhashval); + conf = find_confirmed_client_by_name(&clname); if (conf) { /* case 0: */ status = nfserr_clid_inuse; @@ -2223,7 +2259,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; } } - unconf = find_unconfirmed_client_by_str(dname, strhashval); + unconf = find_unconfirmed_client_by_name(&clname); if (unconf) expire_client(unconf); status = nfserr_jukebox; @@ -2237,7 +2273,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, gen_clid(new); new->cl_minorversion = 0; gen_callback(new, setclid, rqstp); - add_to_unconfirmed(new, strhashval); + add_to_unconfirmed(new); setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; setclid->se_clientid.cl_id = new->cl_clientid.cl_id; memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); @@ -2290,9 +2326,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, nfsd4_probe_callback(conf); expire_client(unconf); } else { /* case 3: normal case; new or rebooted client */ - unsigned int hash = clientstr_hashval(unconf->cl_recdir); - - conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); + conf = find_confirmed_client_by_name(&unconf->cl_name); if (conf) expire_client(conf); move_to_confirmed(unconf); @@ -4706,11 +4740,11 @@ nfs4_state_init(void) for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&conf_id_hashtbl[i]); - INIT_LIST_HEAD(&conf_str_hashtbl[i]); - INIT_LIST_HEAD(&unconf_str_hashtbl[i]); INIT_LIST_HEAD(&unconf_id_hashtbl[i]); INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); } + conf_name_tree = RB_ROOT; + unconf_name_tree = RB_ROOT; for (i = 0; i < SESSION_HASH_SIZE; i++) INIT_LIST_HEAD(&sessionid_hashtbl[i]); for (i = 0; i < FILE_HASH_SIZE; i++) { @@ -4795,6 +4829,7 @@ out_recovery: return ret; } +/* should be called with the state lock held */ static void __nfs4_state_shutdown(void) { @@ -4802,17 +4837,24 @@ __nfs4_state_shutdown(void) struct nfs4_client *clp = NULL; struct nfs4_delegation *dp = NULL; struct list_head *pos, *next, reaplist; + struct rb_node *node, *tmp; for (i = 0; i < CLIENT_HASH_SIZE; i++) { while (!list_empty(&conf_id_hashtbl[i])) { clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); destroy_client(clp); } - while (!list_empty(&unconf_str_hashtbl[i])) { - clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash); - destroy_client(clp); - } } + + node = rb_first(&unconf_name_tree); + while (node != NULL) { + tmp = node; + node = rb_next(tmp); + clp = rb_entry(tmp, struct nfs4_client, cl_namenode); + rb_erase(tmp, &unconf_name_tree); + destroy_client(clp); + } + INIT_LIST_HEAD(&reaplist); spin_lock(&recall_lock); list_for_each_safe(pos, next, &del_recall_lru) { diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index cf9f7ba..6c342bd 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -232,7 +232,7 @@ struct nfsd4_sessionid { */ struct nfs4_client { struct list_head cl_idhash; /* hash by cl_clientid.id */ - struct list_head cl_strhash; /* hash by cl_name */ + struct rb_node cl_namenode; /* link into by-name trees */ struct list_head cl_openowners; struct idr cl_stateids; /* stateid lookup */ struct list_head cl_delegations; @@ -253,6 +253,7 @@ struct nfs4_client { #define NFSD4_CLIENT_CB_KILL (1) #define NFSD4_CLIENT_STABLE (2) /* client on stable storage */ #define NFSD4_CLIENT_RECLAIM_COMPLETE (3) /* reclaim_complete done */ +#define NFSD4_CLIENT_CONFIRMED (4) /* client is confirmed */ #define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \ 1 << NFSD4_CLIENT_CB_KILL) unsigned long cl_flags; -- cgit v0.10.2 From 2216d449a97927cc105912e337d169cd4d4db548 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:57 -0500 Subject: nfsd: get rid of cl_recdir field Remove the cl_recdir field from the nfs4_client struct. Instead, just compute it on the fly when and if it's needed, which is now only when the legacy client tracking code is in effect. The error handling in the legacy client tracker is also changed to handle the case where md5 is unavailable. In that case, we'll warn the admin with a KERN_ERR message and disable the client tracking. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 3048c01..80e77cc 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -103,33 +103,39 @@ md5_to_hex(char *out, char *md5) *out = '\0'; } -__be32 -nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) +static int +nfs4_make_rec_clidname(char *dname, const struct xdr_netobj *clname) { struct xdr_netobj cksum; struct hash_desc desc; struct scatterlist sg; - __be32 status = nfserr_jukebox; + int status; dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", clname->len, clname->data); desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(desc.tfm)) + if (IS_ERR(desc.tfm)) { + status = PTR_ERR(desc.tfm); goto out_no_tfm; + } + cksum.len = crypto_hash_digestsize(desc.tfm); cksum.data = kmalloc(cksum.len, GFP_KERNEL); - if (cksum.data == NULL) + if (cksum.data == NULL) { + status = -ENOMEM; goto out; + } sg_init_one(&sg, clname->data, clname->len); - if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data)) + status = crypto_hash_digest(&desc, &sg, sg.length, cksum.data); + if (status) goto out; md5_to_hex(dname, cksum.data); - status = nfs_ok; + status = 0; out: kfree(cksum.data); crypto_free_hash(desc.tfm); @@ -137,11 +143,36 @@ out_no_tfm: return status; } +/* + * If we had an error generating the recdir name for the legacy tracker + * then warn the admin. If the error doesn't appear to be transient, + * then disable recovery tracking. + */ +static void +legacy_recdir_name_error(int error) +{ + printk(KERN_ERR "NFSD: unable to generate recoverydir " + "name (%d).\n", error); + + /* + * if the algorithm just doesn't exist, then disable the recovery + * tracker altogether. The crypto libs will generally return this if + * FIPS is enabled as well. + */ + if (error == -ENOENT) { + printk(KERN_ERR "NFSD: disabling legacy clientid tracking. " + "Reboot recovery will not function correctly!\n"); + + /* the argument is ignored by the legacy exit function */ + nfsd4_client_tracking_exit(NULL); + } +} + static void nfsd4_create_clid_dir(struct nfs4_client *clp) { const struct cred *original_cred; - char *dname = clp->cl_recdir; + char dname[HEXDIR_LEN]; struct dentry *dir, *dentry; struct nfs4_client_reclaim *crp; int status; @@ -152,6 +183,11 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) return; if (!rec_file) return; + + status = nfs4_make_rec_clidname(dname, &clp->cl_name); + if (status) + return legacy_recdir_name_error(status); + status = nfs4_save_creds(&original_cred); if (status < 0) return; @@ -186,7 +222,7 @@ out_unlock: mutex_unlock(&dir->d_inode->i_mutex); if (status == 0) { if (in_grace) { - crp = nfs4_client_to_reclaim(clp->cl_recdir); + crp = nfs4_client_to_reclaim(dname); if (crp) crp->cr_clp = clp; } @@ -298,11 +334,16 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) { const struct cred *original_cred; struct nfs4_client_reclaim *crp; + char dname[HEXDIR_LEN]; int status; if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) return; + status = nfs4_make_rec_clidname(dname, &clp->cl_name); + if (status) + return legacy_recdir_name_error(status); + status = mnt_want_write_file(rec_file); if (status) goto out; @@ -312,13 +353,13 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) if (status < 0) goto out_drop_write; - status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); + status = nfsd4_unlink_clid_dir(dname, HEXDIR_LEN-1); nfs4_reset_creds(original_cred); if (status == 0) { vfs_fsync(rec_file, 0); if (in_grace) { /* remove reclaim record */ - crp = nfsd4_find_reclaim_client(clp->cl_recdir); + crp = nfsd4_find_reclaim_client(dname); if (crp) nfs4_remove_reclaim_record(crp); } @@ -328,7 +369,7 @@ out_drop_write: out: if (status) printk("NFSD: Failed to remove expired client state directory" - " %.*s\n", HEXDIR_LEN, clp->cl_recdir); + " %.*s\n", HEXDIR_LEN, dname); } static int @@ -500,14 +541,22 @@ nfs4_recoverydir(void) static int nfsd4_check_legacy_client(struct nfs4_client *clp) { + int status; + char dname[HEXDIR_LEN]; struct nfs4_client_reclaim *crp; /* did we already find that this client is stable? */ if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) return 0; + status = nfs4_make_rec_clidname(dname, &clp->cl_name); + if (status) { + legacy_recdir_name_error(status); + return status; + } + /* look for it in the reclaim hashtable otherwise */ - crp = nfsd4_find_reclaim_client(clp->cl_recdir); + crp = nfsd4_find_reclaim_client(dname); if (crp) { set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); crp->cr_clp = clp; @@ -993,7 +1042,7 @@ nfsd4_cltrack_legacy_topdir(void) } static char * -nfsd4_cltrack_legacy_recdir(const char *recdir) +nfsd4_cltrack_legacy_recdir(const struct xdr_netobj *name) { int copied; size_t len; @@ -1010,10 +1059,16 @@ nfsd4_cltrack_legacy_recdir(const char *recdir) if (!result) return result; - copied = snprintf(result, len, LEGACY_RECDIR_ENV_PREFIX "%s/%s", - nfs4_recoverydir(), recdir); - if (copied >= len) { - /* just return nothing if output was truncated */ + copied = snprintf(result, len, LEGACY_RECDIR_ENV_PREFIX "%s/", + nfs4_recoverydir()); + if (copied > (len - HEXDIR_LEN)) { + /* just return nothing if output will be truncated */ + kfree(result); + return NULL; + } + + copied = nfs4_make_rec_clidname(result + copied, name); + if (copied) { kfree(result); return NULL; } @@ -1126,7 +1181,7 @@ nfsd4_umh_cltrack_check(struct nfs4_client *clp) dprintk("%s: can't allocate memory for upcall!\n", __func__); return -ENOMEM; } - legacy = nfsd4_cltrack_legacy_recdir(clp->cl_recdir); + legacy = nfsd4_cltrack_legacy_recdir(&clp->cl_name); ret = nfsd4_umh_cltrack_upcall("check", hexid, legacy); kfree(legacy); kfree(hexid); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 99998a1..37b19f7 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1299,7 +1299,7 @@ static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t return NULL; } -static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, +static struct nfs4_client *create_client(struct xdr_netobj name, struct svc_rqst *rqstp, nfs4_verifier *verf) { struct nfs4_client *clp; @@ -1319,7 +1319,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, return NULL; } idr_init(&clp->cl_stateids); - memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); atomic_set(&clp->cl_refcount, 0); clp->cl_cb_state = NFSD4_CB_UNKNOWN; INIT_LIST_HEAD(&clp->cl_idhash); @@ -1616,7 +1615,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, { struct nfs4_client *unconf, *conf, *new; __be32 status; - char dname[HEXDIR_LEN]; char addr_str[INET6_ADDRSTRLEN]; nfs4_verifier verf = exid->verifier; struct sockaddr *sa = svc_addr(rqstp); @@ -1643,11 +1641,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, return nfserr_serverfault; /* no excuse :-/ */ } - status = nfs4_make_rec_clidname(dname, &exid->clname); - - if (status) - return status; - /* Cases below refer to rfc 5661 section 18.35.4: */ nfs4_lock_state(); conf = find_confirmed_client_by_name(&exid->clname); @@ -1701,7 +1694,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, /* case 1 (normal case) */ out_new: - new = create_client(exid->clname, dname, rqstp, &verf); + new = create_client(exid->clname, rqstp, &verf); if (new == NULL) { status = nfserr_jukebox; goto out; @@ -2236,12 +2229,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfs4_verifier clverifier = setclid->se_verf; struct nfs4_client *conf, *unconf, *new; __be32 status; - char dname[HEXDIR_LEN]; - status = nfs4_make_rec_clidname(dname, &clname); - if (status) - return status; - /* Cases below refer to rfc 3530 section 14.2.33: */ nfs4_lock_state(); conf = find_confirmed_client_by_name(&clname); @@ -2263,7 +2251,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (unconf) expire_client(unconf); status = nfserr_jukebox; - new = create_client(clname, dname, rqstp, &clverifier); + new = create_client(clname, rqstp, &clverifier); if (new == NULL) goto out; if (conf && same_verf(&conf->cl_verifier, &clverifier)) diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 6c342bd..029217a 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -238,7 +238,6 @@ struct nfs4_client { struct list_head cl_delegations; struct list_head cl_lru; /* tail queue */ struct xdr_netobj cl_name; /* id generated by client */ - char cl_recdir[HEXDIR_LEN]; /* recovery dir */ nfs4_verifier cl_verifier; /* generated by client */ time_t cl_time; /* time of last lease renewal */ struct sockaddr_storage cl_addr; /* client ipaddress */ @@ -482,7 +481,6 @@ extern int nfsd4_create_callback_queue(void); extern void nfsd4_destroy_callback_queue(void); extern void nfsd4_shutdown_callback(struct nfs4_client *); extern void nfs4_put_delegation(struct nfs4_delegation *dp); -extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name); extern bool nfs4_has_reclaimed_state(const char *name); extern void release_session_client(struct nfsd4_session *); -- cgit v0.10.2 From 7e4f015d815d04d888d434889dd3bbb4c210511a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 12 Nov 2012 15:00:58 -0500 Subject: nfsd: release the legacy reclaimable clients list in grace_done The current code holds on to this list until nfsd is shut down, but it's never touched once the grace period ends. Release that memory back into the wild when the grace period ends. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 80e77cc..b03b6aa 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -404,6 +404,7 @@ nfsd4_recdir_purge_old(struct net *net, time_t boot_time) vfs_fsync(rec_file, 0); mnt_drop_write_file(rec_file); out: + nfs4_release_reclaim(); if (status) printk("nfsd4: failed to purge old clients from recovery" " directory %s\n", rec_file->f_path.dentry->d_name.name); -- cgit v0.10.2 From b53f4baf8b26303fc75ef3b00cf5e7398b58efd4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 10 Oct 2012 23:32:36 -0700 Subject: i2c: rcar: used devm_request_and_ioremap() instead of devm_ioremap() Signed-off-by: Kuninori Morimoto Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index f9399d1..2bce56d 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -642,7 +642,7 @@ static int __devinit rcar_i2c_probe(struct platform_device *pdev) if (ret < 0) return ret; - priv->io = devm_ioremap(dev, res->start, resource_size(res)); + priv->io = devm_request_and_ioremap(dev, res); if (!priv->io) { dev_err(dev, "cannot ioremap\n"); return -ENODEV; -- cgit v0.10.2 From 45fd5e4ad2052101b4ceda5fdf4b003c428ebdfc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 13 Nov 2012 11:24:15 +0100 Subject: i2c: rcar: fix section mismatch Give the driver struct a name according to the 'standard' to fix: WARNING: vmlinux.o(.data+0x11798): Section mismatch in reference from the variable rcar_i2c_drv to the function .devinit.text:rcar_i2c_probe() ... WARNING: vmlinux.o(.data+0x1179c): Section mismatch in reference from the variable rcar_i2c_drv to the function .devexit.text:rcar_i2c_remove() Reported-by: Simon Horman Signed-off-by: Wolfram Sang Cc: Kuninori Morimoto diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 2bce56d..72a8071 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -693,7 +693,7 @@ static int __devexit rcar_i2c_remove(struct platform_device *pdev) return 0; } -static struct platform_driver rcar_i2c_drv = { +static struct platform_driver rcar_i2c_driver = { .driver = { .name = "i2c-rcar", .owner = THIS_MODULE, @@ -702,7 +702,7 @@ static struct platform_driver rcar_i2c_drv = { .remove = __devexit_p(rcar_i2c_remove), }; -module_platform_driver(rcar_i2c_drv); +module_platform_driver(rcar_i2c_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Renesas R-Car I2C bus driver"); -- cgit v0.10.2 From 970d494c323826d8bb21e8ed1796da15082808ec Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 8 Aug 2012 08:54:32 +0200 Subject: i2c: ocores: Use devm_request_and_ioremap() Replacing the devm_request_mem_region() and devm_ioremap_nocache() calls by a single call to devm_request_and_ioremap() simplifies the code. Signed-off-by: Thierry Reding Acked-by: Jean Delvare Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index bffd550..1fad4ae 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -283,18 +283,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "Memory region busy\n"); - return -EBUSY; - } - - i2c->base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - if (!i2c->base) { - dev_err(&pdev->dev, "Unable to map registers\n"); - return -EIO; - } + i2c->base = devm_request_and_ioremap(&pdev->dev, res); + if (!i2c->base) + return -EADDRNOTAVAIL; pdata = pdev->dev.platform_data; if (pdata) { -- cgit v0.10.2 From 58a7371a4dd9d03f77265ee2784781fc39096136 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Mon, 15 Oct 2012 15:51:17 +0800 Subject: i2c: i2c-gpio: fix name issue with multiple i2c gpio nodes When having multiple i2c-gpio nodes, the name for each is same. So add the patch to fix it. The adap->name printing information was added by myself without this patch the log information is as following ---<8--- adap->name = i2c-gpio-1 i2c-gpio i2c.2: using pins 30 (SDA) and 31 (SCL) adap->name = i2c-gpio-1 i2c-gpio i2c.3: using pins 64 (SDA) and 65 (SCL) --->8--- with this patch, the log information is as following ---<8--- adap->name = i2c.2 i2c-gpio i2c.2: using pins 30 (SDA) and 31 (SCL) adap->name = i2c.3 i2c-gpio i2c.3: using pins 64 (SDA) and 65 (SCL) --->8--- Signed-off-by: Bo Shen Reviewed-by: Stephen Warren [wsa: minor fixes to the commit mesage] Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index e62d2d9..257299a 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -184,7 +184,11 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev) bit_data->data = pdata; adap->owner = THIS_MODULE; - snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); + if (pdev->dev.of_node) + strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); + else + snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); + adap->algo_data = bit_data; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->dev.parent = &pdev->dev; -- cgit v0.10.2 From 7c3fe64d133fbe4132d9966cd2f79a7193f13139 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 13 Nov 2012 16:43:21 +0100 Subject: i2c: at91: fix SMBus quick command The driver claims to support SMBus quick command but it was not the case. This patch fixes this issue. Without it, i2cdetect finds imaginary devices. And with some IP versions, trying to send 0 byte can cause issue when writing data to an EEPROM. Signed-off-by: Ludovic Desroches Acked-by: Jean-Christophe PLAGNIOL-VILLARD [wsa: improved the commit message] Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index aa59a25..c02bf20 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -39,6 +39,7 @@ #define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */ #define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */ #define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */ +#define AT91_TWI_QUICK 0x0040 /* SMBus quick command */ #define AT91_TWI_SWRST 0x0080 /* Software Reset */ #define AT91_TWI_MMR 0x0004 /* Master Mode Register */ @@ -212,7 +213,11 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) INIT_COMPLETION(dev->cmd_complete); dev->transfer_status = 0; - if (dev->msg->flags & I2C_M_RD) { + + if (!dev->buf_len) { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK); + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); + } else if (dev->msg->flags & I2C_M_RD) { unsigned start_flags = AT91_TWI_START; if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { -- cgit v0.10.2 From 49839dc93970789cea46f5171cd7f6ec11af64c7 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 6 Nov 2012 16:31:32 +0000 Subject: Revert "ARM: OMAP: convert I2C driver to PM QoS for MPU latency constraints" This reverts commit 3db11feffc1ad2ab9dea27789e6b5b3032827adc (ARM: OMAP: convert I2C driver to PM QoS for MPU latency constraints). This commit causes I2C timeouts to appear on several OMAP3430/3530-based boards: http://marc.info/?l=linux-arm-kernel&m=135071372426971&w=2 http://marc.info/?l=linux-arm-kernel&m=135067558415214&w=2 http://marc.info/?l=linux-arm-kernel&m=135216013608196&w=2 and appears to have been sent for merging before one of its prerequisites was merged: http://marc.info/?l=linux-arm-kernel&m=135219411617621&w=2 Signed-off-by: Paul Walmsley Acked-by: Jean Pihet Signed-off-by: Wolfram Sang diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index a5683a8..6013831 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -26,12 +26,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #define OMAP_I2C_SIZE 0x3f @@ -127,6 +129,16 @@ static inline int omap1_i2c_add_bus(int bus_id) #ifdef CONFIG_ARCH_OMAP2PLUS +/* + * XXX This function is a temporary compatibility wrapper - only + * needed until the I2C driver can be converted to call + * omap_pm_set_max_dev_wakeup_lat() and handle a return code. + */ +static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t) +{ + omap_pm_set_max_mpu_wakeup_lat(dev, t); +} + static inline int omap2_i2c_add_bus(int bus_id) { int l; @@ -158,6 +170,15 @@ static inline int omap2_i2c_add_bus(int bus_id) dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr; pdata->flags = dev_attr->flags; + /* + * When waiting for completion of a i2c transfer, we need to + * set a wake up latency constraint for the MPU. This is to + * ensure quick enough wakeup from idle, when transfer + * completes. + * Only omap3 has support for constraints + */ + if (cpu_is_omap34xx()) + pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(struct omap_i2c_bus_platform_data), NULL, 0, 0); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index db31eae..0b02543 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,7 +43,6 @@ #include #include #include -#include /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -187,8 +186,9 @@ struct omap_i2c_dev { int reg_shift; /* bit shift for I2C register addresses */ struct completion cmd_complete; struct resource *ioarea; - u32 latency; /* maximum MPU wkup latency */ - struct pm_qos_request pm_qos_request; + u32 latency; /* maximum mpu wkup latency */ + void (*set_mpu_wkup_lat)(struct device *dev, + long latency); u32 speed; /* Speed of bus in kHz */ u32 dtrev; /* extra revision from DT */ u32 flags; @@ -494,7 +494,9 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8); + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->threshold) / + (1000 * dev->speed / 8); } /* @@ -629,16 +631,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r < 0) goto out; - /* - * When waiting for completion of a i2c transfer, we need to - * set a wake up latency constraint for the MPU. This is to - * ensure quick enough wakeup from idle, when transfer - * completes. - */ - if (dev->latency) - pm_qos_add_request(&dev->pm_qos_request, - PM_QOS_CPU_DMA_LATENCY, - dev->latency); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); @@ -646,8 +640,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) break; } - if (dev->latency) - pm_qos_remove_request(&dev->pm_qos_request); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, -1); if (r == 0) r = num; @@ -1104,6 +1098,7 @@ omap_i2c_probe(struct platform_device *pdev) } else if (pdata != NULL) { dev->speed = pdata->clkrate; dev->flags = pdata->flags; + dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; dev->dtrev = pdata->rev; } @@ -1159,8 +1154,9 @@ omap_i2c_probe(struct platform_device *pdev) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - dev->latency = (1000000 * dev->fifo_size) / - (1000 * dev->speed / 8); + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->fifo_size) / + (1000 * dev->speed / 8); } /* reset ASAP, clearing any IRQs */ diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index df804ba..92a0dc7 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -34,6 +34,7 @@ struct omap_i2c_bus_platform_data { u32 clkrate; u32 rev; u32 flags; + void (*set_mpu_wkup_lat)(struct device *dev, long set); }; #endif -- cgit v0.10.2 From 135ae8270d233067c8be426e2a59d0733ba74723 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Sat, 10 Nov 2012 07:20:25 -0500 Subject: nfsd4: init_session should be declared static Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 37b19f7..7de9ba0 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -947,7 +947,7 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) return new; } -void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) +static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) { int idx; -- cgit v0.10.2 From 2b4cf668a7b8f84182a35f07152d8b6f012629d2 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Tue, 13 Nov 2012 15:41:27 -0500 Subject: nfsd4: get_backchannel_cred should be static Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 7bb187a..9968470 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -642,7 +642,7 @@ int set_callback_cred(void) return 0; } -struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses) +static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses) { if (clp->cl_minorversion == 0) { return get_rpccred(callback_cred); -- cgit v0.10.2 From 5383116b86d8e877684770d05acd1dda62be102d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 5 Nov 2012 10:32:55 -0800 Subject: Input: marix-keymap - automatically allocate memory for keymap In device tree enabled setups requiring preallocated memory for storing keymap is quite often awkward, so let's provide an option of allocating it directly in matrix_keypad_build_keymap(). Reviewed-by: Alban Bedel Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c index 443ad64b..419cb6b 100644 --- a/drivers/input/matrix-keymap.c +++ b/drivers/input/matrix-keymap.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -122,6 +123,11 @@ static int matrix_keypad_parse_of_keymap(const char *propname, * it will attempt load the keymap from property specified by @keymap_name * argument (or "linux,keymap" if @keymap_name is %NULL). * + * If @keymap is %NULL the function will automatically allocate managed + * block of memory to store the keymap. This memory will be associated with + * the parent device and automatically freed when device unbinds from the + * driver. + * * Callers are expected to set up input_dev->dev.parent before calling this * function. */ @@ -132,12 +138,27 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, struct input_dev *input_dev) { unsigned int row_shift = get_count_order(cols); + size_t max_keys = rows << row_shift; int i; int error; + if (WARN_ON(!input_dev->dev.parent)) + return -EINVAL; + + if (!keymap) { + keymap = devm_kzalloc(input_dev->dev.parent, + max_keys * sizeof(*keymap), + GFP_KERNEL); + if (!keymap) { + dev_err(input_dev->dev.parent, + "Unable to allocate memory for keymap"); + return -ENOMEM; + } + } + input_dev->keycode = keymap; input_dev->keycodesize = sizeof(*keymap); - input_dev->keycodemax = rows << row_shift; + input_dev->keycodemax = max_keys; __set_bit(EV_KEY, input_dev->evbit); -- cgit v0.10.2 From d60ece5f010043422c5fbc3609714c4420c7c9bf Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 14 Nov 2012 16:22:45 +0200 Subject: i2c: omap: ensure writes to dev->buf_len are ordered if we allow compiler reorder our writes, we could fall into a situation where dev->buf_len is reset for no apparent reason. This bug was found with a simple script which would transfer data to an i2c client from 1 to 1024 bytes (a simple for loop), when we got to transfer sizes bigger than the fifo size, dev->buf_len was reset to zero before we had an oportunity to handle XDR Interrupt. Because dev->buf_len was zero, we entered omap_i2c_transmit_data() to transfer zero bytes, which would mean we would just silently exit omap_i2c_transmit_data() without actually writing anything to DATA register. That would cause XDR IRQ to trigger forever and we would never transfer the remaining bytes. After adding the memory barrier, we also drop resetting dev->buf_len to zero in omap_i2c_xfer_msg() because both omap_i2c_transmit_data() and omap_i2c_receive_data() will act until dev->buf_len reaches zero, rendering the other write in omap_i2c_xfer_msg() redundant. This patch has been tested with pandaboard for a few iterations of the script mentioned above. Signed-off-by: Felipe Balbi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0b02543..3525c9e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -524,6 +524,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, dev->buf = msg->buf; dev->buf_len = msg->len; + /* make sure writes to dev->buf_len are ordered */ + barrier(); + omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len); /* Clear the FIFO Buffers */ @@ -581,7 +584,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, */ timeout = wait_for_completion_timeout(&dev->cmd_complete, OMAP_I2C_TIMEOUT); - dev->buf_len = 0; if (timeout == 0) { dev_err(dev->dev, "controller timed out\n"); omap_i2c_init(dev); -- cgit v0.10.2 From 2d4b4520a5eaed6701b0c9f7540c8fd99a26e449 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Tue, 16 Oct 2012 15:23:20 +0000 Subject: i2c: omap: adopt pinctrl support Some GPIO expanders need some early pin control muxing. Due to legacy boards sometimes the driver uses subsys_initcall instead of module_init. This patch takes advantage of defer probe feature and pin control in order to wait until pin control probing before GPIO driver probing. It has been tested on OMAP5 board with TCA6424 driver. Signed-off-by: Sebastien Guiriec Acked-by: Shubhrajyoti D Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 3525c9e..16afb28 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,6 +43,7 @@ #include #include #include +#include /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -213,6 +214,8 @@ struct omap_i2c_dev { u16 syscstate; u16 westate; u16 errata; + + struct pinctrl *pins; }; static const u8 reg_map_ip_v1[] = { @@ -1104,6 +1107,16 @@ omap_i2c_probe(struct platform_device *pdev) dev->dtrev = pdata->rev; } + dev->pins = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(dev->pins)) { + if (PTR_ERR(dev->pins) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_warn(&pdev->dev, "did not get pins for i2c error: %li\n", + PTR_ERR(dev->pins)); + dev->pins = NULL; + } + dev->dev = &pdev->dev; dev->irq = irq; -- cgit v0.10.2 From 47dcd0161a0b37bf0299473585fc5030d3f45b64 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:36 +0530 Subject: i2c: omap: Fix the revision register read The revision register on OMAP4 is a 16-bit lo and a 16-bit hi. Currently the driver reads only the lower 8-bits. Fix the same by preventing the truncating of the rev register for OMAP4. Also use the scheme bit ie bit-14 of the hi register to know if it is OMAP_I2C_IP_VERSION_2. On platforms previous to OMAP4 the offset 0x04 is IE register whose bit-14 reset value is 0, the code uses the same to its advantage. Also since the omap_i2c_read_reg uses reg_map_ip_* a raw_readw is done to fetch the revision register. The dev->regs is populated after reading the rev_hi. A NULL check has been added in the resume handler to prevent the access before the setting of the regs. Signed-off-by: Shubhrajyoti D Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 16afb28..bf0569e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -49,9 +49,10 @@ #define OMAP_I2C_OMAP1_REV_2 0x20 /* I2C controller revisions present on specific hardware */ -#define OMAP_I2C_REV_ON_2430 0x36 -#define OMAP_I2C_REV_ON_3430_3530 0x3C -#define OMAP_I2C_REV_ON_3630_4430 0x40 +#define OMAP_I2C_REV_ON_2430 0x00000036 +#define OMAP_I2C_REV_ON_3430_3530 0x0000003C +#define OMAP_I2C_REV_ON_3630 0x00000040 +#define OMAP_I2C_REV_ON_4430_PLUS 0x50400002 /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) @@ -203,7 +204,7 @@ struct omap_i2c_dev { * fifo_size==0 implies no fifo * if set, should be trsh+1 */ - u8 rev; + u32 rev; unsigned b_hw:1; /* bad h/w fixes */ unsigned receiver:1; /* true when we're in receiver mode */ u16 iestate; /* Saved interrupt register */ @@ -493,7 +494,7 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); - if (dev->rev < OMAP_I2C_REV_ON_3630_4430) + if (dev->rev < OMAP_I2C_REV_ON_3630) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ @@ -1051,6 +1052,16 @@ static const struct of_device_id omap_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, omap_i2c_of_match); #endif +#define OMAP_I2C_SCHEME(rev) ((rev & 0xc000) >> 14) + +#define OMAP_I2C_REV_SCHEME_0_MAJOR(rev) (rev >> 4) +#define OMAP_I2C_REV_SCHEME_0_MINOR(rev) (rev & 0xf) + +#define OMAP_I2C_REV_SCHEME_1_MAJOR(rev) ((rev & 0x0700) >> 7) +#define OMAP_I2C_REV_SCHEME_1_MINOR(rev) (rev & 0x1f) +#define OMAP_I2C_SCHEME_0 0 +#define OMAP_I2C_SCHEME_1 1 + static int __devinit omap_i2c_probe(struct platform_device *pdev) { @@ -1063,6 +1074,8 @@ omap_i2c_probe(struct platform_device *pdev) const struct of_device_id *match; int irq; int r; + u32 rev; + u16 minor, major; /* NOTE: driver uses the static register mapping */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1127,11 +1140,6 @@ omap_i2c_probe(struct platform_device *pdev) dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; - if (dev->dtrev == OMAP_I2C_IP_VERSION_2) - dev->regs = (u8 *)reg_map_ip_v2; - else - dev->regs = (u8 *)reg_map_ip_v1; - pm_runtime_enable(dev->dev); pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT); pm_runtime_use_autosuspend(dev->dev); @@ -1140,7 +1148,31 @@ omap_i2c_probe(struct platform_device *pdev) if (IS_ERR_VALUE(r)) goto err_free_mem; - dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff; + /* + * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2. + * On omap1/3/2 Offset 4 is IE Reg the bit [15:14] is 0 at reset. + * Also since the omap_i2c_read_reg uses reg_map_ip_* a + * raw_readw is done. + */ + rev = __raw_readw(dev->base + 0x04); + + switch (OMAP_I2C_SCHEME(rev)) { + case OMAP_I2C_SCHEME_0: + dev->regs = (u8 *)reg_map_ip_v1; + dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG); + minor = OMAP_I2C_REV_SCHEME_0_MAJOR(dev->rev); + major = OMAP_I2C_REV_SCHEME_0_MAJOR(dev->rev); + break; + case OMAP_I2C_SCHEME_1: + /* FALLTHROUGH */ + default: + dev->regs = (u8 *)reg_map_ip_v2; + rev = (rev << 16) | + omap_i2c_read_reg(dev, OMAP_I2C_IP_V2_REVNB_LO); + minor = OMAP_I2C_REV_SCHEME_1_MINOR(rev); + major = OMAP_I2C_REV_SCHEME_1_MAJOR(rev); + dev->rev = rev; + } dev->errata = 0; @@ -1165,7 +1197,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev < OMAP_I2C_REV_ON_3630_4430) + if (dev->rev < OMAP_I2C_REV_ON_3630) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ @@ -1209,7 +1241,7 @@ omap_i2c_probe(struct platform_device *pdev) } dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr, - dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); + dev->dtrev, major, minor, dev->speed); of_i2c_register_devices(adap); @@ -1275,6 +1307,9 @@ static int omap_i2c_runtime_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); + if (!_dev->regs) + return 0; + if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0); omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate); -- cgit v0.10.2 From a748021ccbd2bb9b2b818a7fc67b19187d04bdf2 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:37 +0530 Subject: i2c: omap: use revision check for OMAP_I2C_FLAG_APPLY_ERRATA_I207 The errata i207 is enabled for 2430 and 3xxx. Use the revision check to enable the erratum instead. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index bf0569e..7c40960 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1176,7 +1176,8 @@ omap_i2c_probe(struct platform_device *pdev) dev->errata = 0; - if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) + if (dev->rev >= OMAP_I2C_REV_ON_2430 && + dev->rev < OMAP_I2C_REV_ON_4430_PLUS) dev->errata |= I2C_OMAP_ERRATA_I207; if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) -- cgit v0.10.2 From cd10c74aeea76e60ec5ab15357266b76d8e50df1 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:38 +0530 Subject: i2c: omap: remove the dtrev The dtrev is used only for the comments. Remove the same and use the scheme instead to know if it is version2. Signed-off-by: Shubhrajyoti D Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 7c40960..0ca50e7 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -192,7 +192,6 @@ struct omap_i2c_dev { void (*set_mpu_wkup_lat)(struct device *dev, long latency); u32 speed; /* Speed of bus in kHz */ - u32 dtrev; /* extra revision from DT */ u32 flags; u16 cmd_err; u8 *buf; @@ -1075,7 +1074,7 @@ omap_i2c_probe(struct platform_device *pdev) int irq; int r; u32 rev; - u16 minor, major; + u16 minor, major, scheme; /* NOTE: driver uses the static register mapping */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1107,7 +1106,6 @@ omap_i2c_probe(struct platform_device *pdev) u32 freq = 100000; /* default to 100000 Hz */ pdata = match->data; - dev->dtrev = pdata->rev; dev->flags = pdata->flags; of_property_read_u32(node, "clock-frequency", &freq); @@ -1117,7 +1115,6 @@ omap_i2c_probe(struct platform_device *pdev) dev->speed = pdata->clkrate; dev->flags = pdata->flags; dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; - dev->dtrev = pdata->rev; } dev->pins = devm_pinctrl_get_select_default(&pdev->dev); @@ -1156,7 +1153,8 @@ omap_i2c_probe(struct platform_device *pdev) */ rev = __raw_readw(dev->base + 0x04); - switch (OMAP_I2C_SCHEME(rev)) { + scheme = OMAP_I2C_SCHEME(rev); + switch (scheme) { case OMAP_I2C_SCHEME_0: dev->regs = (u8 *)reg_map_ip_v1; dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG); @@ -1241,8 +1239,8 @@ omap_i2c_probe(struct platform_device *pdev) goto err_unuse_clocks; } - dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr, - dev->dtrev, major, minor, dev->speed); + dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, + major, minor, dev->speed); of_i2c_register_devices(adap); -- cgit v0.10.2 From 2c88ab8c5af7d637d2a9d14b607fa6100fa64236 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:39 +0530 Subject: ARM: i2c: omap: Remove the i207 errata flag The commit [i2c: omap: use revision check for OMAP_I2C_FLAG_APPLY_ERRATA_I207] uses the revision id instead of the flag. So the flag can be safely removed. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index c455e41..b79ccf6 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -76,8 +76,7 @@ static struct omap_hwmod_class i2c_class = { static struct omap_i2c_dev_attr i2c_dev_attr = { .fifo_depth = 8, /* bytes */ - .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | - OMAP_I2C_FLAG_BUS_SHIFT_2 | + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2 | OMAP_I2C_FLAG_FORCE_19200_INT_CLK, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index f67b7ee..943222c 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -791,8 +791,7 @@ static struct omap_hwmod omap3xxx_dss_venc_hwmod = { /* I2C1 */ static struct omap_i2c_dev_attr i2c1_dev_attr = { .fifo_depth = 8, /* bytes */ - .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | OMAP_I2C_FLAG_BUS_SHIFT_2, }; @@ -818,8 +817,7 @@ static struct omap_hwmod omap3xxx_i2c1_hwmod = { /* I2C2 */ static struct omap_i2c_dev_attr i2c2_dev_attr = { .fifo_depth = 8, /* bytes */ - .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | OMAP_I2C_FLAG_BUS_SHIFT_2, }; @@ -845,8 +843,7 @@ static struct omap_hwmod omap3xxx_i2c2_hwmod = { /* I2C3 */ static struct omap_i2c_dev_attr i2c3_dev_attr = { .fifo_depth = 64, /* bytes */ - .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | OMAP_I2C_FLAG_BUS_SHIFT_2, }; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0ca50e7..11e645a 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1028,8 +1028,7 @@ static const struct i2c_algorithm omap_i2c_algo = { #ifdef CONFIG_OF static struct omap_i2c_bus_platform_data omap3_pdata = { .rev = OMAP_I2C_IP_VERSION_1, - .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | OMAP_I2C_FLAG_BUS_SHIFT_2, }; diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 92a0dc7..1b25c04 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -21,7 +21,6 @@ #define OMAP_I2C_FLAG_SIMPLE_CLOCK BIT(1) #define OMAP_I2C_FLAG_16BIT_DATA_REG BIT(2) #define OMAP_I2C_FLAG_RESET_REGS_POSTIDLE BIT(3) -#define OMAP_I2C_FLAG_APPLY_ERRATA_I207 BIT(4) #define OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK BIT(5) #define OMAP_I2C_FLAG_FORCE_19200_INT_CLK BIT(6) /* how the CPU address bus must be translated for I2C unit access */ -- cgit v0.10.2 From 95dd3032663fab5a56331b066baf1757cb941b1a Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:40 +0530 Subject: i2c: omap: re-factor omap_i2c_init function re-factor omap_i2c_init() so that we can re-use it for resume. While at it also remove the bufstate variable as we write it in omap_i2c_resize_fifo for every transfer. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 11e645a..0195d99 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -210,7 +210,6 @@ struct omap_i2c_dev { u16 pscstate; u16 scllstate; u16 sclhstate; - u16 bufstate; u16 syscstate; u16 westate; u16 errata; @@ -278,9 +277,34 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) (i2c_dev->regs[reg] << i2c_dev->reg_shift)); } +static void __omap_i2c_init(struct omap_i2c_dev *dev) +{ + + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + + /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */ + omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate); + + /* SCL low and high time values */ + omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate); + omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate); + if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) + omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); + + /* Take the I2C module out of reset: */ + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + + /* + * Don't write to this register if the IE state is 0 as it can + * cause deadlock. + */ + if (dev->iestate) + omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); +} + static int omap_i2c_init(struct omap_i2c_dev *dev) { - u16 psc = 0, scll = 0, sclh = 0, buf = 0; + u16 psc = 0, scll = 0, sclh = 0; u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; unsigned long fclk_rate = 12000000; unsigned long timeout; @@ -330,11 +354,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * REVISIT: Some wkup sources might not be needed. */ dev->westate = OMAP_I2C_WE_ALL; - omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, - dev->westate); } } - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { /* @@ -419,28 +440,17 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) sclh = fclk_rate / (dev->speed * 2) - 7 + psc; } - /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */ - omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc); - - /* SCL low and high time values */ - omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); - omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); - - /* Take the I2C module out of reset: */ - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); - - /* Enable interrupts */ dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | OMAP_I2C_IE_AL) | ((dev->fifo_size) ? (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); - omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); - if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { - dev->pscstate = psc; - dev->scllstate = scll; - dev->sclhstate = sclh; - dev->bufstate = buf; - } + + dev->pscstate = psc; + dev->scllstate = scll; + dev->sclhstate = sclh; + + __omap_i2c_init(dev); + return 0; } @@ -1308,23 +1318,8 @@ static int omap_i2c_runtime_resume(struct device *dev) if (!_dev->regs) return 0; - if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { - omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0); - omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate); - omap_i2c_write_reg(_dev, OMAP_I2C_SCLL_REG, _dev->scllstate); - omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate); - omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate); - omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate); - omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate); - omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); - } - - /* - * Don't write to this register if the IE state is 0 as it can - * cause deadlock. - */ - if (_dev->iestate) - omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate); + if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) + __omap_i2c_init(_dev); return 0; } -- cgit v0.10.2 From d6c842ad564c336d62d3d5777c520454f1473b8c Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:41 +0530 Subject: i2c: omap: make reset a seperate function Implement reset as a separate function. This will enable us to make sure that we don't do the calculation again on every transfer. Also at probe the reset is not added as the hwmod is doing that for us. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0195d99..faaa052 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -302,15 +302,9 @@ static void __omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); } -static int omap_i2c_init(struct omap_i2c_dev *dev) +static int omap_i2c_reset(struct omap_i2c_dev *dev) { - u16 psc = 0, scll = 0, sclh = 0; - u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; - unsigned long fclk_rate = 12000000; unsigned long timeout; - unsigned long internal_clk = 0; - struct clk *fclk; - if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { /* Disable I2C controller before soft reset */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, @@ -348,14 +342,27 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate); - /* - * Enabling all wakup sources to stop I2C freezing on - * WFI instruction. - * REVISIT: Some wkup sources might not be needed. - */ - dev->westate = OMAP_I2C_WE_ALL; } } + return 0; +} + +static int omap_i2c_init(struct omap_i2c_dev *dev) +{ + u16 psc = 0, scll = 0, sclh = 0; + u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; + unsigned long fclk_rate = 12000000; + unsigned long internal_clk = 0; + struct clk *fclk; + + if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { + /* + * Enabling all wakup sources to stop I2C freezing on + * WFI instruction. + * REVISIT: Some wkup sources might not be needed. + */ + dev->westate = OMAP_I2C_WE_ALL; + } if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { /* @@ -599,7 +606,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, OMAP_I2C_TIMEOUT); if (timeout == 0) { dev_err(dev->dev, "controller timed out\n"); - omap_i2c_init(dev); + omap_i2c_reset(dev); + __omap_i2c_init(dev); return -ETIMEDOUT; } @@ -609,7 +617,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, /* We have an error */ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) { - omap_i2c_init(dev); + omap_i2c_reset(dev); + __omap_i2c_init(dev); return -EIO; } -- cgit v0.10.2 From 554c96744afd169886bd6fc2736fb0d9aaf634e8 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:42 +0530 Subject: i2c: omap: Restore i2c context always Currently the restore is done based on the flag OMAP_I2C_FLAG_RESET_REGS_POSTIDLE. This helps the following - The driver is always capable of restoring regardless of the off mode support being there or not. - While testing omap2430 it is found that in case of certain error paths (timeout) a reset is done. However the restore never happens as it is dependent on the POSTIDLE flag. The other option would be to call a restore in the reset case. As there are only a few registers to be restored the penalty in the idle case should not be much. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index faaa052..067a739 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1327,8 +1327,7 @@ static int omap_i2c_runtime_resume(struct device *dev) if (!_dev->regs) return 0; - if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) - __omap_i2c_init(_dev); + __omap_i2c_init(_dev); return 0; } -- cgit v0.10.2 From ca85e248b65649176e9e1edfbf5e791bc44ee52b Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 5 Nov 2012 17:53:43 +0530 Subject: i2c: omap: cleanup the sysc write Currently after the reset the sysc is written with hardcoded values. The patch reads the sysc register and writes back the same value after reset. - Some unnecessary rev checks can be optimised. - Also due to whatever reason the hwmod flags are changed we will not reset the values. - In some of the cases the minor values of the 2430 register is different(0x37) in that case the autoidle setting may be missed. Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 067a739..482c63d 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -305,7 +305,11 @@ static void __omap_i2c_init(struct omap_i2c_dev *dev) static int omap_i2c_reset(struct omap_i2c_dev *dev) { unsigned long timeout; + u16 sysc; + if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { + sysc = omap_i2c_read_reg(dev, OMAP_I2C_SYSC_REG); + /* Disable I2C controller before soft reset */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) & @@ -327,22 +331,8 @@ static int omap_i2c_reset(struct omap_i2c_dev *dev) } /* SYSC register is cleared by the reset; rewrite it */ - if (dev->rev == OMAP_I2C_REV_ON_2430) { - - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, - SYSC_AUTOIDLE_MASK); + omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, sysc); - } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { - dev->syscstate = SYSC_AUTOIDLE_MASK; - dev->syscstate |= SYSC_ENAWAKEUP_MASK; - dev->syscstate |= (SYSC_IDLEMODE_SMART << - __ffs(SYSC_SIDLEMODE_MASK)); - dev->syscstate |= (SYSC_CLOCKACTIVITY_FCLK << - __ffs(SYSC_CLOCKACTIVITY_MASK)); - - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, - dev->syscstate); - } } return 0; } -- cgit v0.10.2 From 27e0fbefa5ddebdd681d2be9824302d14494c5ff Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 14 Nov 2012 18:12:29 +0100 Subject: i2c: omap: don't save a value only needed for read-clearing Acked-by: Felipe Balbi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 482c63d..49b12fb 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1291,14 +1291,13 @@ static int omap_i2c_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); - u16 iv; _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); if (_dev->rev < OMAP_I2C_OMAP1_REV_2) { - iv = omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */ + omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */ } else { omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate); -- cgit v0.10.2 From e81b3295bc54eb0d03f4cdfc8cbf72e731d1b402 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 2 Oct 2012 16:55:01 +0000 Subject: powerpc+of: Add /proc device tree updating to of node add/remove When adding or removing a device tree node we should also update the device tree in /proc/device-tree. This action is already done in the generic OF code for adding/removing properties of a node. This patch adds this functionality for nodes. Signed-off-by: Nathan Fontenot Acked-by: Rob Herring Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 0f1b706..e36789b 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -255,9 +254,6 @@ static struct device_node *derive_parent(const char *path) int dlpar_attach_node(struct device_node *dn) { -#ifdef CONFIG_PROC_DEVICETREE - struct proc_dir_entry *ent; -#endif int rc; of_node_set_flag(dn, OF_DYNAMIC); @@ -274,32 +270,12 @@ int dlpar_attach_node(struct device_node *dn) } of_attach_node(dn); - -#ifdef CONFIG_PROC_DEVICETREE - ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); - if (ent) - proc_device_tree_add_node(dn, ent); -#endif - of_node_put(dn->parent); return 0; } int dlpar_detach_node(struct device_node *dn) { -#ifdef CONFIG_PROC_DEVICETREE - struct device_node *parent = dn->parent; - struct property *prop = dn->properties; - - while (prop) { - remove_proc_entry(prop->name, dn->pde); - prop = prop->next; - } - - if (dn->pde) - remove_proc_entry(dn->pde->name, parent->pde); -#endif - pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, dn); of_detach_node(dn); of_node_put(dn); /* Must decrement the refcount */ diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 39f71fb..f99f1ca 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -23,48 +23,6 @@ #include #include - - -/* - * Routines for "runtime" addition and removal of device tree nodes. - */ -#ifdef CONFIG_PROC_DEVICETREE -/* - * Add a node to /proc/device-tree. - */ -static void add_node_proc_entries(struct device_node *np) -{ - struct proc_dir_entry *ent; - - ent = proc_mkdir(strrchr(np->full_name, '/') + 1, np->parent->pde); - if (ent) - proc_device_tree_add_node(np, ent); -} - -static void remove_node_proc_entries(struct device_node *np) -{ - struct property *pp = np->properties; - struct device_node *parent = np->parent; - - while (pp) { - remove_proc_entry(pp->name, np->pde); - pp = pp->next; - } - if (np->pde) - remove_proc_entry(np->pde->name, parent->pde); -} -#else /* !CONFIG_PROC_DEVICETREE */ -static void add_node_proc_entries(struct device_node *np) -{ - return; -} - -static void remove_node_proc_entries(struct device_node *np) -{ - return; -} -#endif /* CONFIG_PROC_DEVICETREE */ - /** * derive_parent - basically like dirname(1) * @path: the full_name of a node to be added to the tree @@ -149,9 +107,6 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist } of_attach_node(np); - - add_node_proc_entries(np); - of_node_put(np->parent); return 0; @@ -179,8 +134,6 @@ static int pSeries_reconfig_remove_node(struct device_node *np) return -EBUSY; } - remove_node_proc_entries(np); - pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, np); of_detach_node(np); diff --git a/drivers/of/base.c b/drivers/of/base.c index af3b22a..bbd073f 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1160,6 +1160,22 @@ int prom_update_property(struct device_node *np, * device tree nodes. */ +#ifdef CONFIG_PROC_DEVICETREE +static void of_add_proc_dt_entry(struct device_node *dn) +{ + struct proc_dir_entry *ent; + + ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); + if (ent) + proc_device_tree_add_node(dn, ent); +} +#else +static void of_add_proc_dt_entry(struct device_node *dn) +{ + return; +} +#endif + /** * of_attach_node - Plug a device node into the tree and global list. */ @@ -1173,8 +1189,31 @@ void of_attach_node(struct device_node *np) np->parent->child = np; allnodes = np; write_unlock_irqrestore(&devtree_lock, flags); + + of_add_proc_dt_entry(np); } +#ifdef CONFIG_PROC_DEVICETREE +static void of_remove_proc_dt_entry(struct device_node *dn) +{ + struct device_node *parent = dn->parent; + struct property *prop = dn->properties; + + while (prop) { + remove_proc_entry(prop->name, dn->pde); + prop = prop->next; + } + + if (dn->pde) + remove_proc_entry(dn->pde->name, parent->pde); +} +#else +static void of_remove_proc_dt_entry(struct device_node *dn) +{ + return; +} +#endif + /** * of_detach_node - "Unplug" a node from the device tree. * @@ -1188,9 +1227,17 @@ void of_detach_node(struct device_node *np) write_lock_irqsave(&devtree_lock, flags); + if (of_node_check_flag(np, OF_DETACHED)) { + /* someone already detached it */ + write_unlock_irqrestore(&devtree_lock, flags); + return; + } + parent = np->parent; - if (!parent) - goto out_unlock; + if (!parent) { + write_unlock_irqrestore(&devtree_lock, flags); + return; + } if (allnodes == np) allnodes = np->allnext; @@ -1215,9 +1262,9 @@ void of_detach_node(struct device_node *np) } of_node_set_flag(np, OF_DETACHED); - -out_unlock: write_unlock_irqrestore(&devtree_lock, flags); + + of_remove_proc_dt_entry(np); } #endif /* defined(CONFIG_OF_DYNAMIC) */ -- cgit v0.10.2 From f59497208363f3dd9d62b79b7f7eafc95432de79 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 2 Oct 2012 16:56:11 +0000 Subject: powerpc+of: Move of_drconf_cell struct definition to asm/prom.h This patch moves the definition of the of_drconf_cell struct to asm/prom.h to make it available for all powerpc/pseries code. Signed-off-by: Nathan Fontenot Acked-by: Rob Herring Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index b5c9190..99c92d5 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -58,6 +58,22 @@ static inline int of_node_to_nid(struct device_node *device) { return 0; } extern void of_instantiate_rtc(void); +/* The of_drconf_cell struct defines the layout of the LMB array + * specified in the device tree property + * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory + */ +struct of_drconf_cell { + u64 base_addr; + u32 drc_index; + u32 reserved; + u32 aa_index; + u32 flags; +}; + +#define DRCONF_MEM_ASSIGNED 0x00000008 +#define DRCONF_MEM_AI_INVALID 0x00000040 +#define DRCONF_MEM_RESERVED 0x00000080 + /* These includes are put at the bottom because they may contain things * that are overridden by this file. Ideally they shouldn't be included * by this file, but there are a bunch of .c files that currently depend diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 59213cf..bba87ca 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -399,18 +399,6 @@ static unsigned long read_n_cells(int n, const unsigned int **buf) return result; } -struct of_drconf_cell { - u64 base_addr; - u32 drc_index; - u32 reserved; - u32 aa_index; - u32 flags; -}; - -#define DRCONF_MEM_ASSIGNED 0x00000008 -#define DRCONF_MEM_AI_INVALID 0x00000040 -#define DRCONF_MEM_RESERVED 0x00000080 - /* * Read the next memblock list entry from the ibm,dynamic-memory property * and return the information in the provided of_drconf_cell structure. -- cgit v0.10.2 From 1cf3d8b3d24cd383ddfd5442c83ec5c355ffc2f7 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 2 Oct 2012 16:57:57 +0000 Subject: powerpc+of: Add of node/property notification chain for adds and removes This patch moves the notification chain for updates to the device tree from the powerpc/pseries code to the base OF code. This makes this functionality available to all architectures. Additionally the notification chain is updated to allow notifications for property add/remove/update. To make this work a pointer to a new struct (of_prop_reconfig) is passed to the routines in the notification chain. The of_prop_reconfig property contains a pointer to the node containing the property and a pointer to the property itself. In the case of property updates, the property pointer refers to the new property. Signed-off-by: Nathan Fontenot Acked-by: Rob Herring Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h index c07edfe..adc00d2 100644 --- a/arch/powerpc/include/asm/pSeries_reconfig.h +++ b/arch/powerpc/include/asm/pSeries_reconfig.h @@ -2,43 +2,11 @@ #define _PPC64_PSERIES_RECONFIG_H #ifdef __KERNEL__ -#include - -/* - * Use this API if your code needs to know about OF device nodes being - * added or removed on pSeries systems. - */ - -#define PSERIES_RECONFIG_ADD 0x0001 -#define PSERIES_RECONFIG_REMOVE 0x0002 -#define PSERIES_DRCONF_MEM_ADD 0x0003 -#define PSERIES_DRCONF_MEM_REMOVE 0x0004 -#define PSERIES_UPDATE_PROPERTY 0x0005 - -/** - * pSeries_reconfig_notify - Notifier value structure for OFDT property updates - * - * @node: Device tree node which owns the property being updated - * @property: Updated property - */ -struct pSeries_reconfig_prop_update { - struct device_node *node; - struct property *property; -}; - #ifdef CONFIG_PPC_PSERIES -extern int pSeries_reconfig_notifier_register(struct notifier_block *); -extern void pSeries_reconfig_notifier_unregister(struct notifier_block *); -extern int pSeries_reconfig_notify(unsigned long action, void *p); /* Not the best place to put this, will be fixed when we move some * of the rtas suspend-me stuff to pseries */ extern void pSeries_coalesce_init(void); #else /* !CONFIG_PPC_PSERIES */ -static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb) -{ - return 0; -} -static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { } static inline void pSeries_coalesce_init(void) { } #endif /* CONFIG_PPC_PSERIES */ diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 37725e8..6feb60c 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -49,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -802,7 +802,7 @@ static int prom_reconfig_notifier(struct notifier_block *nb, int err; switch (action) { - case PSERIES_RECONFIG_ADD: + case OF_RECONFIG_ATTACH_NODE: err = of_finish_dynamic_node(node); if (err < 0) printk(KERN_ERR "finish_node returned %d\n", err); @@ -821,7 +821,7 @@ static struct notifier_block prom_reconfig_nb = { static int __init prom_reconfig_setup(void) { - return pSeries_reconfig_notifier_register(&prom_reconfig_nb); + return of_reconfig_notifier_register(&prom_reconfig_nb); } __initcall(prom_reconfig_setup); #endif diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index e36789b..a1a7b9a 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -16,13 +16,13 @@ #include #include #include +#include #include "offline_states.h" #include #include #include #include -#include struct cc_workarea { u32 drc_index; @@ -262,24 +262,26 @@ int dlpar_attach_node(struct device_node *dn) if (!dn->parent) return -ENOMEM; - rc = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, dn); + rc = of_attach_node(dn); if (rc) { printk(KERN_ERR "Failed to add device node %s\n", dn->full_name); return rc; } - of_attach_node(dn); of_node_put(dn->parent); return 0; } int dlpar_detach_node(struct device_node *dn) { - pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, dn); - of_detach_node(dn); - of_node_put(dn); /* Must decrement the refcount */ + int rc; + + rc = of_detach_node(dn); + if (rc) + return rc; + of_node_put(dn); /* Must decrement the refcount */ return 0; } diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 64c97d8..a389562 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -23,12 +23,12 @@ #include #include /* for idle_task_exit */ #include +#include #include #include #include #include #include -#include #include #include "plpar_wrappers.h" #include "offline_states.h" @@ -333,10 +333,10 @@ static int pseries_smp_notifier(struct notifier_block *nb, int err = 0; switch (action) { - case PSERIES_RECONFIG_ADD: + case OF_RECONFIG_ATTACH_NODE: err = pseries_add_processor(node); break; - case PSERIES_RECONFIG_REMOVE: + case OF_RECONFIG_DETACH_NODE: pseries_remove_processor(node); break; } @@ -399,7 +399,7 @@ static int __init pseries_cpu_hotplug_init(void) /* Processors can be added/removed only on LPAR */ if (firmware_has_feature(FW_FEATURE_LPAR)) { - pSeries_reconfig_notifier_register(&pseries_smp_nb); + of_reconfig_notifier_register(&pseries_smp_nb); cpu_maps_update_begin(); if (cede_offline_enabled && parse_cede_parameters() == 0) { default_offline_state = CPU_STATE_INACTIVE; diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index ecdb0a6..2372c60 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -16,7 +16,6 @@ #include #include -#include #include static unsigned long get_memblock_size(void) @@ -187,42 +186,69 @@ static int pseries_add_memory(struct device_node *np) return (ret < 0) ? -EINVAL : 0; } -static int pseries_drconf_memory(unsigned long *base, unsigned int action) +static int pseries_update_drconf_memory(struct of_prop_reconfig *pr) { + struct of_drconf_cell *new_drmem, *old_drmem; unsigned long memblock_size; - int rc; + u32 entries; + u32 *p; + int i, rc = -EINVAL; memblock_size = get_memblock_size(); if (!memblock_size) return -EINVAL; - if (action == PSERIES_DRCONF_MEM_ADD) { - rc = memblock_add(*base, memblock_size); - rc = (rc < 0) ? -EINVAL : 0; - } else if (action == PSERIES_DRCONF_MEM_REMOVE) { - rc = pseries_remove_memblock(*base, memblock_size); - } else { - rc = -EINVAL; + p = (u32 *)of_get_property(pr->dn, "ibm,dynamic-memory", NULL); + if (!p) + return -EINVAL; + + /* The first int of the property is the number of lmb's described + * by the property. This is followed by an array of of_drconf_cell + * entries. Get the niumber of entries and skip to the array of + * of_drconf_cell's. + */ + entries = *p++; + old_drmem = (struct of_drconf_cell *)p; + + p = (u32 *)pr->prop->value; + p++; + new_drmem = (struct of_drconf_cell *)p; + + for (i = 0; i < entries; i++) { + if ((old_drmem[i].flags & DRCONF_MEM_ASSIGNED) && + (!(new_drmem[i].flags & DRCONF_MEM_ASSIGNED))) { + rc = pseries_remove_memblock(old_drmem[i].base_addr, + memblock_size); + break; + } else if ((!(old_drmem[i].flags & DRCONF_MEM_ASSIGNED)) && + (new_drmem[i].flags & DRCONF_MEM_ASSIGNED)) { + rc = memblock_add(old_drmem[i].base_addr, + memblock_size); + rc = (rc < 0) ? -EINVAL : 0; + break; + } } return rc; } static int pseries_memory_notifier(struct notifier_block *nb, - unsigned long action, void *node) + unsigned long action, void *node) { + struct of_prop_reconfig *pr; int err = 0; switch (action) { - case PSERIES_RECONFIG_ADD: + case OF_RECONFIG_ATTACH_NODE: err = pseries_add_memory(node); break; - case PSERIES_RECONFIG_REMOVE: + case OF_RECONFIG_DETACH_NODE: err = pseries_remove_memory(node); break; - case PSERIES_DRCONF_MEM_ADD: - case PSERIES_DRCONF_MEM_REMOVE: - err = pseries_drconf_memory(node, action); + case OF_RECONFIG_UPDATE_PROPERTY: + pr = (struct of_prop_reconfig *)node; + if (!strcmp(pr->prop->name, "ibm,dynamic-memory")) + err = pseries_update_drconf_memory(pr); break; } return notifier_from_errno(err); @@ -235,7 +261,7 @@ static struct notifier_block pseries_mem_nb = { static int __init pseries_memory_hotplug_init(void) { if (firmware_has_feature(FW_FEATURE_LPAR)) - pSeries_reconfig_notifier_register(&pseries_mem_nb); + of_reconfig_notifier_register(&pseries_mem_nb); return 0; } diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 6153eea..da5594c 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -36,13 +36,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -1294,7 +1294,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti struct direct_window *window; switch (action) { - case PSERIES_RECONFIG_REMOVE: + case OF_RECONFIG_DETACH_NODE: if (pci && pci->iommu_table) iommu_free_table(pci->iommu_table, np->full_name); @@ -1357,7 +1357,7 @@ void iommu_init_early_pSeries(void) } - pSeries_reconfig_notifier_register(&iommu_reconfig_nb); + of_reconfig_notifier_register(&iommu_reconfig_nb); register_memory_notifier(&iommu_mem_nb); set_pci_dma_ops(&dma_iommu_ops); diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index f99f1ca..720a0cc 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -16,11 +16,11 @@ #include #include #include +#include #include #include #include -#include #include /** @@ -55,28 +55,6 @@ static struct device_node *derive_parent(const char *path) return parent; } -static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain); - -int pSeries_reconfig_notifier_register(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb); -} -EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_register); - -void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) -{ - blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb); -} -EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_unregister); - -int pSeries_reconfig_notify(unsigned long action, void *p) -{ - int err = blocking_notifier_call_chain(&pSeries_reconfig_chain, - action, p); - - return notifier_to_errno(err); -} - static int pSeries_reconfig_add_node(const char *path, struct property *proplist) { struct device_node *np; @@ -100,13 +78,12 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist goto out_err; } - err = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, np); + err = of_attach_node(np); if (err) { printk(KERN_ERR "Failed to add device node %s\n", path); goto out_err; } - of_attach_node(np); of_node_put(np->parent); return 0; @@ -134,9 +111,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np) return -EBUSY; } - pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, np); of_detach_node(np); - of_node_put(parent); of_node_put(np); /* Must decrement the refcount */ return 0; @@ -381,10 +356,9 @@ static int do_remove_property(char *buf, size_t bufsize) static int do_update_property(char *buf, size_t bufsize) { struct device_node *np; - struct pSeries_reconfig_prop_update upd_value; unsigned char *value; char *name, *end, *next_prop; - int rc, length; + int length; struct property *newprop; buf = parse_node(buf, bufsize, &np); end = buf + bufsize; @@ -406,41 +380,7 @@ static int do_update_property(char *buf, size_t bufsize) if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size")) slb_set_size(*(int *)value); - upd_value.node = np; - upd_value.property = newprop; - pSeries_reconfig_notify(PSERIES_UPDATE_PROPERTY, &upd_value); - - rc = prom_update_property(np, newprop); - if (rc) - return rc; - - /* For memory under the ibm,dynamic-reconfiguration-memory node - * of the device tree, adding and removing memory is just an update - * to the ibm,dynamic-memory property instead of adding/removing a - * memory node in the device tree. For these cases we still need to - * involve the notifier chain. - */ - if (!strcmp(name, "ibm,dynamic-memory")) { - int action; - - next_prop = parse_next_property(next_prop, end, &name, - &length, &value); - if (!next_prop) - return -EINVAL; - - if (!strcmp(name, "add")) - action = PSERIES_DRCONF_MEM_ADD; - else - action = PSERIES_DRCONF_MEM_REMOVE; - - rc = pSeries_reconfig_notify(action, value); - if (rc) { - prom_update_property(np, newprop); - return rc; - } - } - - return 0; + return prom_update_property(np, newprop); } /** diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index e3cb7ae..e1a5b8a 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -63,7 +64,6 @@ #include #include #include -#include #include "plpar_wrappers.h" #include "pseries.h" @@ -258,7 +258,7 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act int err = NOTIFY_OK; switch (action) { - case PSERIES_RECONFIG_ADD: + case OF_RECONFIG_ATTACH_NODE: pci = np->parent->data; if (pci) { update_dn_pci_info(np, pci->phb); @@ -389,7 +389,7 @@ static void __init pSeries_setup_arch(void) /* Find and initialize PCI host bridges */ init_pci_config_tokens(); find_and_init_phbs(); - pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); + of_reconfig_notifier_register(&pci_dn_reconfig_nb); pSeries_nvram_init(); diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 0ce6257..6c4c000 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c @@ -28,7 +28,6 @@ #include #include -#include #include #include "nx_csbcpb.h" /* struct nx_csbcpb */ @@ -1014,26 +1013,23 @@ error_out: * NOTIFY_BAD encoded with error number on failure, use * notifier_to_errno() to decode this value */ -static int nx842_OF_notifier(struct notifier_block *np, - unsigned long action, - void *update) +static int nx842_OF_notifier(struct notifier_block *np, unsigned long action, + void *update) { - struct pSeries_reconfig_prop_update *upd; + struct of_prop_reconfig *upd = update; struct nx842_devdata *local_devdata; struct device_node *node = NULL; - upd = (struct pSeries_reconfig_prop_update *)update; - rcu_read_lock(); local_devdata = rcu_dereference(devdata); if (local_devdata) node = local_devdata->dev->of_node; if (local_devdata && - action == PSERIES_UPDATE_PROPERTY && - !strcmp(upd->node->name, node->name)) { + action == OF_RECONFIG_UPDATE_PROPERTY && + !strcmp(upd->dn->name, node->name)) { rcu_read_unlock(); - nx842_OF_upd(upd->property); + nx842_OF_upd(upd->prop); } else rcu_read_unlock(); @@ -1182,7 +1178,7 @@ static int __init nx842_probe(struct vio_dev *viodev, synchronize_rcu(); kfree(old_devdata); - pSeries_reconfig_notifier_register(&nx842_of_nb); + of_reconfig_notifier_register(&nx842_of_nb); ret = nx842_OF_upd(NULL); if (ret && ret != -ENODEV) { @@ -1228,7 +1224,7 @@ static int __exit nx842_remove(struct vio_dev *viodev) spin_lock_irqsave(&devdata_mutex, flags); old_devdata = rcu_dereference_check(devdata, lockdep_is_held(&devdata_mutex)); - pSeries_reconfig_notifier_unregister(&nx842_of_nb); + of_reconfig_notifier_unregister(&nx842_of_nb); rcu_assign_pointer(devdata, NULL); spin_unlock_irqrestore(&devdata_mutex, flags); synchronize_rcu(); diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index 638110e..f7a8a16 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include diff --git a/drivers/of/base.c b/drivers/of/base.c index bbd073f..87b6385 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1028,6 +1028,24 @@ int of_parse_phandle_with_args(struct device_node *np, const char *list_name, } EXPORT_SYMBOL(of_parse_phandle_with_args); +#if defined(CONFIG_OF_DYNAMIC) +static int of_property_notify(int action, struct device_node *np, + struct property *prop) +{ + struct of_prop_reconfig pr; + + pr.dn = np; + pr.prop = prop; + return of_reconfig_notify(action, &pr); +} +#else +static int of_property_notify(int action, struct device_node *np, + struct property *prop) +{ + return 0; +} +#endif + /** * prom_add_property - Add a property to a node */ @@ -1035,6 +1053,11 @@ int prom_add_property(struct device_node *np, struct property *prop) { struct property **next; unsigned long flags; + int rc; + + rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop); + if (rc) + return rc; prop->next = NULL; write_lock_irqsave(&devtree_lock, flags); @@ -1072,6 +1095,11 @@ int prom_remove_property(struct device_node *np, struct property *prop) struct property **next; unsigned long flags; int found = 0; + int rc; + + rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop); + if (rc) + return rc; write_lock_irqsave(&devtree_lock, flags); next = &np->properties; @@ -1114,7 +1142,11 @@ int prom_update_property(struct device_node *np, { struct property **next, *oldprop; unsigned long flags; - int found = 0; + int rc, found = 0; + + rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); + if (rc) + return rc; if (!newprop->name) return -EINVAL; @@ -1160,6 +1192,26 @@ int prom_update_property(struct device_node *np, * device tree nodes. */ +static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); + +int of_reconfig_notifier_register(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&of_reconfig_chain, nb); +} + +int of_reconfig_notifier_unregister(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); +} + +int of_reconfig_notify(unsigned long action, void *p) +{ + int rc; + + rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); + return notifier_to_errno(rc); +} + #ifdef CONFIG_PROC_DEVICETREE static void of_add_proc_dt_entry(struct device_node *dn) { @@ -1179,9 +1231,14 @@ static void of_add_proc_dt_entry(struct device_node *dn) /** * of_attach_node - Plug a device node into the tree and global list. */ -void of_attach_node(struct device_node *np) +int of_attach_node(struct device_node *np) { unsigned long flags; + int rc; + + rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); + if (rc) + return rc; write_lock_irqsave(&devtree_lock, flags); np->sibling = np->parent->child; @@ -1191,6 +1248,7 @@ void of_attach_node(struct device_node *np) write_unlock_irqrestore(&devtree_lock, flags); of_add_proc_dt_entry(np); + return 0; } #ifdef CONFIG_PROC_DEVICETREE @@ -1220,23 +1278,28 @@ static void of_remove_proc_dt_entry(struct device_node *dn) * The caller must hold a reference to the node. The memory associated with * the node is not freed until its refcount goes to zero. */ -void of_detach_node(struct device_node *np) +int of_detach_node(struct device_node *np) { struct device_node *parent; unsigned long flags; + int rc = 0; + + rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); + if (rc) + return rc; write_lock_irqsave(&devtree_lock, flags); if (of_node_check_flag(np, OF_DETACHED)) { /* someone already detached it */ write_unlock_irqrestore(&devtree_lock, flags); - return; + return rc; } parent = np->parent; if (!parent) { write_unlock_irqrestore(&devtree_lock, flags); - return; + return rc; } if (allnodes == np) @@ -1265,6 +1328,7 @@ void of_detach_node(struct device_node *np) write_unlock_irqrestore(&devtree_lock, flags); of_remove_proc_dt_entry(np); + return rc; } #endif /* defined(CONFIG_OF_DYNAMIC) */ diff --git a/include/linux/of.h b/include/linux/of.h index 72843b7..fb5d87b 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -272,11 +273,24 @@ extern int prom_remove_property(struct device_node *np, struct property *prop); extern int prom_update_property(struct device_node *np, struct property *newprop); -#if defined(CONFIG_OF_DYNAMIC) /* For updating the device tree at runtime */ -extern void of_attach_node(struct device_node *); -extern void of_detach_node(struct device_node *); -#endif +#define OF_RECONFIG_ATTACH_NODE 0x0001 +#define OF_RECONFIG_DETACH_NODE 0x0002 +#define OF_RECONFIG_ADD_PROPERTY 0x0003 +#define OF_RECONFIG_REMOVE_PROPERTY 0x0004 +#define OF_RECONFIG_UPDATE_PROPERTY 0x0005 + +struct of_prop_reconfig { + struct device_node *dn; + struct property *prop; +}; + +extern int of_reconfig_notifier_register(struct notifier_block *); +extern int of_reconfig_notifier_unregister(struct notifier_block *); +extern int of_reconfig_notify(unsigned long, void *); + +extern int of_attach_node(struct device_node *); +extern int of_detach_node(struct device_node *); #define of_match_ptr(_ptr) (_ptr) -- cgit v0.10.2 From 79d1c712958f94372482ad74578b00f44e744c12 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 2 Oct 2012 16:58:46 +0000 Subject: powerpc+of: Rename the drivers/of prom_* functions to of_* Rename the prom_*_property routines of the generic OF code to of_*_property. This brings them in line with the naming used by the rest of the OF code. Signed-off-by: Nathan Fontenot Acked-by: Geoff Levand Acked-by: Rob Herring Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index 4748ec5..d61b915 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -211,7 +211,7 @@ static void __init update_fec_mac_prop(enum mac_oui oui) macaddr[4] = (val >> 8) & 0xff; macaddr[5] = (val >> 0) & 0xff; - prom_update_property(np, newmac); + of_update_property(np, newmac); } } diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index fa9f6c7..e1ec57e 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -218,23 +218,23 @@ static void __init export_crashk_values(struct device_node *node) * be sure what's in them, so remove them. */ prop = of_find_property(node, "linux,crashkernel-base", NULL); if (prop) - prom_remove_property(node, prop); + of_remove_property(node, prop); prop = of_find_property(node, "linux,crashkernel-size", NULL); if (prop) - prom_remove_property(node, prop); + of_remove_property(node, prop); if (crashk_res.start != 0) { - prom_add_property(node, &crashk_base_prop); + of_add_property(node, &crashk_base_prop); crashk_size = resource_size(&crashk_res); - prom_add_property(node, &crashk_size_prop); + of_add_property(node, &crashk_size_prop); } /* * memory_limit is required by the kexec-tools to limit the * crash regions to the actual memory used. */ - prom_update_property(node, &memory_limit_prop); + of_update_property(node, &memory_limit_prop); } static int __init kexec_setup(void) @@ -249,11 +249,11 @@ static int __init kexec_setup(void) /* remove any stale properties so ours can be found */ prop = of_find_property(node, kernel_end_prop.name, NULL); if (prop) - prom_remove_property(node, prop); + of_remove_property(node, prop); /* information needed by userspace when using default_machine_kexec */ kernel_end = __pa(_end); - prom_add_property(node, &kernel_end_prop); + of_add_property(node, &kernel_end_prop); export_crashk_values(node); diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index d7f6090..7206701 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -389,14 +389,14 @@ static int __init export_htab_values(void) /* remove any stale propertys so ours can be found */ prop = of_find_property(node, htab_base_prop.name, NULL); if (prop) - prom_remove_property(node, prop); + of_remove_property(node, prop); prop = of_find_property(node, htab_size_prop.name, NULL); if (prop) - prom_remove_property(node, prop); + of_remove_property(node, prop); htab_base = __pa(htab_address); - prom_add_property(node, &htab_base_prop); - prom_add_property(node, &htab_size_prop); + of_add_property(node, &htab_base_prop); + of_add_property(node, &htab_size_prop); of_node_put(node); return 0; diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 4b06ec5..64f526a 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -208,7 +208,7 @@ pci_create_OF_bus_map(void) of_prop->name = "pci-OF-bus-map"; of_prop->length = 256; of_prop->value = &of_prop[1]; - prom_add_property(dn, of_prop); + of_add_property(dn, of_prop); of_node_put(dn); } } diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 848a3e9..8fb1257 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -539,7 +539,7 @@ static void __init p1022_ds_setup_arch(void) }; /* - * prom_update_property() is called before + * of_update_property() is called before * kmalloc() is available, so the 'new' object * should be allocated in the global area. * The easiest way is to do that is to @@ -548,7 +548,7 @@ static void __init p1022_ds_setup_arch(void) */ pr_info("p1022ds: disabling %s node", np2->full_name); - prom_update_property(np2, &nor_status); + of_update_property(np2, &nor_status); of_node_put(np2); } @@ -564,7 +564,7 @@ static void __init p1022_ds_setup_arch(void) pr_info("p1022ds: disabling %s node", np2->full_name); - prom_update_property(np2, &nand_status); + of_update_property(np2, &nand_status); of_node_put(np2); } diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 56d26bc..0978713 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -280,13 +280,13 @@ static void os_area_set_property(struct device_node *node, if (tmp) { pr_debug("%s:%d found %s\n", __func__, __LINE__, prop->name); - prom_remove_property(node, tmp); + of_remove_property(node, tmp); } - result = prom_add_property(node, prop); + result = of_add_property(node, prop); if (result) - pr_debug("%s:%d prom_set_property failed\n", __func__, + pr_debug("%s:%d of_set_property failed\n", __func__, __LINE__); } diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index da5594c..e2685ba 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -760,7 +760,7 @@ static void remove_ddw(struct device_node *np) __remove_ddw(np, ddw_avail, liobn); delprop: - ret = prom_remove_property(np, win64); + ret = of_remove_property(np, win64); if (ret) pr_warning("%s: failed to remove direct window property: %d\n", np->full_name, ret); @@ -1070,7 +1070,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) goto out_free_window; } - ret = prom_add_property(pdn, win64); + ret = of_add_property(pdn, win64); if (ret) { dev_err(&dev->dev, "unable to add dma window property for %s: %d", pdn->full_name, ret); diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index dd30b12..6573808 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -116,7 +116,7 @@ static int update_dt_property(struct device_node *dn, struct property **prop, } if (!more) { - prom_update_property(dn, new_prop); + of_update_property(dn, new_prop); new_prop = NULL; } @@ -172,7 +172,7 @@ static int update_dt_node(u32 phandle) case 0x80000000: prop = of_find_property(dn, prop_name, NULL); - prom_remove_property(dn, prop); + of_remove_property(dn, prop); prop = NULL; break; diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 720a0cc..30b358d 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -326,7 +326,7 @@ static int do_add_property(char *buf, size_t bufsize) if (!prop) return -ENOMEM; - prom_add_property(np, prop); + of_add_property(np, prop); return 0; } @@ -350,7 +350,7 @@ static int do_remove_property(char *buf, size_t bufsize) prop = of_find_property(np, buf, NULL); - return prom_remove_property(np, prop); + return of_remove_property(np, prop); } static int do_update_property(char *buf, size_t bufsize) @@ -380,7 +380,7 @@ static int do_update_property(char *buf, size_t bufsize) if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size")) slb_set_size(*(int *)value); - return prom_update_property(np, newprop); + return of_update_property(np, newprop); } /** diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 7d5a6b4..5b93950 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -997,7 +997,7 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id) "%02x !\n", id, hdr->id); goto failure; } - if (prom_add_property(smu->of_node, prop)) { + if (of_add_property(smu->of_node, prop)) { printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x " "property !\n", id); goto failure; diff --git a/drivers/of/base.c b/drivers/of/base.c index 87b6385..02d94c4 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1047,9 +1047,9 @@ static int of_property_notify(int action, struct device_node *np, #endif /** - * prom_add_property - Add a property to a node + * of_add_property - Add a property to a node */ -int prom_add_property(struct device_node *np, struct property *prop) +int of_add_property(struct device_node *np, struct property *prop) { struct property **next; unsigned long flags; @@ -1083,14 +1083,14 @@ int prom_add_property(struct device_node *np, struct property *prop) } /** - * prom_remove_property - Remove a property from a node. + * of_remove_property - Remove a property from a node. * * Note that we don't actually remove it, since we have given out * who-knows-how-many pointers to the data using get-property. * Instead we just move the property to the "dead properties" * list, so it won't be found any more. */ -int prom_remove_property(struct device_node *np, struct property *prop) +int of_remove_property(struct device_node *np, struct property *prop) { struct property **next; unsigned long flags; @@ -1129,7 +1129,7 @@ int prom_remove_property(struct device_node *np, struct property *prop) } /* - * prom_update_property - Update a property in a node, if the property does + * of_update_property - Update a property in a node, if the property does * not exist, add it. * * Note that we don't actually remove it, since we have given out @@ -1137,8 +1137,7 @@ int prom_remove_property(struct device_node *np, struct property *prop) * Instead we just move the property to the "dead properties" list, * and add the new property to the property list */ -int prom_update_property(struct device_node *np, - struct property *newprop) +int of_update_property(struct device_node *np, struct property *newprop) { struct property **next, *oldprop; unsigned long flags; @@ -1153,7 +1152,7 @@ int prom_update_property(struct device_node *np, oldprop = of_find_property(np, newprop->name, NULL); if (!oldprop) - return prom_add_property(np, newprop); + return of_add_property(np, newprop); write_lock_irqsave(&devtree_lock, flags); next = &np->properties; diff --git a/include/linux/of.h b/include/linux/of.h index fb5d87b..a093b2f 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -268,10 +268,9 @@ extern int of_alias_get_id(struct device_node *np, const char *stem); extern int of_machine_is_compatible(const char *compat); -extern int prom_add_property(struct device_node* np, struct property* prop); -extern int prom_remove_property(struct device_node *np, struct property *prop); -extern int prom_update_property(struct device_node *np, - struct property *newprop); +extern int of_add_property(struct device_node *np, struct property *prop); +extern int of_remove_property(struct device_node *np, struct property *prop); +extern int of_update_property(struct device_node *np, struct property *newprop); /* For updating the device tree at runtime */ #define OF_RECONFIG_ATTACH_NODE 0x0001 -- cgit v0.10.2 From f459d63e1689b16a2f5a965557e19b25bad5dbdc Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 2 Oct 2012 16:59:39 +0000 Subject: powerpc+of: Remove the pSeries_reconfig.h file Remove the pSeries_reconfig.h header file. At this point there is only one definition in the file, pSeries_coalesce_init(), which can be moved to rtas.h. Signed-off-by: Nathan Fontenot Acked-by: Rob Herring Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h deleted file mode 100644 index adc00d2..0000000 --- a/arch/powerpc/include/asm/pSeries_reconfig.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _PPC64_PSERIES_RECONFIG_H -#define _PPC64_PSERIES_RECONFIG_H -#ifdef __KERNEL__ - -#ifdef CONFIG_PPC_PSERIES -/* Not the best place to put this, will be fixed when we move some - * of the rtas suspend-me stuff to pseries */ -extern void pSeries_coalesce_init(void); -#else /* !CONFIG_PPC_PSERIES */ -static inline void pSeries_coalesce_init(void) { } -#endif /* CONFIG_PPC_PSERIES */ - - -#endif /* __KERNEL__ */ -#endif /* _PPC64_PSERIES_RECONFIG_H */ diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 557cff8..aef00c6 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -353,8 +353,13 @@ static inline int page_is_rtas_user_buf(unsigned long pfn) return 1; return 0; } + +/* Not the best place to put pSeries_coalesce_init, will be fixed when we + * move some of the rtas suspend-me stuff to pseries */ +extern void pSeries_coalesce_init(void); #else static inline int page_is_rtas_user_buf(unsigned long pfn) { return 0;} +static inline void pSeries_coalesce_init(void) { } #endif extern int call_rtas(const char *, int, int, unsigned long *, ...); diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index fcec382..1fd6e7b 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -42,7 +42,6 @@ #include #include #include -#include struct rtas_t rtas = { .lock = __ARCH_SPIN_LOCK_UNLOCKED diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 71706bc..9fc0a49 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From 6c39dcc465373daae484b1a893e47b5e631fb62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Hor=C3=A1k?= Date: Wed, 12 Sep 2012 06:06:44 +0000 Subject: fbdev: Add GXT4000P and GXT6500P support to the gxt4500 driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm reviving an old patch from 2009 that adds support for GXT4000P and GXT6500P adapter to the gxt4500 driver. See threads at http://marc.info/?l=linux-fbdev-devel&m=124345080216952&w=2 and https://lists.ozlabs.org/pipermail/linuxppc-dev/2009-June/072672.html for more details. This patch adds support for GXT4000P and GXT6500P cards found on some IBM pSeries machines. GXT4000P/6000P and GXT4500P/6500P couples are identical from software's point of view and are based on the same Raster Engine (RC1000), except for a different reference clock for the PLL. GXT6x00P models are equipped with an additional Geometry Engine (GT1000) but this driver doesn't use it. Signed-off-by: Nico Macrionitis Signed-off-by: Giuseppe Coviello Tested-by: Dan Horák Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d08d799..0cff083 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2140,14 +2140,16 @@ config FB_UDL To compile as a module, choose M here: the module name is udlfb. config FB_IBM_GXT4500 - tristate "Framebuffer support for IBM GXT4500P adaptor" + tristate "Framebuffer support for IBM GXT4000P/4500P/6000P/6500P adaptors" depends on FB && PPC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT ---help--- - Say Y here to enable support for the IBM GXT4500P display - adaptor, found on some IBM System P (pSeries) machines. + Say Y here to enable support for the IBM GXT4000P/6000P and + GXT4500P/6500P display adaptor based on Raster Engine RC1000, + found on some IBM System P (pSeries) machines. This driver + doesn't use Geometry Engine GT1000. config FB_PS3 tristate "PS3 GPU framebuffer driver" diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c index 0e9afa4..4bdea6e 100644 --- a/drivers/video/gxt4500.c +++ b/drivers/video/gxt4500.c @@ -1,5 +1,6 @@ /* - * Frame buffer device for IBM GXT4500P and GXT6000P display adaptors + * Frame buffer device for IBM GXT4500P/6500P and GXT4000P/6000P + * display adaptors * * Copyright (C) 2006 Paul Mackerras, IBM Corp. */ @@ -14,6 +15,8 @@ #include #define PCI_DEVICE_ID_IBM_GXT4500P 0x21c +#define PCI_DEVICE_ID_IBM_GXT6500P 0x21b +#define PCI_DEVICE_ID_IBM_GXT4000P 0x16e #define PCI_DEVICE_ID_IBM_GXT6000P 0x170 /* GXT4500P registers */ @@ -173,6 +176,8 @@ static const struct fb_videomode defaultmode __devinitconst = { /* List of supported cards */ enum gxt_cards { GXT4500P, + GXT6500P, + GXT4000P, GXT6000P }; @@ -182,6 +187,8 @@ static const struct cardinfo { const char *cardname; } cardinfo[] = { [GXT4500P] = { .refclk_ps = 9259, .cardname = "IBM GXT4500P" }, + [GXT6500P] = { .refclk_ps = 9259, .cardname = "IBM GXT6500P" }, + [GXT4000P] = { .refclk_ps = 40000, .cardname = "IBM GXT4000P" }, [GXT6000P] = { .refclk_ps = 40000, .cardname = "IBM GXT6000P" }, }; @@ -736,6 +743,10 @@ static void __devexit gxt4500_remove(struct pci_dev *pdev) static const struct pci_device_id gxt4500_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4500P), .driver_data = GXT4500P }, + { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6500P), + .driver_data = GXT6500P }, + { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4000P), + .driver_data = GXT4000P }, { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6000P), .driver_data = GXT6000P }, { 0 } @@ -768,7 +779,7 @@ static void __exit gxt4500_exit(void) module_exit(gxt4500_exit); MODULE_AUTHOR("Paul Mackerras "); -MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P/6000P"); +MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P/6500P and GXT4000P/6000P"); MODULE_LICENSE("GPL"); module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode_option, "Specify resolution as \"x[-][@]\""); -- cgit v0.10.2 From be812195d8ac536a62cb1eb5c29b5f2fefefb621 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Wed, 12 Sep 2012 07:47:07 +0000 Subject: powerpc/pseries: Double NR_CPUS in defconfig Anticipating growth in coming years, we should ensure we are getting a good lead on testing. Signed-off-by: Nishanth Aravamudan Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 1f710a3..5b8e1e5 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -2,7 +2,7 @@ CONFIG_PPC64=y CONFIG_ALTIVEC=y CONFIG_VSX=y CONFIG_SMP=y -CONFIG_NR_CPUS=1024 +CONFIG_NR_CPUS=2048 CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -- cgit v0.10.2 From 8662d0bcab61032fb453550bed6945b09fbb7d73 Mon Sep 17 00:00:00 2001 From: Matthew McClintock Date: Tue, 18 Sep 2012 09:50:55 +0000 Subject: powerpc: dtc is required to build dtb files Fixes this following: $ make distclean; make corenet32_smp_defconfig; make p4080ds.dtb CLEAN arch/powerpc/boot CLEAN scripts/basic CLEAN scripts/dtc CLEAN scripts/genksyms CLEAN scripts/kconfig CLEAN scripts/mod CLEAN scripts CLEAN include/config include/generated CLEAN .config HOSTCC scripts/basic/fixdep HOSTCC scripts/kconfig/conf.o SHIPPED scripts/kconfig/zconf.tab.c SHIPPED scripts/kconfig/zconf.lex.c SHIPPED scripts/kconfig/zconf.hash.c HOSTCC scripts/kconfig/zconf.tab.o HOSTLD scripts/kconfig/conf scripts/kconfig/conf --silentoldconfig Kconfig DTC arch/powerpc/boot/p4080ds.dtb /bin/sh: /local/home/mattsm/git/linux/scripts/dtc/dtc: No such file or directory make[1]: *** [arch/powerpc/boot/p4080ds.dtb] Error 1 make: *** [p4080ds.dtb] Error 2 Signed-off-by: Matthew McClintock Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 159e94f..b639852 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -181,7 +181,7 @@ $(BOOT_TARGETS2): vmlinux bootwrapper_install: $(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@) -%.dtb: +%.dtb: scripts $(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@) define archhelp -- cgit v0.10.2 From 1afc149def25ac1c44a83882f6c0e42a8e88ce9f Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Tue, 2 Oct 2012 15:52:19 +0000 Subject: powerpc/47x: Use the new ppc-opcode infrastructure Don't use 47x only #defines for TLBIVAX or ICBT, supply and use helpers in ppc-opcode.h This fixes a compile breakage. Signed-off-by: Tony Breeds Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 5f73ce6..66bec46 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -86,6 +86,7 @@ #define PPC_INST_DCBA_MASK 0xfc0007fe #define PPC_INST_DCBAL 0x7c2005ec #define PPC_INST_DCBZL 0x7c2007ec +#define PPC_INST_ICBT 0x7c00002c #define PPC_INST_ISEL 0x7c00001e #define PPC_INST_ISEL_MASK 0xfc00003e #define PPC_INST_LDARX 0x7c0000a8 @@ -198,6 +199,7 @@ #define __PPC_MB(s) (((s) & 0x1f) << 6) #define __PPC_ME(s) (((s) & 0x1f) << 1) #define __PPC_BI(s) (((s) & 0x1f) << 16) +#define __PPC_CT(t) (((t) & 0x0f) << 21) /* * Only use the larx hint bit on 64bit CPUs. e500v1/v2 based CPUs will treat a @@ -260,6 +262,8 @@ __PPC_RS(t) | __PPC_RA0(a) | __PPC_RB(b)) #define PPC_SLBFEE_DOT(t, b) stringify_in_c(.long PPC_INST_SLBFEE | \ __PPC_RT(t) | __PPC_RB(b)) +#define PPC_ICBT(c,a,b) stringify_in_c(.long PPC_INST_ICBT | \ + __PPC_CT(c) | __PPC_RA0(a) | __PPC_RB(b)) /* PASemi instructions */ #define LBZCIX(t,a,b) stringify_in_c(.long PPC_INST_LBZCIX | \ __PPC_RT(t) | __PPC_RA(a) | __PPC_RB(b)) diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S index fab919f..626ad08 100644 --- a/arch/powerpc/mm/tlb_nohash_low.S +++ b/arch/powerpc/mm/tlb_nohash_low.S @@ -191,12 +191,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x) #ifdef CONFIG_PPC_47x /* - * 47x variant of icbt - */ -# define ICBT(CT,RA,RB) \ - .long 0x7c00002c | ((CT) << 21) | ((RA) << 16) | ((RB) << 11) - -/* * _tlbivax_bcast is only on 47x. We don't bother doing a runtime * check though, it will blow up soon enough if we mistakenly try * to use it on a 440. @@ -208,8 +202,7 @@ _GLOBAL(_tlbivax_bcast) wrteei 0 mtspr SPRN_MMUCR,r5 isync -/* tlbivax 0,r3 - use .long to avoid binutils deps */ - .long 0x7c000624 | (r3 << 11) + PPC_TLBIVAX(0, R3) isync eieio tlbsync @@ -227,11 +220,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_476_DD2) bl 2f 2: mflr r6 li r7,32 - ICBT(0,r6,r7) /* touch next cache line */ + PPC_ICBT(0,R6,R7) /* touch next cache line */ add r6,r6,r7 - ICBT(0,r6,r7) /* touch next cache line */ + PPC_ICBT(0,R6,R7) /* touch next cache line */ add r6,r6,r7 - ICBT(0,r6,r7) /* touch next cache line */ + PPC_ICBT(0,R6,R7) /* touch next cache line */ sync nop nop -- cgit v0.10.2 From 0dc3289c797ef9558af566802429212e0b58a5d9 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Tue, 2 Oct 2012 15:52:41 +0000 Subject: powerpc: Add asm/debug.h to get powerpc_debugfs_root Since the "Disintegrate asm/system.h for PowerPC" (ae3a197e3d0bfe3f4bf1693723e82dc018c096f3) This has been failing when DEBUG is #defined. Signed-off-by: Tony Breeds Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 37725e8..f5ca76a 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -54,6 +54,7 @@ #include #include #include +#include #include -- cgit v0.10.2 From f7fb862b843269d02a2fa75e4bbb49603f801b88 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 8 Oct 2012 03:00:04 +0000 Subject: powerpc/windfarm: Use module_i2c_driver to simplify the code Use the module_i2c_driver() macro to make the code smaller and a bit simpler. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/macintosh/windfarm_fcu_controls.c b/drivers/macintosh/windfarm_fcu_controls.c index b3411ed..fd6ed15 100644 --- a/drivers/macintosh/windfarm_fcu_controls.c +++ b/drivers/macintosh/windfarm_fcu_controls.c @@ -593,19 +593,7 @@ static struct i2c_driver wf_fcu_driver = { .id_table = wf_fcu_id, }; -static int __init wf_fcu_init(void) -{ - return i2c_add_driver(&wf_fcu_driver); -} - -static void __exit wf_fcu_exit(void) -{ - i2c_del_driver(&wf_fcu_driver); -} - - -module_init(wf_fcu_init); -module_exit(wf_fcu_exit); +module_i2c_driver(wf_fcu_driver); MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("FCU control objects for PowerMacs thermal control"); diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index b0c2d36..9ef32b3 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -174,19 +174,7 @@ static struct i2c_driver wf_lm75_driver = { .id_table = wf_lm75_id, }; -static int __init wf_lm75_sensor_init(void) -{ - return i2c_add_driver(&wf_lm75_driver); -} - -static void __exit wf_lm75_sensor_exit(void) -{ - i2c_del_driver(&wf_lm75_driver); -} - - -module_init(wf_lm75_sensor_init); -module_exit(wf_lm75_sensor_exit); +module_i2c_driver(wf_lm75_driver); MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control"); diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index 371b058..945a25b 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c @@ -130,18 +130,7 @@ static struct i2c_driver wf_max6690_driver = { .id_table = wf_max6690_id, }; -static int __init wf_max6690_sensor_init(void) -{ - return i2c_add_driver(&wf_max6690_driver); -} - -static void __exit wf_max6690_sensor_exit(void) -{ - i2c_del_driver(&wf_max6690_driver); -} - -module_init(wf_max6690_sensor_init); -module_exit(wf_max6690_sensor_exit); +module_i2c_driver(wf_max6690_driver); MODULE_AUTHOR("Paul Mackerras "); MODULE_DESCRIPTION("MAX6690 sensor objects for PowerMac thermal control"); diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 426e810..d87f5ee 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -364,18 +364,7 @@ static struct i2c_driver wf_sat_driver = { .id_table = wf_sat_id, }; -static int __init sat_sensors_init(void) -{ - return i2c_add_driver(&wf_sat_driver); -} - -static void __exit sat_sensors_exit(void) -{ - i2c_del_driver(&wf_sat_driver); -} - -module_init(sat_sensors_init); -module_exit(sat_sensors_exit); +module_i2c_driver(wf_sat_driver); MODULE_AUTHOR("Paul Mackerras "); MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control"); -- cgit v0.10.2 From 6432200aa8de3242d64c02e0bf29305147df0171 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 9 Oct 2012 04:20:28 +0000 Subject: powerpc/udbg: Remove unused udbg_read() The last user of udbg_read() was removed in 2005, in commit fca5dcd "Simplify and clean up the xmon terminal I/O". Given we haven't needed it for 7 years we can probably drop it. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h index b303881..5a7510e 100644 --- a/arch/powerpc/include/asm/udbg.h +++ b/arch/powerpc/include/asm/udbg.h @@ -21,7 +21,6 @@ extern int (*udbg_getc_poll)(void); extern void udbg_puts(const char *s); extern int udbg_write(const char *s, int n); -extern int udbg_read(char *buf, int buflen); extern void register_early_udbg_console(void); extern void udbg_printf(const char *fmt, ...) diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index c39c1ca..f974849 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -122,29 +122,6 @@ int udbg_write(const char *s, int n) return n - remain; } -int udbg_read(char *buf, int buflen) -{ - char *p = buf; - int i, c; - - if (!udbg_getc) - return 0; - - for (i = 0; i < buflen; ++i) { - do { - c = udbg_getc(); - if (c == -1 && i == 0) - return -1; - - } while (c == 0x11 || c == 0x13); - if (c == 0 || c == -1) - break; - *p++ = c; - } - - return i; -} - #define UDBG_BUFSIZE 256 void udbg_printf(const char *fmt, ...) { -- cgit v0.10.2 From eb1c2abb611b51a935cdb36bbc0e364958ccb83c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 9 Oct 2012 04:20:29 +0000 Subject: powerpc/xmon: Remove unused xmon_expect() & xmon_read_poll() It looks like xmon_expect() was used for doing xmon over a modem (!?), that code was dropped in 2005 in commit 51d3082 "Unify udbg (#2)". Once xmon_expect() is gone xmon_read_poll() is unused, drop it too. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/xmon/nonstdio.c b/arch/powerpc/xmon/nonstdio.c index bfac84f..a225d80 100644 --- a/arch/powerpc/xmon/nonstdio.c +++ b/arch/powerpc/xmon/nonstdio.c @@ -23,33 +23,6 @@ static char line[256]; static char *lineptr; static int lineleft; -int xmon_expect(const char *str, unsigned long timeout) -{ - int c; - unsigned long t0; - - /* assume 25MHz default timebase if tb_ticks_per_sec not set yet */ - timeout *= tb_ticks_per_sec? tb_ticks_per_sec: 25000000; - t0 = get_tbl(); - do { - lineptr = line; - for (;;) { - c = xmon_read_poll(); - if (c == -1) { - if (get_tbl() - t0 > timeout) - return 0; - continue; - } - if (c == '\n') - break; - if (c != '\r' && lineptr < &line[sizeof(line) - 1]) - *lineptr++ = c; - } - *lineptr = 0; - } while (strstr(line, str) == NULL); - return 1; -} - int xmon_getchar(void) { int c; diff --git a/arch/powerpc/xmon/nonstdio.h b/arch/powerpc/xmon/nonstdio.h index 23dd95f..d8cec38 100644 --- a/arch/powerpc/xmon/nonstdio.h +++ b/arch/powerpc/xmon/nonstdio.h @@ -9,7 +9,5 @@ extern void xmon_puts(const char *); extern char *xmon_gets(char *, int); extern void xmon_printf(const char *, ...); extern void xmon_map_scc(void); -extern int xmon_expect(const char *str, unsigned long timeout); extern int xmon_write(const void *ptr, int nb); extern int xmon_readchar(void); -extern int xmon_read_poll(void); diff --git a/arch/powerpc/xmon/start.c b/arch/powerpc/xmon/start.c index 8864de2..84f3a15 100644 --- a/arch/powerpc/xmon/start.c +++ b/arch/powerpc/xmon/start.c @@ -25,10 +25,3 @@ int xmon_readchar(void) return udbg_getc(); return -1; } - -int xmon_read_poll(void) -{ - if (udbg_getc_poll) - return udbg_getc_poll(); - return -1; -} -- cgit v0.10.2 From 08702c73a6182d0f6a429271383a553abc92c0b8 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 9 Oct 2012 04:20:30 +0000 Subject: powerpc/xmon: Remove empty xmon_map_scc() This has been empty since 2005, commit 51d3082 "Unify udbg (#2)". Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/xmon/nonstdio.h b/arch/powerpc/xmon/nonstdio.h index d8cec38..8799ccf 100644 --- a/arch/powerpc/xmon/nonstdio.h +++ b/arch/powerpc/xmon/nonstdio.h @@ -8,6 +8,5 @@ extern int xmon_getchar(void); extern void xmon_puts(const char *); extern char *xmon_gets(char *, int); extern void xmon_printf(const char *, ...); -extern void xmon_map_scc(void); extern int xmon_write(const void *ptr, int nb); extern int xmon_readchar(void); diff --git a/arch/powerpc/xmon/start.c b/arch/powerpc/xmon/start.c index 84f3a15..7769cb5 100644 --- a/arch/powerpc/xmon/start.c +++ b/arch/powerpc/xmon/start.c @@ -10,10 +10,6 @@ #include #include "nonstdio.h" -void xmon_map_scc(void) -{ -} - int xmon_write(const void *ptr, int nb) { return udbg_write(ptr, nb); diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 3a56a63..67d36ab 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2943,7 +2943,6 @@ static void xmon_init(int enable) __debugger_dabr_match = NULL; __debugger_fault_handler = NULL; } - xmon_map_scc(); } #ifdef CONFIG_MAGIC_SYSRQ -- cgit v0.10.2 From 88c6d62641514686e0b1b0e33d9faf1e39ec7e58 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 9 Oct 2012 04:20:31 +0000 Subject: powerpc/xmon: Make xmon_getchar() static xmon_getchar() is only called from within nonstdio.c, so make it static. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/xmon/nonstdio.c b/arch/powerpc/xmon/nonstdio.c index a225d80..2209485 100644 --- a/arch/powerpc/xmon/nonstdio.c +++ b/arch/powerpc/xmon/nonstdio.c @@ -23,7 +23,7 @@ static char line[256]; static char *lineptr; static int lineleft; -int xmon_getchar(void) +static int xmon_getchar(void) { int c; diff --git a/arch/powerpc/xmon/nonstdio.h b/arch/powerpc/xmon/nonstdio.h index 8799ccf..321284f 100644 --- a/arch/powerpc/xmon/nonstdio.h +++ b/arch/powerpc/xmon/nonstdio.h @@ -4,7 +4,6 @@ #define putchar xmon_putchar extern int xmon_putchar(int c); -extern int xmon_getchar(void); extern void xmon_puts(const char *); extern char *xmon_gets(char *, int); extern void xmon_printf(const char *, ...); -- cgit v0.10.2 From 33b5cd686649f56d40fa258a0881f6acdbd70134 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 9 Oct 2012 04:20:32 +0000 Subject: powerpc/xmon: Merge start.c into nonstdio.c The routines in start.c are only ever called from nonstdio.c, so if we move them in there they can become static which is nice. I suspect the idea behind the separation was that start.c could be replaced in order to build xmon in userland. If anyone still cares about doing that we could handle that with an ifdef or two. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile index c168c54e..b49fdbd 100644 --- a/arch/powerpc/xmon/Makefile +++ b/arch/powerpc/xmon/Makefile @@ -6,7 +6,7 @@ GCOV_PROFILE := n ccflags-$(CONFIG_PPC64) := -mno-minimal-toc -obj-y += xmon.o start.o nonstdio.o +obj-y += xmon.o nonstdio.o ifdef CONFIG_XMON_DISASSEMBLY obj-y += ppc-dis.o ppc-opc.o diff --git a/arch/powerpc/xmon/nonstdio.c b/arch/powerpc/xmon/nonstdio.c index 2209485..942d0f6 100644 --- a/arch/powerpc/xmon/nonstdio.c +++ b/arch/powerpc/xmon/nonstdio.c @@ -7,9 +7,23 @@ * 2 of the License, or (at your option) any later version. */ #include +#include #include #include "nonstdio.h" + +static int xmon_write(const void *ptr, int nb) +{ + return udbg_write(ptr, nb); +} + +static int xmon_readchar(void) +{ + if (udbg_getc) + return udbg_getc(); + return -1; +} + int xmon_putchar(int c) { char ch = c; diff --git a/arch/powerpc/xmon/nonstdio.h b/arch/powerpc/xmon/nonstdio.h index 321284f..18a51de 100644 --- a/arch/powerpc/xmon/nonstdio.h +++ b/arch/powerpc/xmon/nonstdio.h @@ -7,5 +7,3 @@ extern int xmon_putchar(int c); extern void xmon_puts(const char *); extern char *xmon_gets(char *, int); extern void xmon_printf(const char *, ...); -extern int xmon_write(const void *ptr, int nb); -extern int xmon_readchar(void); diff --git a/arch/powerpc/xmon/start.c b/arch/powerpc/xmon/start.c deleted file mode 100644 index 7769cb5..0000000 --- a/arch/powerpc/xmon/start.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 1996 Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include "nonstdio.h" - -int xmon_write(const void *ptr, int nb) -{ - return udbg_write(ptr, nb); -} - -int xmon_readchar(void) -{ - if (udbg_getc) - return udbg_getc(); - return -1; -} -- cgit v0.10.2 From b3dc19cddce37a1aaebc911c8db94e5209a9764d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 9 Oct 2012 04:20:33 +0000 Subject: powerpc/xmon: Remove renaming #defines of scanhex() and skipbl() We have two #defines that rename scanhex() and skipbl() to xmon_scanhex() and xmon_skipbl() - but no one ever uses those names. So the only effect is to rename the actual symbols in the generated code, and AFACIS there is no reason to do that, so drop them. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 67d36ab..cc96a71 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -52,9 +52,6 @@ #include "nonstdio.h" #include "dis-asm.h" -#define scanhex xmon_scanhex -#define skipbl xmon_skipbl - #ifdef CONFIG_SMP static cpumask_t cpus_in_xmon = CPU_MASK_NONE; static unsigned long xmon_taken = 1; -- cgit v0.10.2 From c5c5714d5093e677ec962921210eae14156f7179 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 9 Oct 2012 04:20:34 +0000 Subject: powerpc/xmon: Remove unused #defines Neither REGS_PER_LINE or LAST_VOLATILE are used, nor have they ever been as far back as I can see. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index cc96a71..abf6be4 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -166,12 +166,8 @@ extern void xmon_leave(void); #ifdef CONFIG_PPC64 #define REG "%.16lx" -#define REGS_PER_LINE 4 -#define LAST_VOLATILE 13 #else #define REG "%.8lx" -#define REGS_PER_LINE 8 -#define LAST_VOLATILE 12 #endif #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) -- cgit v0.10.2 From c4de38093ed9fe94fa35c3adb14afc40bf05e1da Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 9 Oct 2012 04:20:35 +0000 Subject: powerpc/xmon: Use STACK_FRAME_OVERHEAD in xmon_show_stack() We use STACK_FRAME_OVERHEAD in the exception vectors to establish the exception frame, so it should be good enough to use here. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index abf6be4..d940234 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -1286,12 +1286,6 @@ static int xmon_depth_to_print = 64; #define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long)) #define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long)) -#ifdef __powerpc64__ -#define REGS_OFFSET 0x70 -#else -#define REGS_OFFSET 16 -#endif - static void xmon_show_stack(unsigned long sp, unsigned long lr, unsigned long pc) { @@ -1355,10 +1349,10 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr, an exception frame. */ if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long)) && marker == STACK_FRAME_REGS_MARKER) { - if (mread(sp + REGS_OFFSET, ®s, sizeof(regs)) + if (mread(sp + STACK_FRAME_OVERHEAD, ®s, sizeof(regs)) != sizeof(regs)) { printf("Couldn't read registers at %lx\n", - sp + REGS_OFFSET); + sp + STACK_FRAME_OVERHEAD); break; } printf("--- Exception: %lx %s at ", regs.trap, -- cgit v0.10.2 From 0104cd6839bd575f0aa1af4125eb865dc0391aae Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 9 Oct 2012 04:20:36 +0000 Subject: powerpc/xmon: Fiddle xmon_depth_to_print logic in xmon_show_stack() Currently xmon_depth_to_print is static and global, but it's only ever used in xmon_show_stack(). At least with a modern compiler it's inlined, so there's no point in it being static, we could #define it but it's only used in one place. By reworking the logic we can drop count and just decrement the max value as a loop counter. Also switch to a while loop so we actually print no more than 64 frames as you'd expect based on the variable name. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index d940234..1f8d2f1 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -1281,21 +1281,19 @@ static void get_function_bounds(unsigned long pc, unsigned long *startp, catch_memory_errors = 0; } -static int xmon_depth_to_print = 64; - #define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long)) #define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long)) static void xmon_show_stack(unsigned long sp, unsigned long lr, unsigned long pc) { + int max_to_print = 64; unsigned long ip; unsigned long newsp; unsigned long marker; - int count = 0; struct pt_regs regs; - do { + while (max_to_print--) { if (sp < PAGE_OFFSET) { if (sp != 0) printf("SP (%lx) is in userspace\n", sp); @@ -1366,7 +1364,7 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr, break; sp = newsp; - } while (count++ < xmon_depth_to_print); + } } static void backtrace(struct pt_regs *excp) -- cgit v0.10.2 From b2bb65f680a7b2faa5d6332c02752dca83a49cd6 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 9 Oct 2012 04:20:47 +0000 Subject: powerpc/xmon: Fallback to printk() in xmon_printf() if udbg is not setup It is possible to configure a kernel which has xmon enabled, but has no udbg backend to provide IO. This can make xmon rather confusing, as it produces no output, blocks for two seconds, and then returns. As a last resort we can instead try to printk(), which may deadlock or otherwise crash, but tries quite hard not to. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/xmon/nonstdio.c b/arch/powerpc/xmon/nonstdio.c index 942d0f6..bce3dcf 100644 --- a/arch/powerpc/xmon/nonstdio.c +++ b/arch/powerpc/xmon/nonstdio.c @@ -111,13 +111,19 @@ char *xmon_gets(char *str, int nb) void xmon_printf(const char *format, ...) { va_list args; - int n; static char xmon_outbuf[1024]; + int rc, n; va_start(args, format); n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args); va_end(args); - xmon_write(xmon_outbuf, n); + + rc = xmon_write(xmon_outbuf, n); + + if (n && rc == 0) { + /* No udbg hooks, fallback to printk() - dangerous */ + printk(xmon_outbuf); + } } void xmon_puts(const char *str) -- cgit v0.10.2 From 40c935ae3de413d6bbc5471c231c90e26a63d562 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 10 Oct 2012 08:32:30 +0000 Subject: powerpc/sysdev: Use module_platform_driver macro This patch removes some code duplication by using module_platform_driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c index 8f04654..5aaf86c 100644 --- a/arch/powerpc/sysdev/pmi.c +++ b/arch/powerpc/sysdev/pmi.c @@ -214,18 +214,7 @@ static struct platform_driver pmi_of_platform_driver = { .of_match_table = pmi_match, }, }; - -static int __init pmi_module_init(void) -{ - return platform_driver_register(&pmi_of_platform_driver); -} -module_init(pmi_module_init); - -static void __exit pmi_module_exit(void) -{ - platform_driver_unregister(&pmi_of_platform_driver); -} -module_exit(pmi_module_exit); +module_platform_driver(pmi_of_platform_driver); int pmi_send_message(pmi_message_t msg) { -- cgit v0.10.2 From 490e078d6a21aa90d54f36cdcc544e87070175bd Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 17 Oct 2012 19:53:30 +0000 Subject: powerpc/pnv: Avoid bogus output There're couples of functions defined to print debugging messages during initializing P7IOC. However, we got bogus output from those functions like pe_info(). The problem here is that the message level (the first parameter to printk()) isn't printable and that caused the bogus output. The patch fixes the issue by merging __pe_printk() to the macro define_pe_printk_level() so that we can pass the message level directly to printk(). Reported-by: Benjamin Herrenschmidt Signed-off-by: Gavin Shan Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 471aa3c..53d052e 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -34,24 +34,12 @@ #include "powernv.h" #include "pci.h" -static int __pe_printk(const char *level, const struct pnv_ioda_pe *pe, - struct va_format *vaf) -{ - char pfix[32]; - - if (pe->pdev) - strlcpy(pfix, dev_name(&pe->pdev->dev), sizeof(pfix)); - else - sprintf(pfix, "%04x:%02x ", - pci_domain_nr(pe->pbus), pe->pbus->number); - return printk("pci %s%s: [PE# %.3d] %pV", level, pfix, pe->pe_number, vaf); -} - #define define_pe_printk_level(func, kern_level) \ static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \ { \ struct va_format vaf; \ va_list args; \ + char pfix[32]; \ int r; \ \ va_start(args, fmt); \ @@ -59,7 +47,16 @@ static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \ vaf.fmt = fmt; \ vaf.va = &args; \ \ - r = __pe_printk(kern_level, pe, &vaf); \ + if (pe->pdev) \ + strlcpy(pfix, dev_name(&pe->pdev->dev), \ + sizeof(pfix)); \ + else \ + sprintf(pfix, "%04x:%02x ", \ + pci_domain_nr(pe->pbus), \ + pe->pbus->number); \ + r = printk(kern_level "pci %s: [PE# %.3d] %pV", \ + pfix, pe->pe_number, &vaf); \ + \ va_end(args); \ \ return r; \ -- cgit v0.10.2 From bc26957c6cd913eaec9aac4ce17953efc1582c2e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 21 Oct 2012 00:52:05 +0000 Subject: powerpc/rtas_flash: Eliminate possible double free The function initialize_flash_pde_data is only called four times. All four calls are in the function rtas_flash_init, and on the failure of any of the calls, remove_flash_pde is called on the third argument of each of the calls. There is thus no need for initialize_flash_pde_data to call remove_flash_pde on the same argument. remove_flash_pde kfrees the data field of its argument, and does not clear that field, so this amounts ot a possible double free. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r@ identifier f,free,a; parameter list[n] ps; type T; expression e; @@ f(ps,T a,...) { ... when any when != a = e if(...) { ... free(a); ... return ...; } ... when any } @@ identifier r.f,r.free; expression x,a; expression list[r.n] xs; @@ * x = f(xs,a,...); if (...) { ... free(a); ... return ...; } // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 20b0120..8329190 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -650,10 +650,8 @@ static int initialize_flash_pde_data(const char *rtas_call_name, int token; dp->data = kzalloc(buf_size, GFP_KERNEL); - if (dp->data == NULL) { - remove_flash_pde(dp); + if (dp->data == NULL) return -ENOMEM; - } /* * This code assumes that the status int is the first member of the -- cgit v0.10.2 From ab7f961a58b3d3390148d18cf95ae4ce6a411b21 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 21 Oct 2012 14:30:52 +0000 Subject: powerpc/powernv: Fix OPAL debug entry OPAL provides the firmware base/entry in registers at boot time for debugging purposes. We had a bug in the code trying to stash these into the appropriate kernel globals (a line of code was probably dropped by accident back when this was merged) Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 58bddee..694e3fa 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -703,6 +703,7 @@ _INIT_STATIC(start_here_multiplatform) #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL /* Setup OPAL entry */ + LOAD_REG_ADDR(r11, opal) std r28,0(r11); std r29,8(r11); #endif -- cgit v0.10.2 From 12660b170253255c012cb1352449e61ae9727079 Mon Sep 17 00:00:00 2001 From: Li Zhong Date: Mon, 22 Oct 2012 23:46:27 +0000 Subject: powerpc: Fix MAX_STACK_TRACE_ENTRIES too low warning ! This patch tries to fix the following BUG report: [ 0.012313] BUG: MAX_STACK_TRACE_ENTRIES too low! [ 0.012318] turning off the locking correctness validator. [ 0.012321] Call Trace: [ 0.012330] [c00000017666f6d0] [c000000000012128] .show_stack+0x78/0x184 (unreliable) [ 0.012339] [c00000017666f780] [c0000000000b6348] .save_trace+0x12c/0x14c [ 0.012345] [c00000017666f800] [c0000000000b7448] .mark_lock+0x2bc/0x710 [ 0.012351] [c00000017666f8b0] [c0000000000bb198] .__lock_acquire+0x748/0xaec [ 0.012357] [c00000017666f9b0] [c0000000000bb684] .lock_acquire+0x148/0x194 [ 0.012365] [c00000017666fa80] [c00000000069371c] .mutex_lock_nested+0x84/0x4ec [ 0.012372] [c00000017666fb90] [c000000000096998] .smpboot_register_percpu_thread+0x3c/0x10c [ 0.012380] [c00000017666fc30] [c0000000009ba910] .spawn_ksoftirqd+0x28/0x48 [ 0.012386] [c00000017666fcb0] [c00000000000a98c] .do_one_initcall+0xd8/0x1d0 [ 0.012392] [c00000017666fd60] [c00000000000b1f8] .kernel_init+0x120/0x398 [ 0.012398] [c00000017666fe30] [c000000000009ad4] .ret_from_kernel_thread+0x5c/0x64 [ 0.012404] [c00000017666fa00] [c00000017666fb20] 0xc00000017666fb20 [ 0.012410] [c00000017666fa80] [c00000000069371c] .mutex_lock_nested+0x84/0x4ec [ 0.012416] [c00000017666fb90] [c000000000096998] .smpboot_register_percpu_thread+0x3c/0x10c [ 0.012422] [c00000017666fc30] [c0000000009ba910] .spawn_ksoftirqd+0x28/0x48 [ 0.012427] [c00000017666fcb0] [c00000000000a98c] .do_one_initcall+0xd8/0x1d0 [ 0.012433] [c00000017666fd60] [c00000000000b1f8] .kernel_init+0x120/0x398 [ 0.012439] [c00000017666fe30] [c000000000009ad4] .ret_from_kernel_thread+0x5c/0x64 ....... The reason is that the back chain of c00000017666fe30 (ret_from_kernel_thread) contains some invalid value, which might form a loop. Signed-off-by: Li Zhong Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 56e0ff0..ad76666 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -374,6 +374,8 @@ _GLOBAL(ret_from_kernel_thread) bl .schedule_tail REST_NVGPRS(r1) REST_GPR(2,r1) + li r3,0 + std r3,0(r1) mtlr r14 mr r3,r15 blrl -- cgit v0.10.2 From 16b86bf2520ed29712ca7462dbfe76c856b445e9 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 24 Oct 2012 17:21:09 +0000 Subject: powerpc: Remove no longer used ppc_md.idle_loop() The last user of ppc_md.idle_loop() was removed when we dropped the legacy iSeries code, in commit 8ee3e0d. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index c423197..a338bc7 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -166,9 +166,6 @@ struct machdep_calls { unsigned long size, pgprot_t vma_prot); - /* Idle loop for this platform, leave empty for default idle loop */ - void (*idle_loop)(void); - /* * Function for waiting for work with reduced power in idle loop; * called with interrupts disabled. diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 2099d9a..ea78761 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -55,9 +55,6 @@ __setup("powersave=off", powersave_off); */ void cpu_idle(void) { - if (ppc_md.idle_loop) - ppc_md.idle_loop(); /* doesn't return */ - set_thread_flag(TIF_POLLING_NRFLAG); while (1) { tick_nohz_idle_enter(); -- cgit v0.10.2 From 6c7a2856ade6a58c20038024247d16a12a8d2323 Mon Sep 17 00:00:00 2001 From: "K.Prasad" Date: Sun, 28 Oct 2012 15:13:15 +0000 Subject: powerpc/hw-breakpoint: Use generic hw-breakpoint interfaces for new PPC ptrace flags PPC_PTRACE_GETHWDBGINFO, PPC_PTRACE_SETHWDEBUG and PPC_PTRACE_DELHWDEBUG are PowerPC specific ptrace flags that use the watchpoint register. While they are targeted primarily towards BookE users, user-space applications such as GDB have started using them for BookS too. This patch enables the use of generic hardware breakpoint interfaces for these new flags. Apart from the usual benefits of using generic hw-breakpoint interfaces, these changes allow debuggers (such as GDB) to use a common set of ptrace flags for their watchpoint needs and allow more precise breakpoint specification (length of the variable can be specified). Mikey added: rebased and added dbginfo.features around #ifdef CONFIG_HAVE_HW_BREAKPOINT Signed-off-by: K.Prasad Acked-by: David Gibson Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/Documentation/powerpc/ptrace.txt b/Documentation/powerpc/ptrace.txt index f4a5499..f2a7a39 100644 --- a/Documentation/powerpc/ptrace.txt +++ b/Documentation/powerpc/ptrace.txt @@ -127,6 +127,22 @@ Some examples of using the structure to: p.addr2 = (uint64_t) end_range; p.condition_value = 0; +- set a watchpoint in server processors (BookS) + + p.version = 1; + p.trigger_type = PPC_BREAKPOINT_TRIGGER_RW; + p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; + or + p.addr_mode = PPC_BREAKPOINT_MODE_EXACT; + + p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + p.addr = (uint64_t) begin_range; + /* For PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE addr2 needs to be specified, where + * addr2 - addr <= 8 Bytes. + */ + p.addr2 = (uint64_t) end_range; + p.condition_value = 0; + 3. PTRACE_DELHWDEBUG Takes an integer which identifies an existing breakpoint or watchpoint diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 79d8e56..140238a 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1338,6 +1338,12 @@ static int set_dac_range(struct task_struct *child, static long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_info) { +#ifdef CONFIG_HAVE_HW_BREAKPOINT + int len = 0; + struct thread_struct *thread = &(child->thread); + struct perf_event *bp; + struct perf_event_attr attr; +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ #ifndef CONFIG_PPC_ADV_DEBUG_REGS unsigned long dabr; #endif @@ -1381,13 +1387,9 @@ static long ppc_set_hwdebug(struct task_struct *child, */ if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 || (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 || - bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT || bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE) return -EINVAL; - if (child->thread.dabr) - return -ENOSPC; - if ((unsigned long)bp_info->addr >= TASK_SIZE) return -EIO; @@ -1397,6 +1399,50 @@ static long ppc_set_hwdebug(struct task_struct *child, dabr |= DABR_DATA_READ; if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE) dabr |= DABR_DATA_WRITE; +#ifdef CONFIG_HAVE_HW_BREAKPOINT + if (ptrace_get_breakpoints(child) < 0) + return -ESRCH; + + /* + * Check if the request is for 'range' breakpoints. We can + * support it if range < 8 bytes. + */ + if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE) { + len = bp_info->addr2 - bp_info->addr; + } else if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) { + ptrace_put_breakpoints(child); + return -EINVAL; + } + bp = thread->ptrace_bps[0]; + if (bp) { + ptrace_put_breakpoints(child); + return -ENOSPC; + } + + /* Create a new breakpoint request if one doesn't exist already */ + hw_breakpoint_init(&attr); + attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN; + attr.bp_len = len; + arch_bp_generic_fields(dabr & (DABR_DATA_WRITE | DABR_DATA_READ), + &attr.bp_type); + + thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr, + ptrace_triggered, NULL, child); + if (IS_ERR(bp)) { + thread->ptrace_bps[0] = NULL; + ptrace_put_breakpoints(child); + return PTR_ERR(bp); + } + + ptrace_put_breakpoints(child); + return 1; +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ + + if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) + return -EINVAL; + + if (child->thread.dabr) + return -ENOSPC; child->thread.dabr = dabr; child->thread.dabrx = DABRX_ALL; @@ -1407,6 +1453,11 @@ static long ppc_set_hwdebug(struct task_struct *child, static long ppc_del_hwdebug(struct task_struct *child, long addr, long data) { +#ifdef CONFIG_HAVE_HW_BREAKPOINT + int ret = 0; + struct thread_struct *thread = &(child->thread); + struct perf_event *bp; +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ #ifdef CONFIG_PPC_ADV_DEBUG_REGS int rc; @@ -1426,10 +1477,25 @@ static long ppc_del_hwdebug(struct task_struct *child, long addr, long data) #else if (data != 1) return -EINVAL; + +#ifdef CONFIG_HAVE_HW_BREAKPOINT + if (ptrace_get_breakpoints(child) < 0) + return -ESRCH; + + bp = thread->ptrace_bps[0]; + if (bp) { + unregister_hw_breakpoint(bp); + thread->ptrace_bps[0] = NULL; + } else + ret = -ENOENT; + ptrace_put_breakpoints(child); + return ret; +#else /* CONFIG_HAVE_HW_BREAKPOINT */ if (child->thread.dabr == 0) return -ENOENT; child->thread.dabr = 0; +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ return 0; #endif @@ -1536,7 +1602,11 @@ long arch_ptrace(struct task_struct *child, long request, dbginfo.data_bp_alignment = 4; #endif dbginfo.sizeof_condition = 0; +#ifdef CONFIG_HAVE_HW_BREAKPOINT + dbginfo.features = PPC_DEBUG_FEATURE_DATA_BP_RANGE; +#else dbginfo.features = 0; +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ if (!access_ok(VERIFY_WRITE, datavp, -- cgit v0.10.2 From 84295dfc5989aaeb6e7d4a9df235451194a54bba Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Sun, 28 Oct 2012 15:13:16 +0000 Subject: powerpc/ptrace: Fix spelling mistake s/intruction/instruction/ Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 140238a..7dd32d1 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1037,7 +1037,7 @@ void ptrace_disable(struct task_struct *child) } #ifdef CONFIG_PPC_ADV_DEBUG_REGS -static long set_intruction_bp(struct task_struct *child, +static long set_instruction_bp(struct task_struct *child, struct ppc_hw_breakpoint *bp_info) { int slot; @@ -1371,7 +1371,7 @@ static long ppc_set_hwdebug(struct task_struct *child, if ((bp_info->trigger_type != PPC_BREAKPOINT_TRIGGER_EXECUTE) || (bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)) return -EINVAL; - return set_intruction_bp(child, bp_info); + return set_instruction_bp(child, bp_info); } if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_EXACT) return set_dac(child, bp_info); -- cgit v0.10.2 From ec1b33dcd2c0ed773e6458d1c8b337966114562b Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Sun, 28 Oct 2012 15:13:17 +0000 Subject: powerpc/ptrace: Remove unused addr parameter in ppc_del_hwdebug() Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 7dd32d1..817b411 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1451,7 +1451,7 @@ static long ppc_set_hwdebug(struct task_struct *child, #endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */ } -static long ppc_del_hwdebug(struct task_struct *child, long addr, long data) +static long ppc_del_hwdebug(struct task_struct *child, long data) { #ifdef CONFIG_HAVE_HW_BREAKPOINT int ret = 0; @@ -1633,7 +1633,7 @@ long arch_ptrace(struct task_struct *child, long request, } case PPC_PTRACE_DELHWDEBUG: { - ret = ppc_del_hwdebug(child, addr, data); + ret = ppc_del_hwdebug(child, data); break; } -- cgit v0.10.2 From bb29b719372742939af05457aff1b59608764e89 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Sun, 28 Oct 2012 23:15:14 +0000 Subject: powerpc/powermac/cpufreq_32: Set non-infinite transition time for 7447A driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The transition time for the 7447A is around 8ms which makes it possible to use the ondemand governor. This has been tested on the iBook G4 (PowerBook6,7). Signed-off-by: Andreas Schwab Tested-by: Michel Dänzer Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index 6417119..311b804 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -55,6 +55,7 @@ static unsigned int low_freq; static unsigned int hi_freq; static unsigned int cur_freq; static unsigned int sleep_freq; +static unsigned long transition_latency; /* * Different models uses different mechanisms to switch the frequency @@ -403,7 +404,7 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) if (policy->cpu != 0) return -ENODEV; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cpuinfo.transition_latency = transition_latency; policy->cur = cur_freq; cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu); @@ -658,12 +659,14 @@ static int __init pmac_cpufreq_setup(void) if (!value) goto out; cur_freq = (*value) / 1000; + transition_latency = CPUFREQ_ETERNAL; /* Check for 7447A based MacRISC3 */ if (of_machine_is_compatible("MacRISC3") && of_get_property(cpunode, "dynamic-power-step", NULL) && PVR_VER(mfspr(SPRN_PVR)) == 0x8003) { pmac_cpufreq_init_7447A(cpunode); + transition_latency = 8000000; /* Check for other MacRISC3 machines */ } else if (of_machine_is_compatible("PowerBook3,4") || of_machine_is_compatible("PowerBook3,5") || -- cgit v0.10.2 From da111957796515755d95ec6773dc714350724a4e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 30 Oct 2012 16:09:56 +0000 Subject: powerpc/perf: Add missing L2 constraint handling in Power7 PMU If we have two cache events that require different settings of the L2SEL bits in MMCR1 then we can not schedule those events simultaneously. Add logic to the constraint handling to express that. Signed-off-by: Michael Ellerman Acked-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/perf/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c index 441af08..2ee01e3 100644 --- a/arch/powerpc/perf/power7-pmu.c +++ b/arch/powerpc/perf/power7-pmu.c @@ -54,8 +54,10 @@ * Layout of constraint bits: * 6666555555555544444444443333333333222222222211111111110000000000 * 3210987654321098765432109876543210987654321098765432109876543210 - * [ ><><><><><><> - * NC P6P5P4P3P2P1 + * < >< ><><><><><><> + * L2 NC P6P5P4P3P2P1 + * + * L2 - 16-18 - Required L2SEL value (select field) * * NC - number of counters * 15: NC error 0x8000 @@ -72,7 +74,7 @@ static int power7_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp) { - int pmc, sh; + int pmc, sh, unit; unsigned long mask = 0, value = 0; pmc = (event >> PM_PMC_SH) & PM_PMC_MSK; @@ -90,6 +92,15 @@ static int power7_get_constraint(u64 event, unsigned long *maskp, mask |= 0x8000; value |= 0x1000; } + + unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK; + if (unit == 6) { + /* L2SEL must be identical across events */ + int l2sel = (event >> PM_L2SEL_SH) & PM_L2SEL_MSK; + mask |= 0x7 << 16; + value |= l2sel << 16; + } + *maskp = mask; *valp = value; return 0; -- cgit v0.10.2 From cd5daaf713cf8d728a2be2a3673293fff9465d9a Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 30 Oct 2012 19:34:13 +0000 Subject: powerpc: make POWER7 setup code name generic We are going to reuse this in POWER8 so make the name generic. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index cde12f8..8f61934 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -38,7 +38,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ paca.o nvram_64.o firmware.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o -obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power7.o +obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o obj64-$(CONFIG_RELOCATABLE) += reloc_64.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o obj-$(CONFIG_PPC_A2) += cpu_setup_a2.o diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S new file mode 100644 index 0000000..76797c5 --- /dev/null +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -0,0 +1,95 @@ +/* + * This file contains low level CPU setup functions. + * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +/* Entry: r3 = crap, r4 = ptr to cputable entry + * + * Note that we can be called twice for pseudo-PVRs + */ +_GLOBAL(__setup_cpu_power7) + mflr r11 + bl __init_hvmode_206 + mtlr r11 + beqlr + li r0,0 + mtspr SPRN_LPID,r0 + bl __init_LPCR + bl __init_TLB + mtlr r11 + blr + +_GLOBAL(__restore_cpu_power7) + mflr r11 + mfmsr r3 + rldicl. r0,r3,4,63 + beqlr + li r0,0 + mtspr SPRN_LPID,r0 + bl __init_LPCR + bl __init_TLB + mtlr r11 + blr + +__init_hvmode_206: + /* Disable CPU_FTR_HVMODE and exit if MSR:HV is not set */ + mfmsr r3 + rldicl. r0,r3,4,63 + bnelr + ld r5,CPU_SPEC_FEATURES(r4) + LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE) + xor r5,r5,r6 + std r5,CPU_SPEC_FEATURES(r4) + blr + +__init_LPCR: + /* Setup a sane LPCR: + * + * LPES = 0b01 (HSRR0/1 used for 0x500) + * PECE = 0b111 + * DPFD = 4 + * HDICE = 0 + * VC = 0b100 (VPM0=1, VPM1=0, ISL=0) + * VRMASD = 0b10000 (L=1, LP=00) + * + * Other bits untouched for now + */ + mfspr r3,SPRN_LPCR + li r5,1 + rldimi r3,r5, LPCR_LPES_SH, 64-LPCR_LPES_SH-2 + ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2) + li r5,4 + rldimi r3,r5, LPCR_DPFD_SH, 64-LPCR_DPFD_SH-3 + clrrdi r3,r3,1 /* clear HDICE */ + li r5,4 + rldimi r3,r5, LPCR_VC_SH, 0 + li r5,0x10 + rldimi r3,r5, LPCR_VRMASD_SH, 64-LPCR_VRMASD_SH-5 + mtspr SPRN_LPCR,r3 + isync + blr + +__init_TLB: + /* Clear the TLB */ + li r6,128 + mtctr r6 + li r7,0xc00 /* IS field = 0b11 */ + ptesync +2: tlbiel r7 + addi r7,r7,0x1000 + bdnz 2b + ptesync +1: blr diff --git a/arch/powerpc/kernel/cpu_setup_power7.S b/arch/powerpc/kernel/cpu_setup_power7.S deleted file mode 100644 index 76797c5..0000000 --- a/arch/powerpc/kernel/cpu_setup_power7.S +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This file contains low level CPU setup functions. - * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include - -/* Entry: r3 = crap, r4 = ptr to cputable entry - * - * Note that we can be called twice for pseudo-PVRs - */ -_GLOBAL(__setup_cpu_power7) - mflr r11 - bl __init_hvmode_206 - mtlr r11 - beqlr - li r0,0 - mtspr SPRN_LPID,r0 - bl __init_LPCR - bl __init_TLB - mtlr r11 - blr - -_GLOBAL(__restore_cpu_power7) - mflr r11 - mfmsr r3 - rldicl. r0,r3,4,63 - beqlr - li r0,0 - mtspr SPRN_LPID,r0 - bl __init_LPCR - bl __init_TLB - mtlr r11 - blr - -__init_hvmode_206: - /* Disable CPU_FTR_HVMODE and exit if MSR:HV is not set */ - mfmsr r3 - rldicl. r0,r3,4,63 - bnelr - ld r5,CPU_SPEC_FEATURES(r4) - LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE) - xor r5,r5,r6 - std r5,CPU_SPEC_FEATURES(r4) - blr - -__init_LPCR: - /* Setup a sane LPCR: - * - * LPES = 0b01 (HSRR0/1 used for 0x500) - * PECE = 0b111 - * DPFD = 4 - * HDICE = 0 - * VC = 0b100 (VPM0=1, VPM1=0, ISL=0) - * VRMASD = 0b10000 (L=1, LP=00) - * - * Other bits untouched for now - */ - mfspr r3,SPRN_LPCR - li r5,1 - rldimi r3,r5, LPCR_LPES_SH, 64-LPCR_LPES_SH-2 - ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2) - li r5,4 - rldimi r3,r5, LPCR_DPFD_SH, 64-LPCR_DPFD_SH-3 - clrrdi r3,r3,1 /* clear HDICE */ - li r5,4 - rldimi r3,r5, LPCR_VC_SH, 0 - li r5,0x10 - rldimi r3,r5, LPCR_VRMASD_SH, 64-LPCR_VRMASD_SH-5 - mtspr SPRN_LPCR,r3 - isync - blr - -__init_TLB: - /* Clear the TLB */ - li r6,128 - mtctr r6 - li r7,0xc00 /* IS field = 0b11 */ - ptesync -2: tlbiel r7 - addi r7,r7,0x1000 - bdnz 2b - ptesync -1: blr -- cgit v0.10.2 From aec937b1ee6d7b28499d50ea6df1b2fe9edee91b Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 30 Oct 2012 19:34:14 +0000 Subject: powerpc: Add POWER8 setup code Just a copy of POWER7 for now. Will update with new code later. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 76797c5..a92101d 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -44,6 +44,30 @@ _GLOBAL(__restore_cpu_power7) mtlr r11 blr +_GLOBAL(__setup_cpu_power8) + mflr r11 + bl __init_hvmode_206 + mtlr r11 + beqlr + li r0,0 + mtspr SPRN_LPID,r0 + bl __init_LPCR + bl __init_TLB + mtlr r11 + blr + +_GLOBAL(__restore_cpu_power8) + mflr r11 + mfmsr r3 + rldicl. r0,r3,4,63 + beqlr + li r0,0 + mtspr SPRN_LPID,r0 + bl __init_LPCR + bl __init_TLB + mtlr r11 + blr + __init_hvmode_206: /* Disable CPU_FTR_HVMODE and exit if MSR:HV is not set */ mfmsr r3 diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 0514c21..361f6d9 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -68,6 +68,8 @@ extern void __restore_cpu_pa6t(void); extern void __restore_cpu_ppc970(void); extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec); extern void __restore_cpu_power7(void); +extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec); +extern void __restore_cpu_power8(void); extern void __restore_cpu_a2(void); #endif /* CONFIG_PPC64 */ #if defined(CONFIG_E500) -- cgit v0.10.2 From 71e184972456a8095657e80fd1470a3857b441a0 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Tue, 30 Oct 2012 19:34:15 +0000 Subject: powerpc: POWER8 cputable entry Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 21a0687..76f81bd 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -401,6 +401,14 @@ extern const char *powerpc_base_platform; CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY) +#define CPU_FTRS_POWER8 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_ARCH_206 |\ + CPU_FTR_MMCRA | CPU_FTR_SMT | \ + CPU_FTR_COHERENT_ICACHE | \ + CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ + CPU_FTR_DSCR | CPU_FTR_SAO | \ + CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ + CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY) #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ @@ -421,8 +429,8 @@ extern const char *powerpc_base_platform; #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \ - CPU_FTRS_POWER7 | CPU_FTRS_CELL | CPU_FTRS_PA6T | \ - CPU_FTR_VSX) + CPU_FTRS_POWER7 | CPU_FTRS_POWER8 | CPU_FTRS_CELL | \ + CPU_FTRS_PA6T | CPU_FTR_VSX) #endif #else enum { diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 5e38eed..691fd8a 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -101,6 +101,7 @@ #define MMU_FTRS_POWER5 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE #define MMU_FTRS_POWER6 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE #define MMU_FTRS_POWER7 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE +#define MMU_FTRS_POWER8 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE #define MMU_FTRS_CELL MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ MMU_FTR_CI_LARGE_PAGE #define MMU_FTRS_PA6T MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index d24c141..7b44a6e 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1029,6 +1029,7 @@ #define PVR_970MP 0x0044 #define PVR_970GX 0x0045 #define PVR_POWER7p 0x004A +#define PVR_POWER8 0x004B #define PVR_BE 0x0070 #define PVR_PA6T 0x0090 diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 361f6d9..216ff84 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -96,6 +96,10 @@ extern void __restore_cpu_e5500(void); PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \ PPC_FEATURE_TRUE_LE | \ PPC_FEATURE_PSERIES_PERFMON_COMPAT) +#define COMMON_USER_POWER8 (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_06 |\ + PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \ + PPC_FEATURE_TRUE_LE | \ + PPC_FEATURE_PSERIES_PERFMON_COMPAT) #define COMMON_USER_PA6T (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\ PPC_FEATURE_TRUE_LE | \ PPC_FEATURE_HAS_ALTIVEC_COMP) @@ -465,6 +469,23 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_restore = __restore_cpu_power7, .platform = "power7+", }, + { /* Power8 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x004b0000, + .cpu_name = "POWER8 (raw)", + .cpu_features = CPU_FTRS_POWER8, + .cpu_user_features = COMMON_USER_POWER8, + .mmu_features = MMU_FTRS_POWER8, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, + .oprofile_cpu_type = "ppc64/power8", + .oprofile_type = PPC_OPROFILE_POWER4, + .cpu_setup = __setup_cpu_power8, + .cpu_restore = __restore_cpu_power8, + .platform = "power8", + }, { /* Cell Broadband Engine */ .pvr_mask = 0xffff0000, .pvr_value = 0x00700000, -- cgit v0.10.2 From 51cf2b30a552fe890a1af83cc0bcf49f92d82e58 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 31 Oct 2012 18:58:36 +0000 Subject: powerpc: Fix denorm symbol name Fix global symbol name to match actual denorm_exception_hv label. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 10b658a..5663018 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -276,7 +276,7 @@ vsx_unavailable_pSeries_1: KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_STD, 0x1300) . = 0x1500 - .global denorm_Hypervisor + .global denorm_exception_hv denorm_exception_hv: HMT_MEDIUM mtspr SPRN_SPRG_HSCRATCH0,r13 -- cgit v0.10.2 From 560285cd2c6f535b18b701900d3c028bb31f4dba Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 1 Nov 2012 14:55:04 +0000 Subject: powerpc: Move most of setup.h out of uapi Most of setup.h should not be exported to userspace, so move it back. All we are left with is the asm-generic include to pick up the COMMAND_LINE_SIZE define. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h new file mode 100644 index 0000000..8568c69 --- /dev/null +++ b/arch/powerpc/include/asm/setup.h @@ -0,0 +1,33 @@ +#ifndef _ASM_POWERPC_SETUP_H +#define _ASM_POWERPC_SETUP_H + +#include + +#ifndef __ASSEMBLY__ +extern void ppc_printk_progress(char *s, unsigned short hex); + +extern unsigned int rtas_data; +extern int mem_init_done; /* set on boot once kmalloc can be called */ +extern int init_bootmem_done; /* set once bootmem is available */ +extern unsigned long long memory_limit; +extern unsigned long klimit; +extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask); + +extern void via_cuda_init(void); +extern void read_rtc_time(void); +extern void pmac_find_display(void); + +struct device_node; +extern void note_scsi_host(struct device_node *, void *); + +/* Used in very early kernel initialization. */ +extern unsigned long reloc_offset(void); +extern unsigned long add_reloc_offset(unsigned long); +extern void reloc_got2(unsigned long); + +#define PTRRELOC(x) ((typeof(x)) add_reloc_offset((unsigned long)(x))) + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_POWERPC_SETUP_H */ + diff --git a/arch/powerpc/include/uapi/asm/setup.h b/arch/powerpc/include/uapi/asm/setup.h index 8b9a306..552df83 100644 --- a/arch/powerpc/include/uapi/asm/setup.h +++ b/arch/powerpc/include/uapi/asm/setup.h @@ -1,32 +1 @@ -#ifndef _ASM_POWERPC_SETUP_H -#define _ASM_POWERPC_SETUP_H - #include - -#ifndef __ASSEMBLY__ -extern void ppc_printk_progress(char *s, unsigned short hex); - -extern unsigned int rtas_data; -extern int mem_init_done; /* set on boot once kmalloc can be called */ -extern int init_bootmem_done; /* set once bootmem is available */ -extern unsigned long long memory_limit; -extern unsigned long klimit; -extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask); - -extern void via_cuda_init(void); -extern void read_rtc_time(void); -extern void pmac_find_display(void); - -struct device_node; -extern void note_scsi_host(struct device_node *, void *); - -/* Used in very early kernel initialization. */ -extern unsigned long reloc_offset(void); -extern unsigned long add_reloc_offset(unsigned long); -extern void reloc_got2(unsigned long); - -#define PTRRELOC(x) ((typeof(x)) add_reloc_offset((unsigned long)(x))) - -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASM_POWERPC_SETUP_H */ -- cgit v0.10.2 From 5e0f9ea784036a3e62a25a9ab5e8f323cb25b321 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 1 Nov 2012 14:55:55 +0000 Subject: powerpc: Remove stale function prototypes from setup.h I noticed a couple of function prototypes for functions that no longer exist. Remove them. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h index 8568c69..d3ca855 100644 --- a/arch/powerpc/include/asm/setup.h +++ b/arch/powerpc/include/asm/setup.h @@ -13,10 +13,6 @@ extern unsigned long long memory_limit; extern unsigned long klimit; extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask); -extern void via_cuda_init(void); -extern void read_rtc_time(void); -extern void pmac_find_display(void); - struct device_node; extern void note_scsi_host(struct device_node *, void *); -- cgit v0.10.2 From 8a56e1ee9229ef1c5c558b53f696af9152024a15 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 1 Nov 2012 18:53:42 +0000 Subject: powerpc: Fix typos in Freescale copyright claims There are many cases that Semiconductor is misspelled. The patch fix these typos. Signed-off-by: Li Yang Acked-by: Timur Tabi Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h index 154c067..607e4ee 100644 --- a/arch/powerpc/include/asm/dbell.h +++ b/arch/powerpc/include/asm/dbell.h @@ -1,5 +1,5 @@ /* - * Copyright 2009 Freescale Semicondutor, Inc. + * Copyright 2009 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/arch/powerpc/include/asm/fsl_gtm.h b/arch/powerpc/include/asm/fsl_gtm.h index 8e8c9b5..3b05808 100644 --- a/arch/powerpc/include/asm/fsl_gtm.h +++ b/arch/powerpc/include/asm/fsl_gtm.h @@ -1,7 +1,7 @@ /* * Freescale General-purpose Timers Module * - * Copyright (c) Freescale Semicondutor, Inc. 2006. + * Copyright 2006 Freescale Semiconductor, Inc. * Shlomi Gridish * Jerry Huang * Copyright (c) MontaVista Software, Inc. 2008. diff --git a/arch/powerpc/include/asm/immap_qe.h b/arch/powerpc/include/asm/immap_qe.h index 61e8490..bedbff8 100644 --- a/arch/powerpc/include/asm/immap_qe.h +++ b/arch/powerpc/include/asm/immap_qe.h @@ -3,7 +3,7 @@ * The Internal Memory Map for devices with QE on them. This * is the superset of all QE devices (8360, etc.). - * Copyright (C) 2006. Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006. Freescale Semiconductor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 66bec46..e434d8b 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -1,5 +1,5 @@ /* - * Copyright 2009 Freescale Semicondutor, Inc. + * Copyright 2009 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/arch/powerpc/include/asm/qe.h b/arch/powerpc/include/asm/qe.h index 229571a..32b9bfa 100644 --- a/arch/powerpc/include/asm/qe.h +++ b/arch/powerpc/include/asm/qe.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang diff --git a/arch/powerpc/include/asm/qe_ic.h b/arch/powerpc/include/asm/qe_ic.h index f706164..25784cc 100644 --- a/arch/powerpc/include/asm/qe_ic.h +++ b/arch/powerpc/include/asm/qe_ic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang diff --git a/arch/powerpc/include/asm/ucc.h b/arch/powerpc/include/asm/ucc.h index 46b09ba..6927ac2 100644 --- a/arch/powerpc/include/asm/ucc.h +++ b/arch/powerpc/include/asm/ucc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang diff --git a/arch/powerpc/include/asm/ucc_fast.h b/arch/powerpc/include/asm/ucc_fast.h index 4644c84..72ea9ba 100644 --- a/arch/powerpc/include/asm/ucc_fast.h +++ b/arch/powerpc/include/asm/ucc_fast.h @@ -1,7 +1,7 @@ /* * Internal header file for UCC FAST unit routines. * - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang diff --git a/arch/powerpc/include/asm/ucc_slow.h b/arch/powerpc/include/asm/ucc_slow.h index cf131ff..c44131e 100644 --- a/arch/powerpc/include/asm/ucc_slow.h +++ b/arch/powerpc/include/asm/ucc_slow.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 448d862..1843bc9 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -4,7 +4,7 @@ * Written by: Grant Likely * * Copyright (C) Secret Lab Technologies Ltd. 2006. All rights reserved. - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. * * Description: * This program is free software; you can redistribute it and/or modify it diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index d440435..8d76220 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. * * Description: * MPC832xE MDS board specific routines. diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 1b1f6c8..1a26d2f 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. * * Author: Li Yang * Yin Olivia diff --git a/arch/powerpc/platforms/83xx/mpc836x_rdk.c b/arch/powerpc/platforms/83xx/mpc836x_rdk.c index f8769d7..b63b42d 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_rdk.c +++ b/arch/powerpc/platforms/83xx/mpc836x_rdk.c @@ -1,7 +1,7 @@ /* * MPC8360E-RDK board file. * - * Copyright (c) 2006 Freescale Semicondutor, Inc. + * Copyright (c) 2006 Freescale Semiconductor, Inc. * Copyright (c) 2007-2008 MontaVista Software, Inc. * * Author: Anton Vorontsov diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index eca1f09..9813c81 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -1,7 +1,7 @@ /* * arch/powerpc/platforms/83xx/mpc837x_rdb.c * - * Copyright (C) 2007 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. * * MPC837x RDB board specific routines * diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 8498f73..bd12588 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010, 2012 Freescale Semicondutor, Inc. + * Copyright (C) 2006-2010, 2012 Freescale Semiconductor, Inc. * All rights reserved. * * Author: Andy Fleming diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c index 02cf1e7..0eb871c 100644 --- a/arch/powerpc/sysdev/fsl_gtm.c +++ b/arch/powerpc/sysdev/fsl_gtm.c @@ -1,7 +1,7 @@ /* * Freescale General-purpose Timers Module * - * Copyright (c) Freescale Semicondutor, Inc. 2006. + * Copyright (c) Freescale Semiconductor, Inc. 2006. * Shlomi Gridish * Jerry Huang * Copyright (c) MontaVista Software, Inc. 2008. diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index b043675..238a07b 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006-2010 Freescale Semiconductor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 2fba6ef..b2b87c3 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -1,7 +1,7 @@ /* * arch/powerpc/sysdev/qe_lib/qe_ic.c * - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. * * Author: Li Yang * Based on code from Shlomi Gridish diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h index c327872..efef7ab 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.h +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h @@ -3,7 +3,7 @@ * * QUICC ENGINE Interrupt Controller Header * - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. * * Author: Li Yang * Based on code from Shlomi Gridish diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c index fd1a6c3..a88807b 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_io.c +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -3,7 +3,7 @@ * * QE Parallel I/O ports configuration routines * - * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. * * Author: Li Yang * Based on code from Shlomi Gridish diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c index 0467750..134b07d 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc.c +++ b/arch/powerpc/sysdev/qe_lib/ucc.c @@ -3,7 +3,7 @@ * * QE UCC API Set - UCC specific routines implementations. * - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c index fba0244..cceb2e3 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c index 524c0ea..1c062f4 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang diff --git a/arch/powerpc/sysdev/qe_lib/usb.c b/arch/powerpc/sysdev/qe_lib/usb.c index 9162828..27f23bd 100644 --- a/arch/powerpc/sysdev/qe_lib/usb.c +++ b/arch/powerpc/sysdev/qe_lib/usb.c @@ -1,7 +1,7 @@ /* * QE USB routines * - * Copyright (c) Freescale Semicondutor, Inc. 2006. + * Copyright 2006 Freescale Semiconductor, Inc. * Shlomi Gridish * Jerry Huang * Copyright (c) MontaVista Software, Inc. 2008. -- cgit v0.10.2 From d7a1ed163a3bb7aa727d3f9335349055aeea110c Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Wed, 31 Oct 2012 11:21:28 -0700 Subject: powerpc/perf: Use uapi/unistd.h to fix build error Use the 'unistd.h' from arch/powerpc/include/uapi to build the perf tool. Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Benjamin Herrenschmidt diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 2762877..d4960c3 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -26,7 +26,7 @@ void get_term_dimensions(struct winsize *ws); #endif #ifdef __powerpc__ -#include "../../arch/powerpc/include/asm/unistd.h" +#include "../../arch/powerpc/include/uapi/asm/unistd.h" #define rmb() asm volatile ("sync" ::: "memory") #define cpu_relax() asm volatile ("" ::: "memory"); #define CPUINFO_PROC "cpu" -- cgit v0.10.2 From c5a0809a24c19fcefea5f3aeb07bde9a2dee5d80 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 4 Nov 2012 02:03:43 +0000 Subject: powerpc/iommu: Use bitmap library - Caluculate the bitmap size with BITS_TO_LONGS() - Use bitmap_empty() to verify that all bits are cleared This also includes a printk to pr_warn() conversion. Signed-off-by: Akinobu Mita Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 8226c6c..c862fd7 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -656,7 +656,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) struct iommu_pool *p; /* number of bytes needed for the bitmap */ - sz = (tbl->it_size + 7) >> 3; + sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long); page = alloc_pages_node(nid, GFP_ATOMIC, get_order(sz)); if (!page) @@ -708,7 +708,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) void iommu_free_table(struct iommu_table *tbl, const char *node_name) { - unsigned long bitmap_sz, i; + unsigned long bitmap_sz; unsigned int order; if (!tbl || !tbl->it_map) { @@ -718,17 +718,11 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name) } /* verify that table contains no entries */ - /* it_size is in entries, and we're examining 64 at a time */ - for (i = 0; i < (tbl->it_size/64); i++) { - if (tbl->it_map[i] != 0) { - printk(KERN_WARNING "%s: Unexpected TCEs for %s\n", - __func__, node_name); - break; - } - } + if (!bitmap_empty(tbl->it_map, tbl->it_size)) + pr_warn("%s: Unexpected TCEs for %s\n", __func__, node_name); /* calculate bitmap size in bytes */ - bitmap_sz = (tbl->it_size + 7) / 8; + bitmap_sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long); /* free bitmap */ order = get_order(bitmap_sz); -- cgit v0.10.2 From 2237f4f40af9ab57d5427b35d1514d3e65d31d1a Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 4 Nov 2012 02:03:44 +0000 Subject: powerpc: Remove BITOP_MASK and BITOP_WORD from asm/bitops.h Replace BITOP_MASK and BITOP_WORD with BIT_MASK and BIT_WORD defined in linux/bitops.h and remove BITOP_* which are not used anymore. Signed-off-by: Akinobu Mita Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h index dc2cf9c..920596f 100644 --- a/arch/powerpc/include/asm/bitops.h +++ b/arch/powerpc/include/asm/bitops.h @@ -52,8 +52,6 @@ #define smp_mb__before_clear_bit() smp_mb() #define smp_mb__after_clear_bit() smp_mb() -#define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) #define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7) /* Macro for generating the ***_bits() functions */ @@ -83,22 +81,22 @@ DEFINE_BITOP(change_bits, xor, "", "") static __inline__ void set_bit(int nr, volatile unsigned long *addr) { - set_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)); + set_bits(BIT_MASK(nr), addr + BIT_WORD(nr)); } static __inline__ void clear_bit(int nr, volatile unsigned long *addr) { - clear_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)); + clear_bits(BIT_MASK(nr), addr + BIT_WORD(nr)); } static __inline__ void clear_bit_unlock(int nr, volatile unsigned long *addr) { - clear_bits_unlock(BITOP_MASK(nr), addr + BITOP_WORD(nr)); + clear_bits_unlock(BIT_MASK(nr), addr + BIT_WORD(nr)); } static __inline__ void change_bit(int nr, volatile unsigned long *addr) { - change_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)); + change_bits(BIT_MASK(nr), addr + BIT_WORD(nr)); } /* Like DEFINE_BITOP(), with changes to the arguments to 'op' and the output @@ -136,26 +134,26 @@ DEFINE_TESTOP(test_and_change_bits, xor, PPC_ATOMIC_ENTRY_BARRIER, static __inline__ int test_and_set_bit(unsigned long nr, volatile unsigned long *addr) { - return test_and_set_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0; + return test_and_set_bits(BIT_MASK(nr), addr + BIT_WORD(nr)) != 0; } static __inline__ int test_and_set_bit_lock(unsigned long nr, volatile unsigned long *addr) { - return test_and_set_bits_lock(BITOP_MASK(nr), - addr + BITOP_WORD(nr)) != 0; + return test_and_set_bits_lock(BIT_MASK(nr), + addr + BIT_WORD(nr)) != 0; } static __inline__ int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr) { - return test_and_clear_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0; + return test_and_clear_bits(BIT_MASK(nr), addr + BIT_WORD(nr)) != 0; } static __inline__ int test_and_change_bit(unsigned long nr, volatile unsigned long *addr) { - return test_and_change_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0; + return test_and_change_bits(BIT_MASK(nr), addr + BIT_WORD(nr)) != 0; } #include -- cgit v0.10.2 From 79597be99ac96b1409eb7ae41c336696d7c4f4d9 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 4 Nov 2012 02:03:45 +0000 Subject: powerpc: Use asm-generic/bitops/le.h The only difference between powerpc and asm-generic le-bitops is test_bit_le(). Usually all bitops require a long aligned bitmap. But powerpc test_bit_le() can take an unaligned address. There is no special callsite of test_bit_le() that needs unaligned access in powerpc as far as I can see. So convert to use asm-generic/bitops/le.h for powerpc. Signed-off-by: Akinobu Mita Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h index 920596f..ef918a2 100644 --- a/arch/powerpc/include/asm/bitops.h +++ b/arch/powerpc/include/asm/bitops.h @@ -278,61 +278,8 @@ unsigned long __arch_hweight64(__u64 w); #include /* Little-endian versions */ +#include -static __inline__ int test_bit_le(unsigned long nr, - __const__ void *addr) -{ - __const__ unsigned char *tmp = (__const__ unsigned char *) addr; - return (tmp[nr >> 3] >> (nr & 7)) & 1; -} - -static inline void set_bit_le(int nr, void *addr) -{ - set_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline void clear_bit_le(int nr, void *addr) -{ - clear_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline void __set_bit_le(int nr, void *addr) -{ - __set_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline void __clear_bit_le(int nr, void *addr) -{ - __clear_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline int test_and_set_bit_le(int nr, void *addr) -{ - return test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline int test_and_clear_bit_le(int nr, void *addr) -{ - return test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline int __test_and_set_bit_le(int nr, void *addr) -{ - return __test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline int __test_and_clear_bit_le(int nr, void *addr) -{ - return __test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -#define find_first_zero_bit_le(addr, size) \ - find_next_zero_bit_le((addr), (size), 0) -unsigned long find_next_zero_bit_le(const void *addr, - unsigned long size, unsigned long offset); - -unsigned long find_next_bit_le(const void *addr, - unsigned long size, unsigned long offset); /* Bitmap functions for the ext2 filesystem */ #include -- cgit v0.10.2 From a53fd61ac2f411745471c1c877d5e072fbbf0e5c Mon Sep 17 00:00:00 2001 From: Aravinda Prasad Date: Sun, 4 Nov 2012 22:15:28 +0000 Subject: powerpc/ptrace: Enable hardware breakpoint upon re-registering On powerpc, ptrace will disable hardware breakpoint request once the breakpoint is hit. It is the responsibility of the caller to set it again. However, when the caller sets the hardware breakpoint again using ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, addr), the hardware breakpoint is not enabled. While gdb's approach is to unregister and re-register the hardware breakpoint every time the breakpoint is hit - which is working fine, this could affect other programs trying to re-register hardware breakpoint without unregistering. This patch enables hardware breakpoint if the caller is re-registering. Signed-off-by: Aravinda Prasad Acked-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 817b411..c497000 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -952,6 +952,10 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, arch_bp_generic_fields(data & (DABR_DATA_WRITE | DABR_DATA_READ), &attr.bp_type); + + /* Enable breakpoint */ + attr.disabled = false; + ret = modify_user_hw_breakpoint(bp, &attr); if (ret) { ptrace_put_breakpoints(task); -- cgit v0.10.2 From 03737439d83f4214b98a391f5ef9709b8d15af02 Mon Sep 17 00:00:00 2001 From: JoonSoo Kim Date: Mon, 12 Nov 2012 06:40:33 +0000 Subject: powerpc: Change free_bootmem() to kfree() commit ea96025a('Don't use alloc_bootmem() in init_IRQ() path') changed alloc_bootmem() to kzalloc(), but missed to change free_bootmem() to kfree(). So correct it. Signed-off-by: Joonsoo Kim Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 328d221..74861a7 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -149,7 +148,7 @@ int __init pq2ads_pci_init_irq(void) priv->regs = of_iomap(np, 0); if (!priv->regs) { printk(KERN_ERR "Cannot map PCI PIC registers.\n"); - goto out_free_bootmem; + goto out_free_kmalloc; } /* mask all PCI interrupts */ @@ -171,9 +170,8 @@ int __init pq2ads_pci_init_irq(void) out_unmap_regs: iounmap(priv->regs); -out_free_bootmem: - free_bootmem((unsigned long)priv, - sizeof(struct pq2ads_pci_pic)); +out_free_kmalloc: + kfree(priv); of_node_put(np); out_unmap_irq: irq_dispose_mapping(irq); -- cgit v0.10.2 From df77c79920292673b2ce9a338c0da80fe2538b42 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 8 Nov 2012 20:23:11 +0000 Subject: powerpc/pseries: Update ibm,architecture.vec for PAPR 2.7/POWER8 Update ibm,architecture.vec for POWER8 and allows us to support more than one parition per core. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index cb6c123..779f340 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -671,6 +671,7 @@ static void __init early_cmdline_parse(void) #define OV1_PPC_2_04 0x08 /* set if we support PowerPC 2.04 */ #define OV1_PPC_2_05 0x04 /* set if we support PowerPC 2.05 */ #define OV1_PPC_2_06 0x02 /* set if we support PowerPC 2.06 */ +#define OV1_PPC_2_07 0x01 /* set if we support PowerPC 2.07 */ /* Option vector 2: Open Firmware options supported */ #define OV2_REAL_MODE 0x20 /* set if we want OF in real mode */ @@ -707,6 +708,7 @@ static void __init early_cmdline_parse(void) #define OV5_PFO_HW_RNG 0x80 /* PFO Random Number Generator */ #define OV5_PFO_HW_842 0x40 /* PFO Compression Accelerator */ #define OV5_PFO_HW_ENCR 0x20 /* PFO Encryption Accelerator */ +#define OV5_SUB_PROCESSORS 0x01 /* 1,2,or 4 Sub-Processors supported */ /* Option Vector 6: IBM PAPR hints */ #define OV6_LINUX 0x02 /* Linux is our OS */ @@ -719,6 +721,8 @@ static unsigned char ibm_architecture_vec[] = { W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */ W(0xffff0000), W(0x003e0000), /* POWER6 */ W(0xffff0000), W(0x003f0000), /* POWER7 */ + W(0xffff0000), W(0x004b0000), /* POWER8 */ + W(0xffffffff), W(0x0f000004), /* all 2.07-compliant */ W(0xffffffff), W(0x0f000003), /* all 2.06-compliant */ W(0xffffffff), W(0x0f000002), /* all 2.05-compliant */ W(0xfffffffe), W(0x0f000001), /* all 2.04-compliant and earlier */ @@ -728,7 +732,7 @@ static unsigned char ibm_architecture_vec[] = { 3 - 2, /* length */ 0, /* don't ignore, don't halt */ OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 | - OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06, + OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06 | OV1_PPC_2_07, /* option vector 2: Open Firmware options supported */ 34 - 2, /* length */ @@ -755,7 +759,7 @@ static unsigned char ibm_architecture_vec[] = { OV4_MIN_ENT_CAP, /* minimum VP entitled capacity */ /* option vector 5: PAPR/OF options */ - 18 - 2, /* length */ + 19 - 2, /* length */ 0, /* don't ignore, don't halt */ OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_DONATE_DEDICATE_CPU | OV5_MSI, @@ -769,13 +773,14 @@ static unsigned char ibm_architecture_vec[] = { * must match by the macro below. Update the definition if * the structure layout changes. */ -#define IBM_ARCH_VEC_NRCORES_OFFSET 101 +#define IBM_ARCH_VEC_NRCORES_OFFSET 117 W(NR_CPUS), /* number of cores supported */ 0, 0, 0, 0, OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR | OV5_PFO_HW_842, + OV5_SUB_PROCESSORS, /* option vector 6: IBM PAPR hints */ 4 - 2, /* length */ 0, -- cgit v0.10.2 From c674e703cb1028e468527163074810b4a17bf379 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 8 Nov 2012 20:26:42 +0000 Subject: powerpc: Add POWER8 architected mode to cputable A PVR of 0x0F000004 means we are arch v2.07 complicate ie, POWER8. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 216ff84..75a3d71 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -435,6 +435,21 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_restore = __restore_cpu_power7, .platform = "power7", }, + { /* 2.07-compliant processor, i.e. Power8 "architected" mode */ + .pvr_mask = 0xffffffff, + .pvr_value = 0x0f000004, + .cpu_name = "POWER8 (architected)", + .cpu_features = CPU_FTRS_POWER8, + .cpu_user_features = COMMON_USER_POWER8, + .mmu_features = MMU_FTRS_POWER8, + .icache_bsize = 128, + .dcache_bsize = 128, + .oprofile_type = PPC_OPROFILE_POWER4, + .oprofile_cpu_type = "ppc64/ibm-compat-v1", + .cpu_setup = __setup_cpu_power8, + .cpu_restore = __restore_cpu_power8, + .platform = "power8", + }, { /* Power7 */ .pvr_mask = 0xffff0000, .pvr_value = 0x003f0000, -- cgit v0.10.2 From 11ee7e99f35ecb15f59b21da6a82d96d2cd3fcc8 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 11 Nov 2012 19:01:05 +0000 Subject: powerpc: Fix CONFIG_RELOCATABLE=y CONFIG_CRASH_DUMP=n build If we build a kernel with CONFIG_RELOCATABLE=y CONFIG_CRASH_DUMP=n, the kernel fails when we run at a non zero offset. It turns out we were incorrectly wrapping some of the relocatable kernel code with CONFIG_CRASH_DUMP. Signed-off-by: Anton Blanchard Cc: Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 694e3fa..11a4df9 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -422,7 +422,7 @@ _STATIC(__after_prom_start) tovirt(r6,r6) /* on booke, we already run at PAGE_OFFSET */ #endif -#ifdef CONFIG_CRASH_DUMP +#ifdef CONFIG_RELOCATABLE /* * Check if the kernel has to be running as relocatable kernel based on the * variable __run_at_load, if it is set the kernel is treated as relocatable -- cgit v0.10.2 From 278a6cdc39218c13c7a924d21cda71d829007b60 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 2 Nov 2012 14:11:51 +1100 Subject: powerpc: Whitespace changes in exception64s.S Remove redundancy spaces and make tab usage consistent. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 5663018..29cf7b1 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -613,8 +613,8 @@ machine_check_common: STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) - STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception) - STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) + STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception) + STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception) STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) STD_EXCEPTION_COMMON(0x1502, denorm, .unknown_exception) @@ -714,21 +714,21 @@ data_access_common: ld r3,PACA_EXGEN+EX_DAR(r13) lwz r4,PACA_EXGEN+EX_DSISR(r13) li r5,0x300 - b .do_hash_page /* Try to handle as hpte fault */ + b .do_hash_page /* Try to handle as hpte fault */ .align 7 - .globl h_data_storage_common + .globl h_data_storage_common h_data_storage_common: - mfspr r10,SPRN_HDAR - std r10,PACA_EXGEN+EX_DAR(r13) - mfspr r10,SPRN_HDSISR - stw r10,PACA_EXGEN+EX_DSISR(r13) - EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN) - bl .save_nvgprs + mfspr r10,SPRN_HDAR + std r10,PACA_EXGEN+EX_DAR(r13) + mfspr r10,SPRN_HDSISR + stw r10,PACA_EXGEN+EX_DSISR(r13) + EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN) + bl .save_nvgprs DISABLE_INTS - addi r3,r1,STACK_FRAME_OVERHEAD - bl .unknown_exception - b .ret_from_except + addi r3,r1,STACK_FRAME_OVERHEAD + bl .unknown_exception + b .ret_from_except .align 7 .globl instruction_access_common @@ -741,7 +741,7 @@ instruction_access_common: li r5,0x400 b .do_hash_page /* Try to handle as hpte fault */ - STD_EXCEPTION_COMMON(0xe20, h_instr_storage, .unknown_exception) + STD_EXCEPTION_COMMON(0xe20, h_instr_storage, .unknown_exception) /* * Here is the common SLB miss user that is used when going to virtual @@ -1164,7 +1164,7 @@ fwnmi_data_area: /* pseries and powernv need to keep the whole page from * 0x7000 to 0x8000 free for use by the firmware */ - . = 0x8000 + . = 0x8000 #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ /* Space for CPU0's segment table */ -- cgit v0.10.2 From faab4dd2d281d42cb46b16e36f769be59c0a7338 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 2 Nov 2012 13:53:36 +1100 Subject: powerpc: Remove unessessary 0x3000 location enforcement This removes the large gap between 0x1800 and 0x3000. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 29cf7b1..de02964 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -311,12 +311,14 @@ denorm_exception_hv: #ifdef CONFIG_CBE_RAS STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal) KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1802) +#else + . = 0x1800 #endif /* CONFIG_CBE_RAS */ - . = 0x3000 /*** Out of line interrupts support ***/ + .align 7 /* moved from 0x200 */ machine_check_pSeries: .globl machine_check_fwnmi -- cgit v0.10.2 From 61e2390ede3cea186cc01f5f3d0c9eb570c42c40 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 5 Nov 2012 17:10:35 +1100 Subject: powerpc: Make load_hander handle upto 64k offset If we change load_hander() to use an ori instead of addi, we can load handlers upto 64k away provided we are still 64k aligned. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index a43c147..9258daa 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -55,7 +55,8 @@ * word. */ #define LOAD_HANDLER(reg, label) \ - addi reg,reg,(label)-_stext; /* virt addr of handler ... */ + /* Handlers must be within 64K of kbase, which must be 64k aligned */ \ + ori reg,reg,(label)-_stext; /* virt addr of handler ... */ /* Exception register prefixes */ #define EXC_HV H diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index de02964..0969b7f 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -585,8 +585,8 @@ __end_interrupts: * Code from here down to __end_handlers is invoked from the * exception prologs above. Because the prologs assemble the * addresses of these handlers using the LOAD_HANDLER macro, - * which uses an addi instruction, these handlers must be in - * the first 32k of the kernel image. + * which uses an ori instruction, these handlers must be in + * the first 64k of the kernel image. */ /*** Common interrupt handlers ***/ diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index efb6a41..6da881b 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -601,6 +601,11 @@ void __init setup_arch(char **cmdline_p) kvm_linear_init(); + /* Interrupt code needs to be 64K-aligned */ + if ((unsigned long)_stext & 0xffff) + panic("Kernelbase not 64K-aligned (0x%lx)!\n", + (unsigned long)_stext); + ppc64_boot_msg(0x15, "Setup Done"); } -- cgit v0.10.2 From 742415d6b66bf09e3e73280178ef7ec85c90b7ee Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 2 Nov 2012 17:16:01 +1100 Subject: powerpc: Turn syscall handler into macros This turns the syscall handler into macros as we are going to want to reuse them again later. Signed-off-by: Matt Evans Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 0969b7f..85b3c7e 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -25,6 +25,43 @@ * 0x7000 - 0x7fff : FWNMI data area * 0x8000 - : Early init and support code */ + /* Syscall routine is used twice, in reloc-off and reloc-on paths */ +#define SYSCALL_PSERIES_1 \ +BEGIN_FTR_SECTION \ + cmpdi r0,0x1ebe ; \ + beq- 1f ; \ +END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ + mr r9,r13 ; \ + GET_PACA(r13) ; \ + mfspr r11,SPRN_SRR0 ; \ +0: + +#define SYSCALL_PSERIES_2_RFID \ + mfspr r12,SPRN_SRR1 ; \ + ld r10,PACAKBASE(r13) ; \ + LOAD_HANDLER(r10, system_call_entry) ; \ + mtspr SPRN_SRR0,r10 ; \ + ld r10,PACAKMSR(r13) ; \ + mtspr SPRN_SRR1,r10 ; \ + rfid ; \ + b . ; /* prevent speculative execution */ + +#define SYSCALL_PSERIES_3 \ + /* Fast LE/BE switch system call */ \ +1: mfspr r12,SPRN_SRR1 ; \ + xori r12,r12,MSR_LE ; \ + mtspr SPRN_SRR1,r12 ; \ + rfid ; /* return to userspace */ \ + b . ; \ +2: mfspr r12,SPRN_SRR1 ; \ + andi. r12,r12,MSR_PR ; \ + bne 0b ; \ + mtspr SPRN_SRR0,r3 ; \ + mtspr SPRN_SRR1,r4 ; \ + mtspr SPRN_SDR1,r5 ; \ + rfid ; \ + b . ; /* prevent speculative execution */ + /* * This is the start of the interrupt handlers for pSeries @@ -207,31 +244,11 @@ system_call_pSeries: KVMTEST(0xc00) GET_SCRATCH0(r13) #endif -BEGIN_FTR_SECTION - cmpdi r0,0x1ebe - beq- 1f -END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) - mr r9,r13 - GET_PACA(r13) - mfspr r11,SPRN_SRR0 - mfspr r12,SPRN_SRR1 - ld r10,PACAKBASE(r13) - LOAD_HANDLER(r10, system_call_entry) - mtspr SPRN_SRR0,r10 - ld r10,PACAKMSR(r13) - mtspr SPRN_SRR1,r10 - rfid - b . /* prevent speculative execution */ - + SYSCALL_PSERIES_1 + SYSCALL_PSERIES_2_RFID + SYSCALL_PSERIES_3 KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xc00) -/* Fast LE/BE switch system call */ -1: mfspr r12,SPRN_SRR1 - xori r12,r12,MSR_LE - mtspr SPRN_SRR1,r12 - rfid /* return to userspace */ - b . - STD_EXCEPTION_PSERIES(0xd00, 0xd00, single_step) KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xd00) -- cgit v0.10.2 From 4700dfaf1e988b785bd9791064df92d3353e8b88 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 2 Nov 2012 17:21:28 +1100 Subject: powerpc: Add new macros needed for relocation on exceptions POWER8/v2.07 allows exceptions to be taken with the MMU still on. A new set of exception vectors is added at 0xc000_0000_0000_4xxx. When the HW takes us here, MSR IR/DR will be set already and we no longer need a costly RFID to turn the MMU back on again. The original 0x0 based exception vectors remain for when the HW can't leave the MMU on. Examples of this are when we can't trust the current the MMU mappings, like when we are changing from guest to hypervisor (HV 0 -> 1) or when the MMU was off already. In these cases the HW will take us to the original 0x0 based exception vectors with the MMU off as before. The below macros are copies of the macros used at the 0x0 offset but modified to handle the MMU being on. In these macros we use the link register to jump to the secondary handlers rather than using RFID (RFID was also use to turn on the MMU). Signed-off-by: Matt Evans Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 9258daa..10787d3 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -48,6 +48,35 @@ #define EX_LR 72 #define EX_CFAR 80 +#ifdef CONFIG_RELOCATABLE +#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \ + ld r12,PACAKBASE(r13); /* get high part of &label */ \ + mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ + LOAD_HANDLER(r12,label); \ + mtlr r12; \ + mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ + li r10,MSR_RI; \ + mtmsrd r10,1; /* Set RI (EE=0) */ \ + blr; +#else +/* If not relocatable, we can jump directly -- and save messing with LR */ +#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \ + mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ + mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ + li r10,MSR_RI; \ + mtmsrd r10,1; /* Set RI (EE=0) */ \ + b label; +#endif + +/* + * As EXCEPTION_PROLOG_PSERIES(), except we've already got relocation on + * so no need to rfid. Save lr in case we're CONFIG_RELOCATABLE, in which + * case EXCEPTION_RELON_PROLOG_PSERIES_1 will be using lr. + */ +#define EXCEPTION_RELON_PROLOG_PSERIES(area, label, h, extra, vec) \ + EXCEPTION_PROLOG_1(area, extra, vec); \ + EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) + /* * We're short on space and time in the exception prolog, so we can't * use the normal SET_REG_IMMEDIATE macro. Normally we just need the @@ -62,6 +91,22 @@ #define EXC_HV H #define EXC_STD +#if defined(CONFIG_RELOCATABLE) +/* + * If we support interrupts with relocation on AND we're a relocatable + * kernel, we need to use LR to get to the 2nd level handler. So, save/restore + * it when required. + */ +#define SAVE_LR(reg, area) mflr reg ; std reg,area+EX_LR(r13) +#define GET_LR(reg, area) ld reg,area+EX_LR(r13) +#define RESTORE_LR(reg, area) ld reg,area+EX_LR(r13) ; mtlr reg +#else +/* ...else LR is unused and in register. */ +#define SAVE_LR(reg, area) +#define GET_LR(reg, area) mflr reg +#define RESTORE_LR(reg, area) +#endif + #define __EXCEPTION_PROLOG_1(area, extra, vec) \ GET_PACA(r13); \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ @@ -233,6 +278,26 @@ label##_hv: \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ EXC_HV, KVMTEST, vec) +#define STD_RELON_EXCEPTION_PSERIES(loc, vec, label) \ + . = loc; \ + .globl label##_relon_pSeries; \ +label##_relon_pSeries: \ + HMT_MEDIUM; \ + /* No guest interrupts come through here */ \ + SET_SCRATCH0(r13); /* save r13 */ \ + EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ + EXC_STD, KVMTEST_PR, vec) + +#define STD_RELON_EXCEPTION_HV(loc, vec, label) \ + . = loc; \ + .globl label##_relon_hv; \ +label##_relon_hv: \ + HMT_MEDIUM; \ + /* No guest interrupts come through here */ \ + SET_SCRATCH0(r13); /* save r13 */ \ + EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ + EXC_HV, KVMTEST, vec) + /* This associate vector numbers with bits in paca->irq_happened */ #define SOFTEN_VALUE_0x500 PACA_IRQ_EE #define SOFTEN_VALUE_0x502 PACA_IRQ_EE @@ -258,6 +323,9 @@ label##_hv: \ KVMTEST(vec); \ _SOFTEN_TEST(EXC_STD, vec) +#define SOFTEN_NOTEST_PR(vec) _SOFTEN_TEST(EXC_STD, vec) +#define SOFTEN_NOTEST_HV(vec) _SOFTEN_TEST(EXC_HV, vec) + #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \ HMT_MEDIUM; \ SET_SCRATCH0(r13); /* save r13 */ \ @@ -280,6 +348,28 @@ label##_hv: \ _MASKABLE_EXCEPTION_PSERIES(vec, label, \ EXC_HV, SOFTEN_TEST_HV) +#define __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) \ + HMT_MEDIUM; \ + SET_SCRATCH0(r13); /* save r13 */ \ + __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \ + EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, h); +#define _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) \ + __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) + +#define MASKABLE_RELON_EXCEPTION_PSERIES(loc, vec, label) \ + . = loc; \ + .globl label##_relon_pSeries; \ +label##_relon_pSeries: \ + _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, \ + EXC_STD, SOFTEN_NOTEST_PR) + +#define MASKABLE_RELON_EXCEPTION_HV(loc, vec, label) \ + . = loc; \ + .globl label##_relon_hv; \ +label##_relon_hv: \ + _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, \ + EXC_HV, SOFTEN_NOTEST_HV) + /* * Our exception common code can be passed various "additions" * to specify the behaviour of interrupts, whether to kick the diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 85b3c7e..4dc1a04 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -62,6 +62,31 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ rfid ; \ b . ; /* prevent speculative execution */ +#if defined(CONFIG_RELOCATABLE) + /* + * We can't branch directly; in the direct case we use LR + * and system_call_entry restores LR. (We thus need to move + * LR to r10 in the RFID case too.) + */ +#define SYSCALL_PSERIES_2_DIRECT \ + mflr r10 ; \ + ld r12,PACAKBASE(r13) ; \ + LOAD_HANDLER(r12, system_call_entry_direct) ; \ + mtlr r12 ; \ + mfspr r12,SPRN_SRR1 ; \ + /* Re-use of r13... No spare regs to do this */ \ + li r13,MSR_RI ; \ + mtmsrd r13,1 ; \ + GET_PACA(r13) ; /* get r13 back */ \ + blr ; +#else + /* We can branch directly */ +#define SYSCALL_PSERIES_2_DIRECT \ + mfspr r12,SPRN_SRR1 ; \ + li r10,MSR_RI ; \ + mtmsrd r10,1 ; /* Set RI (EE=0) */ \ + b system_call_entry_direct ; +#endif /* * This is the start of the interrupt handlers for pSeries -- cgit v0.10.2 From c1fb6816fb1b78dd94b673b0fdaa9a7a16e97bd1 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 2 Nov 2012 17:21:43 +1100 Subject: powerpc: Add relocation on exception vector handlers POWER8/v2.07 allows exceptions to be taken with the MMU still on. A new set of exception vectors is added at 0xc000_0000_0000_4xxx. When the HW takes us here, MSR IR/DR will be set already and we no longer need a costly RFID to turn the MMU back on again. The original 0x0 based exception vectors remain for when the HW can't leave the MMU on. Examples of this are when we can't trust the current MMU mappings, like when we are changing from guest to hypervisor (HV 0 -> 1) or when the MMU was off already. In these cases the HW will take us to the original 0x0 based exception vectors with the MMU off as before. This uses the new macros added previously too implement these new execption vectors at 0xc000_0000_0000_4xxx. We exit these exception vectors using mflr/blr (rather than mtspr SSR0/RFID), since we don't need the costly MMU switch anymore. This moves the __end_interrupts marker down past these new 0x4000 vectors since they will need to be copied down to 0x0 when the kernel is not at 0x0. Signed-off-by: Matt Evans Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 10787d3..ad708dd 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -115,6 +115,7 @@ mfspr r10,SPRN_CFAR; \ std r10,area+EX_CFAR(r13); \ END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ + SAVE_LR(r10, area); \ mfcr r9; \ extra(vec); \ std r11,area+EX_R11(r13); \ @@ -215,6 +216,7 @@ do_kvm_##n: \ sth r1,PACA_TRAP_SAVE(r13); \ std r3,area+EX_R3(r13); \ addi r3,r13,area; /* r3 -> where regs are saved*/ \ + RESTORE_LR(r1, area); \ b bad_stack; \ 3: std r9,_CCR(r1); /* save CR in stackframe */ \ std r11,_NIP(r1); /* save SRR0 in stackframe */ \ @@ -240,8 +242,8 @@ do_kvm_##n: \ ld r10,area+EX_CFAR(r13); \ std r10,ORIG_GPR3(r1); \ END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ + GET_LR(r9,area); /* Get LR, later save to stack */ \ ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ - mflr r9; /* save LR in stackframe */ \ std r9,_LINK(r1); \ mfctr r10; /* save CTR in stackframe */ \ std r10,_CTR(r1); \ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 4dc1a04..4665e82 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -19,11 +19,13 @@ /* * We layout physical memory as follows: * 0x0000 - 0x00ff : Secondary processor spin code - * 0x0100 - 0x2fff : pSeries Interrupt prologs - * 0x3000 - 0x5fff : interrupt support common interrupt prologs - * 0x6000 - 0x6fff : Initial (CPU0) segment table + * 0x0100 - 0x17ff : pSeries Interrupt prologs + * 0x1800 - 0x4000 : interrupt support common interrupt prologs + * 0x4000 - 0x5fff : pSeries interrupts with IR=1,DR=1 + * 0x6000 - 0x6fff : more interrupt support including for IR=1,DR=1 * 0x7000 - 0x7fff : FWNMI data area - * 0x8000 - : Early init and support code + * 0x8000 - 0x8fff : Initial (CPU0) segment table + * 0x9000 - : Early init and support code */ /* Syscall routine is used twice, in reloc-off and reloc-on paths */ #define SYSCALL_PSERIES_1 \ @@ -619,10 +621,6 @@ slb_miss_user_pseries: b . /* prevent spec. execution */ #endif /* __DISABLED__ */ - .align 7 - .globl __end_interrupts -__end_interrupts: - /* * Code from here down to __end_handlers is invoked from the * exception prologs above. Because the prologs assemble the @@ -673,7 +671,158 @@ machine_check_common: STD_EXCEPTION_COMMON(0x1800, cbe_thermal, .cbe_thermal_exception) #endif /* CONFIG_CBE_RAS */ + /* + * Relocation-on interrupts: A subset of the interrupts can be delivered + * with IR=1/DR=1, if AIL==2 and MSR.HV won't be changed by delivering + * it. Addresses are the same as the original interrupt addresses, but + * offset by 0xc000000000004000. + * It's impossible to receive interrupts below 0x300 via this mechanism. + * KVM: None of these traps are from the guest ; anything that escalated + * to HV=1 from HV=0 is delivered via real mode handlers. + */ + + /* + * This uses the standard macro, since the original 0x300 vector + * only has extra guff for STAB-based processors -- which never + * come here. + */ + STD_RELON_EXCEPTION_PSERIES(0x4300, 0x300, data_access) + . = 0x4380 + .globl data_access_slb_relon_pSeries +data_access_slb_relon_pSeries: + HMT_MEDIUM + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380) + std r3,PACA_EXSLB+EX_R3(r13) + mfspr r3,SPRN_DAR + mfspr r12,SPRN_SRR1 +#ifndef CONFIG_RELOCATABLE + b .slb_miss_realmode +#else + /* + * We can't just use a direct branch to .slb_miss_realmode + * because the distance from here to there depends on where + * the kernel ends up being put. + */ + mfctr r11 + ld r10,PACAKBASE(r13) + LOAD_HANDLER(r10, .slb_miss_realmode) + mtctr r10 + bctr +#endif + + STD_RELON_EXCEPTION_PSERIES(0x4400, 0x400, instruction_access) + . = 0x4480 + .globl instruction_access_slb_relon_pSeries +instruction_access_slb_relon_pSeries: + HMT_MEDIUM + SET_SCRATCH0(r13) + EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480) + std r3,PACA_EXSLB+EX_R3(r13) + mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ + mfspr r12,SPRN_SRR1 +#ifndef CONFIG_RELOCATABLE + b .slb_miss_realmode +#else + mfctr r11 + ld r10,PACAKBASE(r13) + LOAD_HANDLER(r10, .slb_miss_realmode) + mtctr r10 + bctr +#endif + + . = 0x4500 + .globl hardware_interrupt_relon_pSeries; + .globl hardware_interrupt_relon_hv; +hardware_interrupt_relon_pSeries: +hardware_interrupt_relon_hv: + BEGIN_FTR_SECTION + _MASKABLE_RELON_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV, SOFTEN_TEST_HV) + FTR_SECTION_ELSE + _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD, SOFTEN_TEST_PR) + ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_206) + STD_RELON_EXCEPTION_PSERIES(0x4600, 0x600, alignment) + STD_RELON_EXCEPTION_PSERIES(0x4700, 0x700, program_check) + STD_RELON_EXCEPTION_PSERIES(0x4800, 0x800, fp_unavailable) + MASKABLE_RELON_EXCEPTION_PSERIES(0x4900, 0x900, decrementer) + STD_RELON_EXCEPTION_HV(0x4980, 0x982, hdecrementer) + STD_RELON_EXCEPTION_PSERIES(0x4b00, 0xb00, trap_0b) + + . = 0x4c00 + .globl system_call_relon_pSeries +system_call_relon_pSeries: + HMT_MEDIUM + SYSCALL_PSERIES_1 + SYSCALL_PSERIES_2_DIRECT + SYSCALL_PSERIES_3 + + STD_RELON_EXCEPTION_PSERIES(0x4d00, 0xd00, single_step) + + . = 0x4e00 + b h_data_storage_relon_hv + + . = 0x4e20 + b h_instr_storage_relon_hv + + . = 0x4e40 + b emulation_assist_relon_hv + + . = 0x4e50 + b hmi_exception_relon_hv + + . = 0x4e60 + b hmi_exception_relon_hv + + /* For when we support the doorbell interrupt: + STD_RELON_EXCEPTION_HYPERVISOR(0x4e80, 0xe80, doorbell_hyper) + */ + +performance_monitor_relon_pSeries_1: + . = 0x4f00 + b performance_monitor_relon_pSeries + +altivec_unavailable_relon_pSeries_1: + . = 0x4f20 + b altivec_unavailable_relon_pSeries + +vsx_unavailable_relon_pSeries_1: + . = 0x4f40 + b vsx_unavailable_relon_pSeries + +#ifdef CONFIG_CBE_RAS + STD_RELON_EXCEPTION_HV(0x5200, 0x1202, cbe_system_error) +#endif /* CONFIG_CBE_RAS */ + STD_RELON_EXCEPTION_PSERIES(0x5300, 0x1300, instruction_breakpoint) +#ifdef CONFIG_PPC_DENORMALISATION + . = 0x5500 + b denorm_exception_hv +#endif +#ifdef CONFIG_CBE_RAS + STD_RELON_EXCEPTION_HV(0x5600, 0x1602, cbe_maintenance) +#else +#ifdef CONFIG_HVC_SCOM + STD_RELON_EXCEPTION_HV(0x5600, 0x1600, maintence_interrupt) + KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1600) +#endif /* CONFIG_HVC_SCOM */ +#endif /* CONFIG_CBE_RAS */ + STD_RELON_EXCEPTION_PSERIES(0x5700, 0x1700, altivec_assist) +#ifdef CONFIG_CBE_RAS + STD_RELON_EXCEPTION_HV(0x5800, 0x1802, cbe_thermal) +#endif /* CONFIG_CBE_RAS */ + + /* Other future vectors */ + .align 7 + .globl __end_interrupts +__end_interrupts: + .align 7 +system_call_entry_direct: +#if defined(CONFIG_RELOCATABLE) + /* The first level prologue may have used LR to get here, saving + * orig in r10. To save hacking/ifdeffing common code, restore here. + */ + mtlr r10 +#endif system_call_entry: b system_call_common @@ -1196,6 +1345,21 @@ _GLOBAL(do_stab_bolted) rfid b . /* prevent speculative execution */ + + /* Equivalents to the above handlers for relocation-on interrupt vectors */ + STD_RELON_EXCEPTION_HV(., 0xe00, h_data_storage) + KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe00) + STD_RELON_EXCEPTION_HV(., 0xe20, h_instr_storage) + KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe20) + STD_RELON_EXCEPTION_HV(., 0xe40, emulation_assist) + KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe40) + STD_RELON_EXCEPTION_HV(., 0xe60, hmi_exception) + KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe60) + + STD_RELON_EXCEPTION_PSERIES(., 0xf00, performance_monitor) + STD_RELON_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable) + STD_RELON_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable) + #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) /* * Data area reserved for FWNMI option. diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 11a4df9..116f086 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -432,7 +432,8 @@ _STATIC(__after_prom_start) cmplwi cr0,r7,1 bne 3f - li r5,__end_interrupts - _stext /* just copy interrupts */ + /* just copy interrupts */ + LOAD_REG_IMMEDIATE(r5, __end_interrupts - _stext) b 5f 3: #endif -- cgit v0.10.2 From f7c32c24f5788798f17d4e520a5d238335a859cb Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 5 Nov 2012 14:40:18 +1100 Subject: powerpc: Move initial mfspr LPCR out of __init_LPCR We want to change what's initially set in the LPCR, so start by taking the move from LPCR out of the function and into the caller. Signed-off-by: Matt Evans Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index a92101d..52dd033 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -27,6 +27,7 @@ _GLOBAL(__setup_cpu_power7) beqlr li r0,0 mtspr SPRN_LPID,r0 + mfspr r3,SPRN_LPCR bl __init_LPCR bl __init_TLB mtlr r11 @@ -39,6 +40,7 @@ _GLOBAL(__restore_cpu_power7) beqlr li r0,0 mtspr SPRN_LPID,r0 + mfspr r3,SPRN_LPCR bl __init_LPCR bl __init_TLB mtlr r11 @@ -51,6 +53,7 @@ _GLOBAL(__setup_cpu_power8) beqlr li r0,0 mtspr SPRN_LPID,r0 + mfspr r3,SPRN_LPCR bl __init_LPCR bl __init_TLB mtlr r11 @@ -63,6 +66,7 @@ _GLOBAL(__restore_cpu_power8) beqlr li r0,0 mtspr SPRN_LPID,r0 + mfspr r3,SPRN_LPCR bl __init_LPCR bl __init_TLB mtlr r11 @@ -81,6 +85,7 @@ __init_hvmode_206: __init_LPCR: /* Setup a sane LPCR: + * Called with initial LPCR in R3 * * LPES = 0b01 (HSRR0/1 used for 0x500) * PECE = 0b111 @@ -91,7 +96,6 @@ __init_LPCR: * * Other bits untouched for now */ - mfspr r3,SPRN_LPCR li r5,1 rldimi r3,r5, LPCR_LPES_SH, 64-LPCR_LPES_SH-2 ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2) -- cgit v0.10.2 From b0302722eec7c086a31de6e3d9789304ef21df7b Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 2 Nov 2012 16:41:58 +1100 Subject: powerpc: Setup relocation on exceptions for bare metal systems This turns on MMU on execptions via AIL field in the LPCR. Signed-off-by: Matt Evans Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 7b44a6e..1b853f7 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -249,6 +249,8 @@ #define LPCR_RMLS 0x1C000000 /* impl dependent rmo limit sel */ #define LPCR_RMLS_SH (63-37) #define LPCR_ILE 0x02000000 /* !HV irqs set MSR:LE */ +#define LPCR_AIL_0 0x00000000 /* MMU off exception offset 0x0 */ +#define LPCR_AIL_3 0x01800000 /* MMU on exception offset 0xc00...4xxx */ #define LPCR_PECE 0x00007000 /* powersave exit cause enable */ #define LPCR_PECE0 0x00004000 /* ext. exceptions can cause exit */ #define LPCR_PECE1 0x00002000 /* decrementer can cause exit */ diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 52dd033..57cf140 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -54,6 +54,7 @@ _GLOBAL(__setup_cpu_power8) li r0,0 mtspr SPRN_LPID,r0 mfspr r3,SPRN_LPCR + oris r3, r3, LPCR_AIL_3@h bl __init_LPCR bl __init_TLB mtlr r11 @@ -67,6 +68,7 @@ _GLOBAL(__restore_cpu_power8) li r0,0 mtspr SPRN_LPID,r0 mfspr r3,SPRN_LPCR + oris r3, r3, LPCR_AIL_3@h bl __init_LPCR bl __init_TLB mtlr r11 -- cgit v0.10.2 From d8f48ecc0e81cbc52a8eac907e02916d98dbfb5a Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Tue, 6 Nov 2012 16:15:17 +1100 Subject: powerpc: Add set_mode hcall This new hcall in POWER8 is used to set various resource mode registers. eg. it can set address translation mode on interrupt (note: partition wide scope) Signed-off-by: Ian Munsie Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h index ad0b751..973cc3b 100644 --- a/arch/powerpc/include/asm/firmware.h +++ b/arch/powerpc/include/asm/firmware.h @@ -49,6 +49,7 @@ #define FW_FEATURE_XCMO ASM_CONST(0x0000000008000000) #define FW_FEATURE_OPAL ASM_CONST(0x0000000010000000) #define FW_FEATURE_OPALv2 ASM_CONST(0x0000000020000000) +#define FW_FEATURE_SET_MODE ASM_CONST(0x0000000040000000) #ifndef __ASSEMBLY__ @@ -62,7 +63,8 @@ enum { FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN | FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR | FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR | - FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO, + FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO | + FW_FEATURE_SET_MODE, FW_FEATURE_PSERIES_ALWAYS = 0, FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2, FW_FEATURE_POWERNV_ALWAYS = 0, diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index 7a86706..a3d26d8 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -267,7 +267,8 @@ #define H_RANDOM 0x300 #define H_COP 0x304 #define H_GET_MPP_X 0x314 -#define MAX_HCALL_OPCODE H_GET_MPP_X +#define H_SET_MODE 0x31C +#define MAX_HCALL_OPCODE H_SET_MODE #ifndef __ASSEMBLY__ diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index 0b0eff0..7b56118 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -56,6 +56,7 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = { {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, {FW_FEATURE_SPLPAR, "hcall-splpar"}, {FW_FEATURE_VPHN, "hcall-vphn"}, + {FW_FEATURE_SET_MODE, "hcall-set-mode"}, }; /* Build up the firmware features bitmask using the contents of diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index 13e8cc4..44ad214 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h @@ -273,4 +273,10 @@ static inline long plpar_put_term_char(unsigned long termno, unsigned long len, lbuf[1]); } +/* Set various resource mode parameters */ +static inline long plpar_set_mode(unsigned long mflags, unsigned long resource, + unsigned long value1, unsigned long value2) +{ + return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2); +} #endif /* _PSERIES_PLPAR_WRAPPERS_H */ -- cgit v0.10.2 From 798042da4e039ef551ff6e1b1ead50a763181daa Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Thu, 8 Nov 2012 15:57:04 +1100 Subject: powerpc: Add wrappers to enable/disable relocation on exceptions These wrappers hide the parameters that have to be passed to H_SET_MODE to enable/disable relocation on during exceptions. As noted in the comments, since these have partition wide scope, they may take some time to complete and must be periodically retried until H_SUCCESS is returned. Signed-off-by: Ian Munsie Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index 44ad214..e6cc34a 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h @@ -279,4 +279,29 @@ static inline long plpar_set_mode(unsigned long mflags, unsigned long resource, { return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2); } + +/* + * Enable relocation on exceptions on this partition + * + * Note: this call has a partition wide scope and can take a while to complete. + * If it returns H_LONG_BUSY_* it should be retried periodically until it + * returns H_SUCCESS. + */ +static inline long enable_reloc_on_exceptions(void) +{ + /* mflags = 3: Exceptions at 0xC000000000004000 */ + return plpar_set_mode(3, 3, 0, 0); +} + +/* + * Disable relocation on exceptions on this partition + * + * Note: this call has a partition wide scope and can take a while to complete. + * If it returns H_LONG_BUSY_* it should be retried periodically until it + * returns H_SUCCESS. + */ +static inline long disable_reloc_on_exceptions(void) { + return plpar_set_mode(0, 3, 0, 0); +} + #endif /* _PSERIES_PLPAR_WRAPPERS_H */ -- cgit v0.10.2 From cca55d9ddf6d431114ab9f7cad3e761b74255c9c Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Thu, 8 Nov 2012 16:10:29 +1100 Subject: powerpc: Move get_longbusy_msecs into hvcall.h and remove duplicate function I am going to use this in the next patch, better to have this code in one place rather than three. Signed-off-by: Ian Munsie Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index a3d26d8..0975e5c 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -356,6 +356,26 @@ struct hvcall_mpp_x_data { int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data); +static inline unsigned int get_longbusy_msecs(int longbusy_rc) +{ + switch (longbusy_rc) { + case H_LONG_BUSY_ORDER_1_MSEC: + return 1; + case H_LONG_BUSY_ORDER_10_MSEC: + return 10; + case H_LONG_BUSY_ORDER_100_MSEC: + return 100; + case H_LONG_BUSY_ORDER_1_SEC: + return 1000; + case H_LONG_BUSY_ORDER_10_SEC: + return 10000; + case H_LONG_BUSY_ORDER_100_SEC: + return 100000; + default: + return 1; + } +} + #ifdef CONFIG_PPC_PSERIES extern int CMO_PrPSP; extern int CMO_SecPSP; diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index 2d41d04..89517ff 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c @@ -90,26 +90,6 @@ static DEFINE_SPINLOCK(hcall_lock); -static u32 get_longbusy_msecs(int longbusy_rc) -{ - switch (longbusy_rc) { - case H_LONG_BUSY_ORDER_1_MSEC: - return 1; - case H_LONG_BUSY_ORDER_10_MSEC: - return 10; - case H_LONG_BUSY_ORDER_100_MSEC: - return 100; - case H_LONG_BUSY_ORDER_1_SEC: - return 1000; - case H_LONG_BUSY_ORDER_10_SEC: - return 10000; - case H_LONG_BUSY_ORDER_100_SEC: - return 100000; - default: - return 1; - } -} - static long ehca_plpar_hcall_norets(unsigned long opcode, unsigned long arg1, unsigned long arg2, diff --git a/drivers/net/ethernet/ibm/ehea/ehea_phyp.h b/drivers/net/ethernet/ibm/ehea/ehea_phyp.h index 8364815..99b6c2a 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_phyp.h +++ b/drivers/net/ethernet/ibm/ehea/ehea_phyp.h @@ -39,26 +39,6 @@ * hcp_* - structures, variables and functions releated to Hypervisor Calls */ -static inline u32 get_longbusy_msecs(int long_busy_ret_code) -{ - switch (long_busy_ret_code) { - case H_LONG_BUSY_ORDER_1_MSEC: - return 1; - case H_LONG_BUSY_ORDER_10_MSEC: - return 10; - case H_LONG_BUSY_ORDER_100_MSEC: - return 100; - case H_LONG_BUSY_ORDER_1_SEC: - return 1000; - case H_LONG_BUSY_ORDER_10_SEC: - return 10000; - case H_LONG_BUSY_ORDER_100_SEC: - return 100000; - default: - return 1; - } -} - /* Number of pages which can be registered at once by H_REGISTER_HEA_RPAGES */ #define EHEA_MAX_RPAGE 512 -- cgit v0.10.2 From fc8effa4e46fb7bd8a3c5e293efc56b74a54b7a5 Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Thu, 8 Nov 2012 16:03:14 +1100 Subject: powerpc: Enable relocation on during exceptions at boot We currently do this synchronously at boot from setup_arch. On a large system this could hypothetically take a little while to complete, so currently we will give up if we are asked to wait for more than a second in total. If we actually start hitting that timeout in practice we can always move this code into a kernel thread to take care of it in the background. Signed-off-by: Ian Munsie Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index e1a5b8a..5d97553 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -367,6 +367,36 @@ static void pSeries_idle(void) } } +/* + * Enable relocation on during exceptions. This has partition wide scope and + * may take a while to complete, if it takes longer than one second we will + * just give up rather than wasting any more time on this - if that turns out + * to ever be a problem in practice we can move this into a kernel thread to + * finish off the process later in boot. + */ +static int __init pSeries_enable_reloc_on_exc(void) +{ + long rc; + unsigned int delay, total_delay = 0; + + while (1) { + rc = enable_reloc_on_exceptions(); + if (!H_IS_LONG_BUSY(rc)) + return rc; + + delay = get_longbusy_msecs(rc); + total_delay += delay; + if (total_delay > 1000) { + pr_warn("Warning: Giving up waiting to enable " + "relocation on exceptions (%u msec)!\n", + total_delay); + return rc; + } + + mdelay(delay); + } +} + static void __init pSeries_setup_arch(void) { panic_timeout = 10; @@ -402,6 +432,14 @@ static void __init pSeries_setup_arch(void) ppc_md.enable_pmcs = pseries_lpar_enable_pmcs; else ppc_md.enable_pmcs = power4_enable_pmcs; + + if (firmware_has_feature(FW_FEATURE_SET_MODE)) { + long rc; + if ((rc = pSeries_enable_reloc_on_exc()) != H_SUCCESS) { + pr_warn("Unable to enable relocation on exceptions: " + "%ld\n", rc); + } + } } static int __init pSeries_init_panel(void) -- cgit v0.10.2 From cedddd812a79a4fda3885a15711aee3de78c4a24 Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Thu, 8 Nov 2012 16:40:28 +1100 Subject: powerpc: Disable relocation on exceptions when kexecing Since we don't know if they new kernel we are kexecing into has been built to support relocation on exceptions, we disable them before we kexec. We do NOT disable them if we are execing a kdump kernel, because we want to change as little state as possible and it is likely that we are execing ourselves and will be able to handle them anyway. Signed-off-by: Ian Munsie Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 5d97553..ca55882 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -397,6 +398,35 @@ static int __init pSeries_enable_reloc_on_exc(void) } } +#ifdef CONFIG_KEXEC +static long pSeries_disable_reloc_on_exc(void) +{ + long rc; + + while (1) { + rc = disable_reloc_on_exceptions(); + if (!H_IS_LONG_BUSY(rc)) + return rc; + mdelay(get_longbusy_msecs(rc)); + } +} + +static void pSeries_machine_kexec(struct kimage *image) +{ + long rc; + + if (firmware_has_feature(FW_FEATURE_SET_MODE) && + (image->type != KEXEC_TYPE_CRASH)) { + rc = pSeries_disable_reloc_on_exc(); + if (rc != H_SUCCESS) + pr_warning("Warning: Failed to disable relocation on " + "exceptions: %ld\n", rc); + } + + default_machine_kexec(image); +} +#endif + static void __init pSeries_setup_arch(void) { panic_timeout = 10; @@ -697,4 +727,7 @@ define_machine(pseries) { .progress = rtas_progress, .system_reset_exception = pSeries_system_reset_exception, .machine_check_exception = pSeries_machine_check_exception, +#ifdef CONFIG_KEXEC + .machine_kexec = pSeries_machine_kexec, +#endif }; -- cgit v0.10.2 From a755b76ab4cefe3d3aa046f3abc62b7e087336b3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 6 Nov 2012 17:10:10 -0800 Subject: mm: fix slab.c kernel-doc warnings Fix new kernel-doc warnings in mm/slab.c: Warning(mm/slab.c:2358): No description found for parameter 'cachep' Warning(mm/slab.c:2358): Excess function parameter 'name' description in '__kmem_cache_create' Warning(mm/slab.c:2358): Excess function parameter 'size' description in '__kmem_cache_create' Warning(mm/slab.c:2358): Excess function parameter 'align' description in '__kmem_cache_create' Warning(mm/slab.c:2358): Excess function parameter 'ctor' description in '__kmem_cache_create' Signed-off-by: Randy Dunlap Cc: Christoph Lameter Cc: Pekka Enberg Cc: Matt Mackall Signed-off-by: Pekka Enberg diff --git a/mm/slab.c b/mm/slab.c index 6ebb951..e26bff5 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2314,11 +2314,8 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp) /** * __kmem_cache_create - Create a cache. - * @name: A string which is used in /proc/slabinfo to identify this cache. - * @size: The size of objects to be created in this cache. - * @align: The required alignment for the objects. + * @cachep: cache management descriptor * @flags: SLAB flags - * @ctor: A constructor for the objects. * * Returns a ptr to the cache on success, NULL on failure. * Cannot be called within a int, but can be interrupted. -- cgit v0.10.2 From 621eb19ce1ec216e03ad354cb0c4061736b2a436 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 14 Nov 2012 10:48:05 -0500 Subject: svcrpc: Revert "sunrpc/cache.h: replace simple_strtoul" Commit bbf43dc888833ac0539e437dbaeb28bfd4fbab9f "sunrpc/cache.h: replace simple_strtoul" introduced new range-checking which could cause get_int to fail on unsigned integers too large to be represented as an int. We could parse them as unsigned instead--but it turns out svcgssd is actually passing down "-1" in some cases. Which is perhaps stupid, but there's nothing we can do about it now. So just revert back to the previous "sloppy" behavior that accepts either representation. Cc: stable@vger.kernel.org Reported-by: Sven Geggus Signed-off-by: J. Bruce Fields diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index f792794..5dc9ee4 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -217,6 +217,8 @@ extern int qword_get(char **bpp, char *dest, int bufsize); static inline int get_int(char **bpp, int *anint) { char buf[50]; + char *ep; + int rv; int len = qword_get(bpp, buf, sizeof(buf)); if (len < 0) @@ -224,9 +226,11 @@ static inline int get_int(char **bpp, int *anint) if (len == 0) return -ENOENT; - if (kstrtoint(buf, 0, anint)) + rv = simple_strtol(buf, &ep, 0); + if (*ep) return -EINVAL; + *anint = rv; return 0; } -- cgit v0.10.2 From 7f2210fa6b791c290e36d8b3c8af7aaf22b2aaf0 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:05 +0300 Subject: nfsd: use service net instead of hard-coded net where possible Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7de9ba0..207b9af 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2281,7 +2281,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, nfs4_verifier confirm = setclientid_confirm->sc_confirm; clientid_t * clid = &setclientid_confirm->sc_clientid; __be32 status; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); if (STALE_CLIENTID(clid, nn)) return nfserr_stale_clientid; @@ -3151,7 +3151,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, { struct nfs4_client *clp; __be32 status; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); nfs4_lock_state(); dprintk("process_renew(%08x/%08x): starting\n", @@ -4104,7 +4104,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, bool new_state = false; int lkflg; int err; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", (long long) lock->lk_offset, @@ -4277,7 +4277,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct file_lock *file_lock = NULL; struct nfs4_lockowner *lo; __be32 status; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); if (locks_in_grace(SVC_NET(rqstp))) return nfserr_grace; @@ -4453,7 +4453,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct list_head matches; unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); __be32 status; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", clid->cl_boot, clid->cl_id); -- cgit v0.10.2 From c212cecfa21b3d30cd5cc2389754a46973ad9027 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:10 +0300 Subject: nfsd: make nfs4_client network namespace dependent And use it's net where possible. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 9968470..826cc26 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -663,7 +663,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c .to_retries = 0, }; struct rpc_create_args args = { - .net = &init_net, + .net = clp->net, .address = (struct sockaddr *) &conn->cb_addr, .addrsize = conn->cb_addrlen, .saddress = (struct sockaddr *) &conn->cb_saddr, diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index b03b6aa..9881bca 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -859,8 +859,7 @@ nfsd4_cld_create(struct nfs4_client *clp) { int ret; struct cld_upcall *cup; - /* FIXME: determine net from clp */ - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); struct cld_net *cn = nn->cld_net; /* Don't upcall if it's already stored */ @@ -897,8 +896,7 @@ nfsd4_cld_remove(struct nfs4_client *clp) { int ret; struct cld_upcall *cup; - /* FIXME: determine net from clp */ - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); struct cld_net *cn = nn->cld_net; /* Don't upcall if it's already removed */ @@ -935,8 +933,7 @@ nfsd4_cld_check(struct nfs4_client *clp) { int ret; struct cld_upcall *cup; - /* FIXME: determine net from clp */ - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); struct cld_net *cn = nn->cld_net; /* Don't upcall if one was already stored during this grace pd */ diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 207b9af..001bbc9 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1263,10 +1263,9 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2) return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); } -static void gen_clid(struct nfs4_client *clp) +static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) { static u32 current_clientid = 1; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); clp->cl_clientid.cl_boot = nn->boot_time; clp->cl_clientid.cl_id = current_clientid++; @@ -1305,6 +1304,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, struct nfs4_client *clp; struct sockaddr *sa = svc_addr(rqstp); int ret; + struct net *net = SVC_NET(rqstp); clp = alloc_client(name); if (clp == NULL) @@ -1335,6 +1335,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); gen_confirm(clp); clp->cl_cb_session = NULL; + clp->net = net; return clp; } @@ -1471,7 +1472,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r else goto out_err; - conn->cb_addrlen = rpc_uaddr2sockaddr(&init_net, se->se_callback_addr_val, + conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, se->se_callback_addr_len, (struct sockaddr *)&conn->cb_addr, sizeof(conn->cb_addr)); @@ -1619,6 +1620,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, nfs4_verifier verf = exid->verifier; struct sockaddr *sa = svc_addr(rqstp); bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); rpc_ntop(sa, addr_str, sizeof(addr_str)); dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " @@ -1701,7 +1703,7 @@ out_new: } new->cl_minorversion = 1; - gen_clid(new); + gen_clid(new, nn); add_to_unconfirmed(new); out_copy: exid->clientid.cl_boot = new->cl_clientid.cl_boot; @@ -2229,7 +2231,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfs4_verifier clverifier = setclid->se_verf; struct nfs4_client *conf, *unconf, *new; __be32 status; - + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + /* Cases below refer to rfc 3530 section 14.2.33: */ nfs4_lock_state(); conf = find_confirmed_client_by_name(&clname); @@ -2258,7 +2261,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, /* case 1: probable callback update */ copy_clid(new, conf); else /* case 4 (new client) or cases 2, 3 (client reboot): */ - gen_clid(new); + gen_clid(new, nn); new->cl_minorversion = 0; gen_callback(new, setclid, rqstp); add_to_unconfirmed(new); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 029217a..ca8ee8c 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -283,6 +283,7 @@ struct nfs4_client { unsigned long cl_cb_slot_busy; struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */ /* wait here for slots */ + struct net *net; }; static inline void -- cgit v0.10.2 From 52e19c09a183d82d99f10c284bc8b27933b1d1fc Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:16 +0300 Subject: nfsd: make reclaim_str_hashtbl allocated per net This hash holds nfs4_clients info, which are network namespace aware. So let's make it allocated per network namespace. Note: this hash is used only by legacy tracker. So let's allocate hash in tracker init. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 65c2431..49e5479 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -24,6 +24,11 @@ #include #include +/* Hash tables for nfs4_clientid state */ +#define CLIENT_HASH_BITS 4 +#define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) +#define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1) + struct cld_net; struct nfsd_net { @@ -38,6 +43,13 @@ struct nfsd_net { struct lock_manager nfsd4_manager; bool grace_ended; time_t boot_time; + + /* + * reclaim_str_hashtbl[] holds known client info from previous reset/reboot + * used in reboot/reset lease grace period processing + */ + struct list_head *reclaim_str_hashtbl; + int reclaim_str_hashtbl_size; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 9881bca..376692a 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -176,6 +176,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) struct dentry *dir, *dentry; struct nfs4_client_reclaim *crp; int status; + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); @@ -222,7 +223,7 @@ out_unlock: mutex_unlock(&dir->d_inode->i_mutex); if (status == 0) { if (in_grace) { - crp = nfs4_client_to_reclaim(dname); + crp = nfs4_client_to_reclaim(dname, nn); if (crp) crp->cr_clp = clp; } @@ -237,7 +238,7 @@ out_unlock: nfs4_reset_creds(original_cred); } -typedef int (recdir_func)(struct dentry *, struct dentry *); +typedef int (recdir_func)(struct dentry *, struct dentry *, struct nfsd_net *); struct name_list { char name[HEXDIR_LEN]; @@ -263,7 +264,7 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen, } static int -nfsd4_list_rec_dir(recdir_func *f) +nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) { const struct cred *original_cred; struct dentry *dir = rec_file->f_path.dentry; @@ -292,7 +293,7 @@ nfsd4_list_rec_dir(recdir_func *f) status = PTR_ERR(dentry); break; } - status = f(dir, dentry); + status = f(dir, dentry, nn); dput(dentry); } list_del(&entry->list); @@ -336,6 +337,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) struct nfs4_client_reclaim *crp; char dname[HEXDIR_LEN]; int status; + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) return; @@ -359,9 +361,9 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) vfs_fsync(rec_file, 0); if (in_grace) { /* remove reclaim record */ - crp = nfsd4_find_reclaim_client(dname); + crp = nfsd4_find_reclaim_client(dname, nn); if (crp) - nfs4_remove_reclaim_record(crp); + nfs4_remove_reclaim_record(crp, nn); } } out_drop_write: @@ -373,11 +375,11 @@ out: } static int -purge_old(struct dentry *parent, struct dentry *child) +purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) { int status; - if (nfs4_has_reclaimed_state(child->d_name.name)) + if (nfs4_has_reclaimed_state(child->d_name.name, nn)) return 0; status = vfs_rmdir(parent->d_inode, child); @@ -392,6 +394,7 @@ static void nfsd4_recdir_purge_old(struct net *net, time_t boot_time) { int status; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); in_grace = false; if (!rec_file) @@ -399,19 +402,19 @@ nfsd4_recdir_purge_old(struct net *net, time_t boot_time) status = mnt_want_write_file(rec_file); if (status) goto out; - status = nfsd4_list_rec_dir(purge_old); + status = nfsd4_list_rec_dir(purge_old, nn); if (status == 0) vfs_fsync(rec_file, 0); mnt_drop_write_file(rec_file); out: - nfs4_release_reclaim(); + nfs4_release_reclaim(nn); if (status) printk("nfsd4: failed to purge old clients from recovery" " directory %s\n", rec_file->f_path.dentry->d_name.name); } static int -load_recdir(struct dentry *parent, struct dentry *child) +load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) { if (child->d_name.len != HEXDIR_LEN - 1) { printk("nfsd4: illegal name %s in recovery directory\n", @@ -419,18 +422,19 @@ load_recdir(struct dentry *parent, struct dentry *child) /* Keep trying; maybe the others are OK: */ return 0; } - nfs4_client_to_reclaim(child->d_name.name); + nfs4_client_to_reclaim(child->d_name.name, nn); return 0; } static int -nfsd4_recdir_load(void) { +nfsd4_recdir_load(struct net *net) { int status; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); if (!rec_file) return 0; - status = nfsd4_list_rec_dir(load_recdir); + status = nfsd4_list_rec_dir(load_recdir, nn); if (status) printk("nfsd4: failed loading clients from recovery" " directory %s\n", rec_file->f_path.dentry->d_name.name); @@ -474,11 +478,53 @@ nfsd4_init_recdir(void) return status; } + +static int +nfs4_legacy_state_init(struct net *net) +{ + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + int i; + + nn->reclaim_str_hashtbl = kmalloc(sizeof(struct list_head) * + CLIENT_HASH_SIZE, GFP_KERNEL); + if (!nn->reclaim_str_hashtbl) + return -ENOMEM; + + for (i = 0; i < CLIENT_HASH_SIZE; i++) + INIT_LIST_HEAD(&nn->reclaim_str_hashtbl[i]); + nn->reclaim_str_hashtbl_size = 0; + + return 0; +} + +static void +nfs4_legacy_state_shutdown(struct net *net) +{ + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + kfree(nn->reclaim_str_hashtbl); +} + static int nfsd4_load_reboot_recovery_data(struct net *net) { int status; + nfs4_lock_state(); + status = nfsd4_init_recdir(); + if (!status) + status = nfsd4_recdir_load(net); + nfs4_unlock_state(); + if (status) + printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n"); + return status; +} + +static int +nfsd4_legacy_tracking_init(struct net *net) +{ + int status; + /* XXX: The legacy code won't work in a container */ if (net != &init_net) { WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client " @@ -486,13 +532,17 @@ nfsd4_load_reboot_recovery_data(struct net *net) return -EINVAL; } - nfs4_lock_state(); - status = nfsd4_init_recdir(); - if (!status) - status = nfsd4_recdir_load(); - nfs4_unlock_state(); + status = nfs4_legacy_state_init(net); if (status) - printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n"); + return status; + + status = nfsd4_load_reboot_recovery_data(net); + if (status) + goto err; + return 0; + +err: + nfs4_legacy_state_shutdown(net); return status; } @@ -508,8 +558,11 @@ nfsd4_shutdown_recdir(void) static void nfsd4_legacy_tracking_exit(struct net *net) { - nfs4_release_reclaim(); + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + nfs4_release_reclaim(nn); nfsd4_shutdown_recdir(); + nfs4_legacy_state_shutdown(net); } /* @@ -545,6 +598,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp) int status; char dname[HEXDIR_LEN]; struct nfs4_client_reclaim *crp; + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); /* did we already find that this client is stable? */ if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) @@ -557,7 +611,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp) } /* look for it in the reclaim hashtable otherwise */ - crp = nfsd4_find_reclaim_client(dname); + crp = nfsd4_find_reclaim_client(dname, nn); if (crp) { set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); crp->cr_clp = clp; @@ -568,7 +622,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp) } static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = { - .init = nfsd4_load_reboot_recovery_data, + .init = nfsd4_legacy_tracking_init, .exit = nfsd4_legacy_tracking_exit, .create = nfsd4_create_clid_dir, .remove = nfsd4_remove_clid_dir, diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 001bbc9..ba47855 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -393,11 +393,6 @@ unhash_delegation(struct nfs4_delegation *dp) /* client_lock protects the client lru list and session hash table */ static DEFINE_SPINLOCK(client_lock); -/* Hash tables for nfs4_clientid state */ -#define CLIENT_HASH_BITS 4 -#define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) -#define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1) - static unsigned int clientid_hashval(u32 id) { return id & CLIENT_HASH_MASK; @@ -409,11 +404,8 @@ static unsigned int clientstr_hashval(const char *name) } /* - * reclaim_str_hashtbl[] holds known client info from previous reset/reboot - * used in reboot/reset lease grace period processing - * * conf_id_hashtbl[], and conf_name_tree hold confirmed - * setclientid_confirmed info. + * setclientid_confirmed info. * * unconf_id_hashtbl[] and unconf_name_tree hold unconfirmed * setclientid info. @@ -426,8 +418,6 @@ static unsigned int clientstr_hashval(const char *name) * * All of the above fields are protected by the client_mutex. */ -static struct list_head reclaim_str_hashtbl[CLIENT_HASH_SIZE]; -static int reclaim_str_hashtbl_size = 0; static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; static struct rb_root conf_name_tree; @@ -4509,11 +4499,11 @@ alloc_reclaim(void) } bool -nfs4_has_reclaimed_state(const char *name) +nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) { struct nfs4_client_reclaim *crp; - crp = nfsd4_find_reclaim_client(name); + crp = nfsd4_find_reclaim_client(name, nn); return (crp && crp->cr_clp); } @@ -4521,7 +4511,7 @@ nfs4_has_reclaimed_state(const char *name) * failure => all reset bets are off, nfserr_no_grace... */ struct nfs4_client_reclaim * -nfs4_client_to_reclaim(const char *name) +nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) { unsigned int strhashval; struct nfs4_client_reclaim *crp; @@ -4531,42 +4521,42 @@ nfs4_client_to_reclaim(const char *name) if (crp) { strhashval = clientstr_hashval(name); INIT_LIST_HEAD(&crp->cr_strhash); - list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); + list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); memcpy(crp->cr_recdir, name, HEXDIR_LEN); crp->cr_clp = NULL; - reclaim_str_hashtbl_size++; + nn->reclaim_str_hashtbl_size++; } return crp; } void -nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp) +nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) { list_del(&crp->cr_strhash); kfree(crp); - reclaim_str_hashtbl_size--; + nn->reclaim_str_hashtbl_size--; } void -nfs4_release_reclaim(void) +nfs4_release_reclaim(struct nfsd_net *nn) { struct nfs4_client_reclaim *crp = NULL; int i; for (i = 0; i < CLIENT_HASH_SIZE; i++) { - while (!list_empty(&reclaim_str_hashtbl[i])) { - crp = list_entry(reclaim_str_hashtbl[i].next, + while (!list_empty(&nn->reclaim_str_hashtbl[i])) { + crp = list_entry(nn->reclaim_str_hashtbl[i].next, struct nfs4_client_reclaim, cr_strhash); - nfs4_remove_reclaim_record(crp); + nfs4_remove_reclaim_record(crp, nn); } } - BUG_ON(reclaim_str_hashtbl_size); + BUG_ON(nn->reclaim_str_hashtbl_size); } /* * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ struct nfs4_client_reclaim * -nfsd4_find_reclaim_client(const char *recdir) +nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) { unsigned int strhashval; struct nfs4_client_reclaim *crp = NULL; @@ -4574,7 +4564,7 @@ nfsd4_find_reclaim_client(const char *recdir) dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); strhashval = clientstr_hashval(recdir); - list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { + list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { if (same_name(crp->cr_recdir, recdir)) { return crp; } @@ -4732,7 +4722,6 @@ nfs4_state_init(void) for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&conf_id_hashtbl[i]); INIT_LIST_HEAD(&unconf_id_hashtbl[i]); - INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); } conf_name_tree = RB_ROOT; unconf_name_tree = RB_ROOT; @@ -4749,7 +4738,6 @@ nfs4_state_init(void) INIT_LIST_HEAD(&close_lru); INIT_LIST_HEAD(&client_lru); INIT_LIST_HEAD(&del_recall_lru); - reclaim_str_hashtbl_size = 0; } /* diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index ca8ee8c..26a912c 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -466,9 +466,10 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net, stateid_t *stateid, int flags, struct file **filp); extern void nfs4_lock_state(void); extern void nfs4_unlock_state(void); -void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *); -extern void nfs4_release_reclaim(void); -extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir); +void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); +extern void nfs4_release_reclaim(struct nfsd_net *); +extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, + struct nfsd_net *nn); extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions); extern void nfs4_free_openowner(struct nfs4_openowner *); extern void nfs4_free_lockowner(struct nfs4_lockowner *); @@ -482,8 +483,9 @@ extern int nfsd4_create_callback_queue(void); extern void nfsd4_destroy_callback_queue(void); extern void nfsd4_shutdown_callback(struct nfs4_client *); extern void nfs4_put_delegation(struct nfs4_delegation *dp); -extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name); -extern bool nfs4_has_reclaimed_state(const char *name); +extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name, + struct nfsd_net *nn); +extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn); extern void release_session_client(struct nfsd4_session *); extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); -- cgit v0.10.2 From 8daae4dc0d09d44d38194f72bc91740b46a6ce53 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:21 +0300 Subject: nfsd: make conf_id_hashtbl allocated per net This hash holds nfs4_clients info, which are network namespace aware. So let's make it allocated per network namespace. Note: this hash can be allocated in per-net operations. But it looks better to allocate it on nfsd state start and thus don't waste resources if server is not running. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 49e5479..0cc85e9 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -50,6 +50,7 @@ struct nfsd_net { */ struct list_head *reclaim_str_hashtbl; int reclaim_str_hashtbl_size; + struct list_head *conf_id_hashtbl; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ba47855..6df427773 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -418,7 +418,6 @@ static unsigned int clientstr_hashval(const char *name) * * All of the above fields are protected by the client_mutex. */ -static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; static struct rb_root conf_name_tree; static struct rb_root unconf_name_tree; @@ -1385,9 +1384,10 @@ static void move_to_confirmed(struct nfs4_client *clp) { unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); - list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); + list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); rb_erase(&clp->cl_namenode, &unconf_name_tree); add_clp_to_name_tree(clp, &conf_name_tree); set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); @@ -1395,12 +1395,12 @@ move_to_confirmed(struct nfs4_client *clp) } static struct nfs4_client * -find_confirmed_client(clientid_t *clid, bool sessions) +find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) { struct nfs4_client *clp; unsigned int idhashval = clientid_hashval(clid->cl_id); - list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { + list_for_each_entry(clp, &nn->conf_id_hashtbl[idhashval], cl_idhash) { if (same_clid(&clp->cl_clientid, clid)) { if ((bool)clp->cl_minorversion != sessions) return NULL; @@ -1787,6 +1787,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, struct nfsd4_conn *conn; struct nfsd4_clid_slot *cs_slot = NULL; __be32 status = 0; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) return nfserr_inval; @@ -1802,7 +1803,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, nfs4_lock_state(); unconf = find_unconfirmed_client(&cr_ses->clientid, true); - conf = find_confirmed_client(&cr_ses->clientid, true); + conf = find_confirmed_client(&cr_ses->clientid, true, nn); if (conf) { cs_slot = &conf->cl_cs_slot; @@ -2142,10 +2143,11 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta { struct nfs4_client *conf, *unconf, *clp; __be32 status = 0; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); nfs4_lock_state(); unconf = find_unconfirmed_client(&dc->clientid, true); - conf = find_confirmed_client(&dc->clientid, true); + conf = find_confirmed_client(&dc->clientid, true, nn); if (conf) { clp = conf; @@ -2280,7 +2282,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, return nfserr_stale_clientid; nfs4_lock_state(); - conf = find_confirmed_client(clid, false); + conf = find_confirmed_client(clid, false, nn); unconf = find_unconfirmed_client(clid, false); /* * We try hard to give out unique clientid's, so if we get an @@ -2656,7 +2658,8 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, oo = find_openstateowner_str(strhashval, open, cstate->minorversion); open->op_openowner = oo; if (!oo) { - clp = find_confirmed_client(clientid, cstate->minorversion); + clp = find_confirmed_client(clientid, cstate->minorversion, + nn); if (clp == NULL) return nfserr_expired; goto new_owner; @@ -3152,7 +3155,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfserr_stale_clientid; if (STALE_CLIENTID(clid, nn)) goto out; - clp = find_confirmed_client(clid, cstate->minorversion); + clp = find_confirmed_client(clid, cstate->minorversion, nn); status = nfserr_expired; if (clp == NULL) { /* We assume the client took too long to RENEW. */ @@ -3428,7 +3431,7 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, s return nfserr_bad_stateid; if (STALE_STATEID(stateid, nn)) return nfserr_stale_stateid; - cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions); + cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions, nn); if (!cl) return nfserr_expired; *s = find_stateid_by_type(cl, stateid, typemask); @@ -4579,9 +4582,10 @@ __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions) { struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); /* find clientid in conf_id_hashtbl */ - clp = find_confirmed_client(clid, sessions); + clp = find_confirmed_client(clid, sessions, nn); if (clp == NULL) return nfserr_reclaim_bad; @@ -4720,7 +4724,6 @@ nfs4_state_init(void) int i; for (i = 0; i < CLIENT_HASH_SIZE; i++) { - INIT_LIST_HEAD(&conf_id_hashtbl[i]); INIT_LIST_HEAD(&unconf_id_hashtbl[i]); } conf_name_tree = RB_ROOT; @@ -4761,6 +4764,38 @@ set_max_delegations(void) max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); } +static int nfs4_state_start_net(struct net *net) +{ + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + int i; + + nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) * + CLIENT_HASH_SIZE, GFP_KERNEL); + if (!nn->conf_id_hashtbl) + return -ENOMEM; + + for (i = 0; i < CLIENT_HASH_SIZE; i++) + INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); + + return 0; +} + +static void +__nfs4_state_shutdown_net(struct net *net) +{ + int i; + struct nfs4_client *clp = NULL; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + for (i = 0; i < CLIENT_HASH_SIZE; i++) { + while (!list_empty(&nn->conf_id_hashtbl[i])) { + clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); + destroy_client(clp); + } + } + kfree(nn->conf_id_hashtbl); +} + /* initialization to perform when the nfsd service is started: */ int @@ -4778,6 +4813,9 @@ nfs4_state_start(void) * basis. */ get_net(net); + ret = nfs4_state_start_net(net); + if (ret) + return ret; nfsd4_client_tracking_init(net); nn->boot_time = get_seconds(); locks_start_grace(net, &nn->nfsd4_manager); @@ -4804,26 +4842,21 @@ out_free_laundry: destroy_workqueue(laundry_wq); out_recovery: nfsd4_client_tracking_exit(net); + __nfs4_state_shutdown_net(net); put_net(net); return ret; } /* should be called with the state lock held */ static void -__nfs4_state_shutdown(void) +__nfs4_state_shutdown(struct net *net) { - int i; struct nfs4_client *clp = NULL; struct nfs4_delegation *dp = NULL; struct list_head *pos, *next, reaplist; struct rb_node *node, *tmp; - for (i = 0; i < CLIENT_HASH_SIZE; i++) { - while (!list_empty(&conf_id_hashtbl[i])) { - clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); - destroy_client(clp); - } - } + __nfs4_state_shutdown_net(net); node = rb_first(&unconf_name_tree); while (node != NULL) { @@ -4860,7 +4893,7 @@ nfs4_state_shutdown(void) destroy_workqueue(laundry_wq); locks_end_grace(&nn->nfsd4_manager); nfs4_lock_state(); - __nfs4_state_shutdown(); + __nfs4_state_shutdown(net); nfs4_unlock_state(); nfsd4_destroy_callback_queue(); } -- cgit v0.10.2 From 382a62e76cbf91fb364a4cd8732761e4ecf62153 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:26 +0300 Subject: nfsd: make conf_name_tree per net This tree holds nfs4_clients info, which are network namespace aware. So let's make it per network namespace. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 0cc85e9..afd9116 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -47,10 +47,14 @@ struct nfsd_net { /* * reclaim_str_hashtbl[] holds known client info from previous reset/reboot * used in reboot/reset lease grace period processing + * + * conf_id_hashtbl[], and conf_name_tree hold confirmed + * setclientid_confirmed info. */ struct list_head *reclaim_str_hashtbl; int reclaim_str_hashtbl_size; struct list_head *conf_id_hashtbl; + struct rb_root conf_name_tree; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6df427773..d40e57b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -404,9 +404,6 @@ static unsigned int clientstr_hashval(const char *name) } /* - * conf_id_hashtbl[], and conf_name_tree hold confirmed - * setclientid_confirmed info. - * * unconf_id_hashtbl[] and unconf_name_tree hold unconfirmed * setclientid info. * @@ -419,7 +416,6 @@ static unsigned int clientstr_hashval(const char *name) * All of the above fields are protected by the client_mutex. */ static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; -static struct rb_root conf_name_tree; static struct rb_root unconf_name_tree; static struct list_head client_lru; static struct list_head close_lru; @@ -1114,6 +1110,7 @@ destroy_client(struct nfs4_client *clp) struct nfs4_openowner *oo; struct nfs4_delegation *dp; struct list_head reaplist; + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); INIT_LIST_HEAD(&reaplist); spin_lock(&recall_lock); @@ -1136,7 +1133,7 @@ destroy_client(struct nfs4_client *clp) svc_xprt_put(clp->cl_cb_conn.cb_xprt); list_del(&clp->cl_idhash); if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) - rb_erase(&clp->cl_namenode, &conf_name_tree); + rb_erase(&clp->cl_namenode, &nn->conf_name_tree); else rb_erase(&clp->cl_namenode, &unconf_name_tree); spin_lock(&client_lock); @@ -1389,7 +1386,7 @@ move_to_confirmed(struct nfs4_client *clp) dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); rb_erase(&clp->cl_namenode, &unconf_name_tree); - add_clp_to_name_tree(clp, &conf_name_tree); + add_clp_to_name_tree(clp, &nn->conf_name_tree); set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); renew_client(clp); } @@ -1433,9 +1430,9 @@ static bool clp_used_exchangeid(struct nfs4_client *clp) } static struct nfs4_client * -find_confirmed_client_by_name(struct xdr_netobj *name) +find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) { - return find_clp_in_name_tree(name, &conf_name_tree); + return find_clp_in_name_tree(name, &nn->conf_name_tree); } static struct nfs4_client * @@ -1635,7 +1632,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, /* Cases below refer to rfc 5661 section 18.35.4: */ nfs4_lock_state(); - conf = find_confirmed_client_by_name(&exid->clname); + conf = find_confirmed_client_by_name(&exid->clname, nn); if (conf) { bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); bool verfs_match = same_verf(&verf, &conf->cl_verifier); @@ -1829,7 +1826,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, status = nfserr_seq_misordered; goto out_free_conn; } - old = find_confirmed_client_by_name(&unconf->cl_name); + old = find_confirmed_client_by_name(&unconf->cl_name, nn); if (old) expire_client(old); move_to_confirmed(unconf); @@ -2227,7 +2224,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, /* Cases below refer to rfc 3530 section 14.2.33: */ nfs4_lock_state(); - conf = find_confirmed_client_by_name(&clname); + conf = find_confirmed_client_by_name(&clname, nn); if (conf) { /* case 0: */ status = nfserr_clid_inuse; @@ -2309,7 +2306,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, nfsd4_probe_callback(conf); expire_client(unconf); } else { /* case 3: normal case; new or rebooted client */ - conf = find_confirmed_client_by_name(&unconf->cl_name); + conf = find_confirmed_client_by_name(&unconf->cl_name, nn); if (conf) expire_client(conf); move_to_confirmed(unconf); @@ -4726,7 +4723,6 @@ nfs4_state_init(void) for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&unconf_id_hashtbl[i]); } - conf_name_tree = RB_ROOT; unconf_name_tree = RB_ROOT; for (i = 0; i < SESSION_HASH_SIZE; i++) INIT_LIST_HEAD(&sessionid_hashtbl[i]); @@ -4772,12 +4768,17 @@ static int nfs4_state_start_net(struct net *net) nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) * CLIENT_HASH_SIZE, GFP_KERNEL); if (!nn->conf_id_hashtbl) - return -ENOMEM; + goto err; - for (i = 0; i < CLIENT_HASH_SIZE; i++) + for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); + } + nn->conf_name_tree = RB_ROOT; return 0; + +err: + return -ENOMEM; } static void -- cgit v0.10.2 From 0a7ec37727dcc3293cd4c9958b25c43f3a797d47 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:31 +0300 Subject: nfsd: make unconf_id_hashtbl allocated per net This hash holds nfs4_clients info, which are network namespace aware. So let's make it allocated per network namespace. Note: this hash can be allocated in per-net operations. But it looks better to allocate it on nfsd state start and thus don't waste resources if server is not running. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index afd9116..1ff781f 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -55,6 +55,7 @@ struct nfsd_net { int reclaim_str_hashtbl_size; struct list_head *conf_id_hashtbl; struct rb_root conf_name_tree; + struct list_head *unconf_id_hashtbl; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d40e57b..f33bbfb 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -415,7 +415,6 @@ static unsigned int clientstr_hashval(const char *name) * * All of the above fields are protected by the client_mutex. */ -static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; static struct rb_root unconf_name_tree; static struct list_head client_lru; static struct list_head close_lru; @@ -1369,11 +1368,12 @@ static void add_to_unconfirmed(struct nfs4_client *clp) { unsigned int idhashval; + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); add_clp_to_name_tree(clp, &unconf_name_tree); idhashval = clientid_hashval(clp->cl_clientid.cl_id); - list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); + list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); renew_client(clp); } @@ -1409,12 +1409,12 @@ find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) } static struct nfs4_client * -find_unconfirmed_client(clientid_t *clid, bool sessions) +find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) { struct nfs4_client *clp; unsigned int idhashval = clientid_hashval(clid->cl_id); - list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { + list_for_each_entry(clp, &nn->unconf_id_hashtbl[idhashval], cl_idhash) { if (same_clid(&clp->cl_clientid, clid)) { if ((bool)clp->cl_minorversion != sessions) return NULL; @@ -1799,7 +1799,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, goto out_free_session; nfs4_lock_state(); - unconf = find_unconfirmed_client(&cr_ses->clientid, true); + unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); conf = find_confirmed_client(&cr_ses->clientid, true, nn); if (conf) { @@ -2143,7 +2143,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); nfs4_lock_state(); - unconf = find_unconfirmed_client(&dc->clientid, true); + unconf = find_unconfirmed_client(&dc->clientid, true, nn); conf = find_confirmed_client(&dc->clientid, true, nn); if (conf) { @@ -2280,7 +2280,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, nfs4_lock_state(); conf = find_confirmed_client(clid, false, nn); - unconf = find_unconfirmed_client(clid, false); + unconf = find_unconfirmed_client(clid, false, nn); /* * We try hard to give out unique clientid's, so if we get an * attempt to confirm the same clientid with a different cred, @@ -4720,9 +4720,6 @@ nfs4_state_init(void) { int i; - for (i = 0; i < CLIENT_HASH_SIZE; i++) { - INIT_LIST_HEAD(&unconf_id_hashtbl[i]); - } unconf_name_tree = RB_ROOT; for (i = 0; i < SESSION_HASH_SIZE; i++) INIT_LIST_HEAD(&sessionid_hashtbl[i]); @@ -4769,14 +4766,21 @@ static int nfs4_state_start_net(struct net *net) CLIENT_HASH_SIZE, GFP_KERNEL); if (!nn->conf_id_hashtbl) goto err; + nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) * + CLIENT_HASH_SIZE, GFP_KERNEL); + if (!nn->unconf_id_hashtbl) + goto err_unconf_id; for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); + INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); } nn->conf_name_tree = RB_ROOT; return 0; +err_unconf_id: + kfree(nn->conf_id_hashtbl); err: return -ENOMEM; } @@ -4794,6 +4798,7 @@ __nfs4_state_shutdown_net(struct net *net) destroy_client(clp); } } + kfree(nn->unconf_id_hashtbl); kfree(nn->conf_id_hashtbl); } -- cgit v0.10.2 From a99454aa4ff1241a19dcb486fa302d3e8cc09e5b Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:36 +0300 Subject: nfsd: make unconf_name_tree per net This hash holds nfs4_clients info, which are network namespace aware. So let's make it allocated per network namespace. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 1ff781f..1e76030 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -50,12 +50,16 @@ struct nfsd_net { * * conf_id_hashtbl[], and conf_name_tree hold confirmed * setclientid_confirmed info. + * + * unconf_str_hastbl[] and unconf_name_tree hold unconfirmed + * setclientid info. */ struct list_head *reclaim_str_hashtbl; int reclaim_str_hashtbl_size; struct list_head *conf_id_hashtbl; struct rb_root conf_name_tree; struct list_head *unconf_id_hashtbl; + struct rb_root unconf_name_tree; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f33bbfb..b353291 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -404,9 +404,6 @@ static unsigned int clientstr_hashval(const char *name) } /* - * unconf_id_hashtbl[] and unconf_name_tree hold unconfirmed - * setclientid info. - * * client_lru holds client queue ordered by nfs4_client.cl_time * for lease renewal. * @@ -415,7 +412,6 @@ static unsigned int clientstr_hashval(const char *name) * * All of the above fields are protected by the client_mutex. */ -static struct rb_root unconf_name_tree; static struct list_head client_lru; static struct list_head close_lru; @@ -1134,7 +1130,7 @@ destroy_client(struct nfs4_client *clp) if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) rb_erase(&clp->cl_namenode, &nn->conf_name_tree); else - rb_erase(&clp->cl_namenode, &unconf_name_tree); + rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); spin_lock(&client_lock); unhash_client_locked(clp); if (atomic_read(&clp->cl_refcount) == 0) @@ -1371,7 +1367,7 @@ add_to_unconfirmed(struct nfs4_client *clp) struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); - add_clp_to_name_tree(clp, &unconf_name_tree); + add_clp_to_name_tree(clp, &nn->unconf_name_tree); idhashval = clientid_hashval(clp->cl_clientid.cl_id); list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); renew_client(clp); @@ -1385,7 +1381,7 @@ move_to_confirmed(struct nfs4_client *clp) dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); - rb_erase(&clp->cl_namenode, &unconf_name_tree); + rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); add_clp_to_name_tree(clp, &nn->conf_name_tree); set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); renew_client(clp); @@ -1436,9 +1432,9 @@ find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) } static struct nfs4_client * -find_unconfirmed_client_by_name(struct xdr_netobj *name) +find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) { - return find_clp_in_name_tree(name, &unconf_name_tree); + return find_clp_in_name_tree(name, &nn->unconf_name_tree); } static void @@ -1677,7 +1673,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, goto out; } - unconf = find_unconfirmed_client_by_name(&exid->clname); + unconf = find_unconfirmed_client_by_name(&exid->clname, nn); if (unconf) /* case 4, possible retry or client restart */ expire_client(unconf); @@ -2239,7 +2235,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; } } - unconf = find_unconfirmed_client_by_name(&clname); + unconf = find_unconfirmed_client_by_name(&clname, nn); if (unconf) expire_client(unconf); status = nfserr_jukebox; @@ -4720,7 +4716,6 @@ nfs4_state_init(void) { int i; - unconf_name_tree = RB_ROOT; for (i = 0; i < SESSION_HASH_SIZE; i++) INIT_LIST_HEAD(&sessionid_hashtbl[i]); for (i = 0; i < FILE_HASH_SIZE; i++) { @@ -4776,6 +4771,7 @@ static int nfs4_state_start_net(struct net *net) INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); } nn->conf_name_tree = RB_ROOT; + nn->unconf_name_tree = RB_ROOT; return 0; @@ -4791,6 +4787,7 @@ __nfs4_state_shutdown_net(struct net *net) int i; struct nfs4_client *clp = NULL; struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct rb_node *node, *tmp; for (i = 0; i < CLIENT_HASH_SIZE; i++) { while (!list_empty(&nn->conf_id_hashtbl[i])) { @@ -4798,6 +4795,16 @@ __nfs4_state_shutdown_net(struct net *net) destroy_client(clp); } } + + node = rb_first(&nn->unconf_name_tree); + while (node != NULL) { + tmp = node; + node = rb_next(tmp); + clp = rb_entry(tmp, struct nfs4_client, cl_namenode); + rb_erase(tmp, &nn->unconf_name_tree); + destroy_client(clp); + } + kfree(nn->unconf_id_hashtbl); kfree(nn->conf_id_hashtbl); } @@ -4857,22 +4864,11 @@ out_recovery: static void __nfs4_state_shutdown(struct net *net) { - struct nfs4_client *clp = NULL; struct nfs4_delegation *dp = NULL; struct list_head *pos, *next, reaplist; - struct rb_node *node, *tmp; __nfs4_state_shutdown_net(net); - node = rb_first(&unconf_name_tree); - while (node != NULL) { - tmp = node; - node = rb_next(tmp); - clp = rb_entry(tmp, struct nfs4_client, cl_namenode); - rb_erase(tmp, &unconf_name_tree); - destroy_client(clp); - } - INIT_LIST_HEAD(&reaplist); spin_lock(&recall_lock); list_for_each_safe(pos, next, &del_recall_lru) { -- cgit v0.10.2 From 9b5311374057e5c87017ea3756e566047c9b61e7 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:41 +0300 Subject: nfsd: make ownerstr_hashtbl allocated per net This hash holds open owner state and closely associated with nfs4_clients info, which are network namespace aware. So let's make it allocated per network namespace too. Note: this hash can be allocated in per-net operations. But it looks better to allocate it on nfsd state start and thus don't waste resources if server is not running. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 1e76030..46cca94 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -60,6 +60,7 @@ struct nfsd_net { struct rb_root conf_name_tree; struct list_head *unconf_id_hashtbl; struct rb_root unconf_name_tree; + struct list_head *ownerstr_hashtbl; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b353291..f68514d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -176,8 +176,6 @@ static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) return ret & OWNER_HASH_MASK; } -static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; - /* hash table for nfs4_file */ #define FILE_HASH_BITS 8 #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) @@ -2428,7 +2426,9 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) { - list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + + list_add(&oo->oo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); list_add(&oo->oo_perclient, &clp->cl_openowners); } @@ -2486,13 +2486,14 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, } static struct nfs4_openowner * -find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, bool sessions) +find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, + bool sessions, struct nfsd_net *nn) { struct nfs4_stateowner *so; struct nfs4_openowner *oo; struct nfs4_client *clp; - list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { + list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) { if (!so->so_is_open_owner) continue; if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { @@ -2648,7 +2649,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, return nfserr_jukebox; strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); - oo = find_openstateowner_str(strhashval, open, cstate->minorversion); + oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn); open->op_openowner = oo; if (!oo) { clp = find_confirmed_client(clientid, cstate->minorversion, @@ -3976,8 +3977,9 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s struct inode *inode = open_stp->st_file->fi_inode; unsigned int inohash = lockowner_ino_hashval(inode, clp->cl_clientid.cl_id, &lo->lo_owner.so_owner); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); - list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]); + list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]); list_add(&lo->lo_perstateid, &open_stp->st_lockowners); } @@ -4458,7 +4460,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, status = nfserr_locks_held; INIT_LIST_HEAD(&matches); - list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) { + list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) { if (sop->so_is_open_owner) continue; if (!same_owner_str(sop, owner, clid)) @@ -4614,13 +4616,14 @@ static void release_openowner_sop(struct nfs4_stateowner *sop) } static int nfsd_release_n_owners(u64 num, bool is_open_owner, - void (*release_sop)(struct nfs4_stateowner *)) + void (*release_sop)(struct nfs4_stateowner *), + struct nfsd_net *nn) { int i, count = 0; struct nfs4_stateowner *sop, *next; for (i = 0; i < OWNER_HASH_SIZE; i++) { - list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) { + list_for_each_entry_safe(sop, next, &nn->ownerstr_hashtbl[i], so_strhash) { if (sop->so_is_open_owner != is_open_owner) continue; release_sop(sop); @@ -4634,9 +4637,10 @@ static int nfsd_release_n_owners(u64 num, bool is_open_owner, void nfsd_forget_locks(u64 num) { int count; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); nfs4_lock_state(); - count = nfsd_release_n_owners(num, false, release_lockowner_sop); + count = nfsd_release_n_owners(num, false, release_lockowner_sop, nn); nfs4_unlock_state(); printk(KERN_INFO "NFSD: Forgot %d locks", count); @@ -4645,9 +4649,10 @@ void nfsd_forget_locks(u64 num) void nfsd_forget_openowners(u64 num) { int count; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); nfs4_lock_state(); - count = nfsd_release_n_owners(num, true, release_openowner_sop); + count = nfsd_release_n_owners(num, true, release_openowner_sop, nn); nfs4_unlock_state(); printk(KERN_INFO "NFSD: Forgot %d open owners", count); @@ -4721,9 +4726,6 @@ nfs4_state_init(void) for (i = 0; i < FILE_HASH_SIZE; i++) { INIT_LIST_HEAD(&file_hashtbl[i]); } - for (i = 0; i < OWNER_HASH_SIZE; i++) { - INIT_LIST_HEAD(&ownerstr_hashtbl[i]); - } for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]); INIT_LIST_HEAD(&close_lru); @@ -4765,16 +4767,24 @@ static int nfs4_state_start_net(struct net *net) CLIENT_HASH_SIZE, GFP_KERNEL); if (!nn->unconf_id_hashtbl) goto err_unconf_id; + nn->ownerstr_hashtbl = kmalloc(sizeof(struct list_head) * + OWNER_HASH_SIZE, GFP_KERNEL); + if (!nn->ownerstr_hashtbl) + goto err_ownerstr; for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); } + for (i = 0; i < OWNER_HASH_SIZE; i++) + INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]); nn->conf_name_tree = RB_ROOT; nn->unconf_name_tree = RB_ROOT; return 0; +err_ownerstr: + kfree(nn->unconf_id_hashtbl); err_unconf_id: kfree(nn->conf_id_hashtbl); err: @@ -4805,6 +4815,7 @@ __nfs4_state_shutdown_net(struct net *net) destroy_client(clp); } + kfree(nn->ownerstr_hashtbl); kfree(nn->unconf_id_hashtbl); kfree(nn->conf_id_hashtbl); } -- cgit v0.10.2 From 20e9e2bc98b907efe82621797c561f6169d63d96 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:46 +0300 Subject: nfsd: make lockowner_ino_hashtbl allocated per net This hash holds file lock owners and closely associated with nfs4_clients info, which are network namespace aware. So let's make it allocated per network namespace too. Note: this hash can be allocated in per-net operations. But it looks better to allocate it on nfsd state start and thus don't waste resources if server is not running. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 46cca94..2281f6d 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -29,6 +29,9 @@ #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) #define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1) +#define LOCKOWNER_INO_HASH_BITS 8 +#define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS) + struct cld_net; struct nfsd_net { @@ -61,6 +64,7 @@ struct nfsd_net { struct list_head *unconf_id_hashtbl; struct rb_root unconf_name_tree; struct list_head *ownerstr_hashtbl; + struct list_head *lockowner_ino_hashtbl; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f68514d..1e76d55 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3862,8 +3862,6 @@ out: #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) -#define LOCKOWNER_INO_HASH_BITS 8 -#define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS) #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1) static inline u64 @@ -3893,8 +3891,6 @@ static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct & LOCKOWNER_INO_HASH_MASK; } -static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE]; - /* * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that * we can't properly handle lock requests that go beyond the (2^63 - 1)-th @@ -3960,12 +3956,12 @@ static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, c static struct nfs4_lockowner * find_lockowner_str(struct inode *inode, clientid_t *clid, - struct xdr_netobj *owner) + struct xdr_netobj *owner, struct nfsd_net *nn) { unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner); struct nfs4_lockowner *lo; - list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) { + list_for_each_entry(lo, &nn->lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) { if (same_lockowner_ino(lo, inode, clid, owner)) return lo; } @@ -3980,7 +3976,7 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); - list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]); + list_add(&lo->lo_owner_ino_hash, &nn->lockowner_ino_hashtbl[inohash]); list_add(&lo->lo_perstateid, &open_stp->st_lockowners); } @@ -4054,8 +4050,10 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, s struct nfs4_client *cl = oo->oo_owner.so_client; struct nfs4_lockowner *lo; unsigned int strhashval; + struct nfsd_net *nn = net_generic(cl->net, nfsd_net_id); - lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner); + lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, + &lock->v.new.owner, nn); if (lo) { if (!cstate->minorversion) return nfserr_bad_seqid; @@ -4308,7 +4306,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; } - lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner); + lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner, nn); if (lo) file_lock->fl_owner = (fl_owner_t)lo; file_lock->fl_pid = current->tgid; @@ -4726,8 +4724,6 @@ nfs4_state_init(void) for (i = 0; i < FILE_HASH_SIZE; i++) { INIT_LIST_HEAD(&file_hashtbl[i]); } - for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) - INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]); INIT_LIST_HEAD(&close_lru); INIT_LIST_HEAD(&client_lru); INIT_LIST_HEAD(&del_recall_lru); @@ -4771,6 +4767,10 @@ static int nfs4_state_start_net(struct net *net) OWNER_HASH_SIZE, GFP_KERNEL); if (!nn->ownerstr_hashtbl) goto err_ownerstr; + nn->lockowner_ino_hashtbl = kmalloc(sizeof(struct list_head) * + LOCKOWNER_INO_HASH_SIZE, GFP_KERNEL); + if (!nn->lockowner_ino_hashtbl) + goto err_lockowner_ino; for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); @@ -4778,11 +4778,15 @@ static int nfs4_state_start_net(struct net *net) } for (i = 0; i < OWNER_HASH_SIZE; i++) INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]); + for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) + INIT_LIST_HEAD(&nn->lockowner_ino_hashtbl[i]); nn->conf_name_tree = RB_ROOT; nn->unconf_name_tree = RB_ROOT; return 0; +err_lockowner_ino: + kfree(nn->ownerstr_hashtbl); err_ownerstr: kfree(nn->unconf_id_hashtbl); err_unconf_id: @@ -4815,6 +4819,7 @@ __nfs4_state_shutdown_net(struct net *net) destroy_client(clp); } + kfree(nn->lockowner_ino_hashtbl); kfree(nn->ownerstr_hashtbl); kfree(nn->unconf_id_hashtbl); kfree(nn->conf_id_hashtbl); -- cgit v0.10.2 From 1872de0e8171904612ee85de218fa045bc473cad Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:51 +0300 Subject: nfsd: make sessionid_hashtbl allocated per net This hash holds established sessions state and closely associated with nfs4_clients info, which are network namespace aware. So let's make it allocated per network namespace too. Note: this hash can be allocated in per-net operations. But it looks better to allocate it on nfsd state start and thus don't waste resources if server is not running. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 2281f6d..da33d3f 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -32,6 +32,8 @@ #define LOCKOWNER_INO_HASH_BITS 8 #define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS) +#define SESSION_HASH_SIZE 512 + struct cld_net; struct nfsd_net { @@ -65,6 +67,7 @@ struct nfsd_net { struct rb_root unconf_name_tree; struct list_head *ownerstr_hashtbl; struct list_head *lockowner_ino_hashtbl; + struct list_head *sessionid_hashtbl; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 1e76d55..248f217 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -632,9 +632,6 @@ static void release_openowner(struct nfs4_openowner *oo) nfs4_free_openowner(oo); } -#define SESSION_HASH_SIZE 512 -static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; - static inline int hash_sessionid(struct nfs4_sessionid *sessionid) { @@ -928,6 +925,7 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) { int idx; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); new->se_client = clp; gen_sessionid(new); @@ -941,7 +939,7 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru kref_init(&new->se_ref); idx = hash_sessionid(&new->se_sessionid); spin_lock(&client_lock); - list_add(&new->se_hash, &sessionid_hashtbl[idx]); + list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); spin_lock(&clp->cl_lock); list_add(&new->se_perclnt, &clp->cl_sessions); spin_unlock(&clp->cl_lock); @@ -963,15 +961,16 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru /* caller must hold client_lock */ static struct nfsd4_session * -find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) +find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) { struct nfsd4_session *elem; int idx; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); dump_sessionid(__func__, sessionid); idx = hash_sessionid(sessionid); /* Search in the appropriate list */ - list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { + list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { if (!memcmp(elem->se_sessionid.data, sessionid->data, NFS4_MAX_SESSIONID_LEN)) { return elem; @@ -1905,7 +1904,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, if (!nfsd4_last_compound_op(rqstp)) return nfserr_not_only_op; spin_lock(&client_lock); - cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid); + cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp)); /* Sorta weird: we only need the refcnt'ing because new_conn acquires * client_lock iself: */ if (cstate->session) { @@ -1954,7 +1953,7 @@ nfsd4_destroy_session(struct svc_rqst *r, } dump_sessionid(__func__, &sessionid->sessionid); spin_lock(&client_lock); - ses = find_in_sessionid_hashtbl(&sessionid->sessionid); + ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r)); if (!ses) { spin_unlock(&client_lock); goto out; @@ -2050,7 +2049,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, spin_lock(&client_lock); status = nfserr_badsession; - session = find_in_sessionid_hashtbl(&seq->sessionid); + session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp)); if (!session) goto out; @@ -4719,8 +4718,6 @@ nfs4_state_init(void) { int i; - for (i = 0; i < SESSION_HASH_SIZE; i++) - INIT_LIST_HEAD(&sessionid_hashtbl[i]); for (i = 0; i < FILE_HASH_SIZE; i++) { INIT_LIST_HEAD(&file_hashtbl[i]); } @@ -4771,6 +4768,10 @@ static int nfs4_state_start_net(struct net *net) LOCKOWNER_INO_HASH_SIZE, GFP_KERNEL); if (!nn->lockowner_ino_hashtbl) goto err_lockowner_ino; + nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) * + SESSION_HASH_SIZE, GFP_KERNEL); + if (!nn->sessionid_hashtbl) + goto err_sessionid; for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); @@ -4780,11 +4781,15 @@ static int nfs4_state_start_net(struct net *net) INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]); for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) INIT_LIST_HEAD(&nn->lockowner_ino_hashtbl[i]); + for (i = 0; i < SESSION_HASH_SIZE; i++) + INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); nn->conf_name_tree = RB_ROOT; nn->unconf_name_tree = RB_ROOT; return 0; +err_sessionid: + kfree(nn->lockowner_ino_hashtbl); err_lockowner_ino: kfree(nn->ownerstr_hashtbl); err_ownerstr: @@ -4819,6 +4824,7 @@ __nfs4_state_shutdown_net(struct net *net) destroy_client(clp); } + kfree(nn->sessionid_hashtbl); kfree(nn->lockowner_ino_hashtbl); kfree(nn->ownerstr_hashtbl); kfree(nn->unconf_id_hashtbl); -- cgit v0.10.2 From 5ed58bb243484e01e82ffca8451907403168e262 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:21:56 +0300 Subject: nfsd: make client_lru list per net This list holds nfs4 clients queue for lease renewal, which are network namespace aware. So let's make this list per network namespace too. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index da33d3f..9a98a0a 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -68,6 +68,11 @@ struct nfsd_net { struct list_head *ownerstr_hashtbl; struct list_head *lockowner_ino_hashtbl; struct list_head *sessionid_hashtbl; + /* + * client_lru holds client queue ordered by nfs4_client.cl_time + * for lease renewal. + */ + struct list_head client_lru; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 248f217..9cf7e9b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -402,15 +402,11 @@ static unsigned int clientstr_hashval(const char *name) } /* - * client_lru holds client queue ordered by nfs4_client.cl_time - * for lease renewal. - * * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time * for last close replay. * * All of the above fields are protected by the client_mutex. */ -static struct list_head client_lru; static struct list_head close_lru; /* @@ -995,6 +991,8 @@ unhash_session(struct nfsd4_session *ses) static inline void renew_client_locked(struct nfs4_client *clp) { + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + if (is_client_expired(clp)) { WARN_ON(1); printk("%s: client (clientid %08x/%08x) already expired\n", @@ -1007,7 +1005,7 @@ renew_client_locked(struct nfs4_client *clp) dprintk("renewing client (clientid %08x/%08x)\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); - list_move_tail(&clp->cl_lru, &client_lru); + list_move_tail(&clp->cl_lru, &nn->client_lru); clp->cl_time = get_seconds(); } @@ -3196,6 +3194,7 @@ nfs4_laundromat(void) time_t cutoff = get_seconds() - nfsd4_lease; time_t t, clientid_val = nfsd4_lease; time_t u, test_val = nfsd4_lease; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); nfs4_lock_state(); @@ -3203,7 +3202,7 @@ nfs4_laundromat(void) nfsd4_end_grace(&init_net); INIT_LIST_HEAD(&reaplist); spin_lock(&client_lock); - list_for_each_safe(pos, next, &client_lru) { + list_for_each_safe(pos, next, &nn->client_lru) { clp = list_entry(pos, struct nfs4_client, cl_lru); if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { t = clp->cl_time - cutoff; @@ -4590,9 +4589,10 @@ void nfsd_forget_clients(u64 num) { struct nfs4_client *clp, *next; int count = 0; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); nfs4_lock_state(); - list_for_each_entry_safe(clp, next, &client_lru, cl_lru) { + list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { expire_client(clp); if (++count == num) break; @@ -4722,7 +4722,6 @@ nfs4_state_init(void) INIT_LIST_HEAD(&file_hashtbl[i]); } INIT_LIST_HEAD(&close_lru); - INIT_LIST_HEAD(&client_lru); INIT_LIST_HEAD(&del_recall_lru); } @@ -4785,6 +4784,7 @@ static int nfs4_state_start_net(struct net *net) INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); nn->conf_name_tree = RB_ROOT; nn->unconf_name_tree = RB_ROOT; + INIT_LIST_HEAD(&nn->client_lru); return 0; -- cgit v0.10.2 From 73758fed711b847d833b9b0db59137eaeed06485 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:22:01 +0300 Subject: nfsd: make close_lru list per net This list holds nfs4 clients (open) stateowner queue for last close replay, which are network namespace aware. So let's make this list per network namespace too. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 9a98a0a..a356ea3 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -71,8 +71,14 @@ struct nfsd_net { /* * client_lru holds client queue ordered by nfs4_client.cl_time * for lease renewal. + * + * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time + * for last close replay. + * + * All of the above fields are protected by the client_mutex. */ struct list_head client_lru; + struct list_head close_lru; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9cf7e9b..a8e4064 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -402,14 +402,6 @@ static unsigned int clientstr_hashval(const char *name) } /* - * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time - * for last close replay. - * - * All of the above fields are protected by the client_mutex. - */ -static struct list_head close_lru; - -/* * We store the NONE, READ, WRITE, and BOTH bits separately in the * st_{access,deny}_bmap field of the stateid, in order to track not * only what share bits are currently in force, but also what @@ -2465,11 +2457,13 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, } static void -move_to_close_lru(struct nfs4_openowner *oo) +move_to_close_lru(struct nfs4_openowner *oo, struct net *net) { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); - list_move_tail(&oo->oo_close_lru, &close_lru); + list_move_tail(&oo->oo_close_lru, &nn->close_lru); oo->oo_time = get_seconds(); } @@ -3242,7 +3236,7 @@ nfs4_laundromat(void) unhash_delegation(dp); } test_val = nfsd4_lease; - list_for_each_safe(pos, next, &close_lru) { + list_for_each_safe(pos, next, &nn->close_lru) { oo = container_of(pos, struct nfs4_openowner, oo_close_lru); if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { u = oo->oo_time - cutoff; @@ -3820,7 +3814,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * little while to handle CLOSE replay. */ if (list_empty(&oo->oo_owner.so_stateids)) - move_to_close_lru(oo); + move_to_close_lru(oo, SVC_NET(rqstp)); } } out: @@ -4721,7 +4715,6 @@ nfs4_state_init(void) for (i = 0; i < FILE_HASH_SIZE; i++) { INIT_LIST_HEAD(&file_hashtbl[i]); } - INIT_LIST_HEAD(&close_lru); INIT_LIST_HEAD(&del_recall_lru); } @@ -4785,6 +4778,7 @@ static int nfs4_state_start_net(struct net *net) nn->conf_name_tree = RB_ROOT; nn->unconf_name_tree = RB_ROOT; INIT_LIST_HEAD(&nn->client_lru); + INIT_LIST_HEAD(&nn->close_lru); return 0; -- cgit v0.10.2 From 3320fef19b542b8df9606bd8e63990dc2a3fb330 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:22:07 +0300 Subject: nfsd: use service net instead of hard-coded init_net This patch replaces init_net by SVC_NET(), where possible and also passes proper context to nested functions where required. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index f955176..1d2396b 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -40,6 +40,7 @@ #include "xdr4.h" #include "vfs.h" #include "current_stateid.h" +#include "netns.h" #define NFSDDBG_FACILITY NFSDDBG_PROC @@ -304,6 +305,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, { __be32 status; struct nfsd4_compoundres *resp; + struct net *net = SVC_NET(rqstp); + struct nfsd_net *nn = net_generic(net, nfsd_net_id); dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n", (int)open->op_fname.len, open->op_fname.data, @@ -331,7 +334,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, /* check seqid for replay. set nfs4_owner */ resp = rqstp->rq_resp; - status = nfsd4_process_open1(&resp->cstate, open); + status = nfsd4_process_open1(&resp->cstate, open, nn); if (status == nfserr_replay_me) { struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay; fh_put(&cstate->current_fh); @@ -354,10 +357,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, /* Openowner is now set, so sequence id will get bumped. Now we need * these checks before we do any creates: */ status = nfserr_grace; - if (locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) + if (locks_in_grace(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) goto out; status = nfserr_no_grace; - if (!locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) + if (!locks_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) goto out; switch (open->op_claim_type) { @@ -370,7 +373,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, break; case NFS4_OPEN_CLAIM_PREVIOUS: open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; - status = nfs4_check_open_reclaim(&open->op_clientid, cstate->minorversion); + status = nfs4_check_open_reclaim(&open->op_clientid, + cstate->minorversion, + nn); if (status) goto out; case NFS4_OPEN_CLAIM_FH: diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index a8e4064..996a8a5 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2620,14 +2620,13 @@ static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4 __be32 nfsd4_process_open1(struct nfsd4_compound_state *cstate, - struct nfsd4_open *open) + struct nfsd4_open *open, struct nfsd_net *nn) { clientid_t *clientid = &open->op_clientid; struct nfs4_client *clp = NULL; unsigned int strhashval; struct nfs4_openowner *oo = NULL; __be32 status; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); if (STALE_CLIENTID(&open->op_clientid, nn)) return nfserr_stale_clientid; @@ -3408,10 +3407,11 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) return nfs_ok; } -static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s, bool sessions) +static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, + struct nfs4_stid **s, bool sessions, + struct nfsd_net *nn) { struct nfs4_client *cl; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) return nfserr_bad_stateid; @@ -3439,6 +3439,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, struct nfs4_delegation *dp = NULL; struct svc_fh *current_fh = &cstate->current_fh; struct inode *ino = current_fh->fh_dentry->d_inode; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); __be32 status; if (filpp) @@ -3450,7 +3451,8 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) return check_special_stateids(net, current_fh, stateid, flags); - status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion); + status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, + &s, cstate->minorversion, nn); if (status) return status; status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); @@ -3591,7 +3593,8 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_ static __be32 nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, char typemask, - struct nfs4_ol_stateid **stpp) + struct nfs4_ol_stateid **stpp, + struct nfsd_net *nn) { __be32 status; struct nfs4_stid *s; @@ -3600,7 +3603,8 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, seqid, STATEID_VAL(stateid)); *stpp = NULL; - status = nfsd4_lookup_stateid(stateid, typemask, &s, cstate->minorversion); + status = nfsd4_lookup_stateid(stateid, typemask, &s, + cstate->minorversion, nn); if (status) return status; *stpp = openlockstateid(s); @@ -3609,13 +3613,14 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp); } -static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_ol_stateid **stpp) +static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, + stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) { __be32 status; struct nfs4_openowner *oo; status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, - NFS4_OPEN_STID, stpp); + NFS4_OPEN_STID, stpp, nn); if (status) return status; oo = openowner((*stpp)->st_stateowner); @@ -3631,6 +3636,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, __be32 status; struct nfs4_openowner *oo; struct nfs4_ol_stateid *stp; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", (int)cstate->current_fh.fh_dentry->d_name.len, @@ -3644,7 +3650,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfs4_preprocess_seqid_op(cstate, oc->oc_seqid, &oc->oc_req_stateid, - NFS4_OPEN_STID, &stp); + NFS4_OPEN_STID, &stp, nn); if (status) goto out; oo = openowner(stp->st_stateowner); @@ -3708,6 +3714,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, { __be32 status; struct nfs4_ol_stateid *stp; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", (int)cstate->current_fh.fh_dentry->d_name.len, @@ -3720,7 +3727,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, nfs4_lock_state(); status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, - &od->od_stateid, &stp); + &od->od_stateid, &stp, nn); if (status) goto out; status = nfserr_inval; @@ -3783,6 +3790,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, __be32 status; struct nfs4_openowner *oo; struct nfs4_ol_stateid *stp; + struct net *net = SVC_NET(rqstp); + struct nfsd_net *nn = net_generic(net, nfsd_net_id); dprintk("NFSD: nfsd4_close on file %.*s\n", (int)cstate->current_fh.fh_dentry->d_name.len, @@ -3792,7 +3801,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, &close->cl_stateid, NFS4_OPEN_STID|NFS4_CLOSED_STID, - &stp); + &stp, nn); if (status) goto out; oo = openowner(stp->st_stateowner); @@ -3831,12 +3840,14 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stateid_t *stateid = &dr->dr_stateid; struct nfs4_stid *s; __be32 status; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) return status; nfs4_lock_state(); - status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion); + status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, + cstate->minorversion, nn); if (status) goto out; dp = delegstateid(s); @@ -4085,7 +4096,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, bool new_state = false; int lkflg; int err; - struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + struct net *net = SVC_NET(rqstp); + struct nfsd_net *nn = net_generic(net, nfsd_net_id); dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", (long long) lock->lk_offset, @@ -4119,7 +4131,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfs4_preprocess_confirmed_seqid_op(cstate, lock->lk_new_open_seqid, &lock->lk_new_open_stateid, - &open_stp); + &open_stp, nn); if (status) goto out; open_sop = openowner(open_stp->st_stateowner); @@ -4133,7 +4145,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfs4_preprocess_seqid_op(cstate, lock->lk_old_lock_seqid, &lock->lk_old_lock_stateid, - NFS4_LOCK_STID, &lock_stp); + NFS4_LOCK_STID, &lock_stp, nn); if (status) goto out; lock_sop = lockowner(lock_stp->st_stateowner); @@ -4144,10 +4156,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; status = nfserr_grace; - if (locks_in_grace(SVC_NET(rqstp)) && !lock->lk_reclaim) + if (locks_in_grace(net) && !lock->lk_reclaim) goto out; status = nfserr_no_grace; - if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim) + if (!locks_in_grace(net) && lock->lk_reclaim) goto out; file_lock = locks_alloc_lock(); @@ -4333,7 +4345,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct file_lock *file_lock = NULL; __be32 status; int err; - + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", (long long) locku->lu_offset, (long long) locku->lu_length); @@ -4344,7 +4357,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfs4_lock_state(); status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, - &locku->lu_stateid, NFS4_LOCK_STID, &stp); + &locku->lu_stateid, NFS4_LOCK_STID, + &stp, nn); if (status) goto out; filp = find_any_file(stp->st_file); @@ -4564,10 +4578,9 @@ nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) * Called from OPEN. Look for clientid in reclaim list. */ __be32 -nfs4_check_open_reclaim(clientid_t *clid, bool sessions) +nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn) { struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); /* find clientid in conf_id_hashtbl */ clp = find_confirmed_client(clid, sessions, nn); @@ -4583,7 +4596,7 @@ void nfsd_forget_clients(u64 num) { struct nfs4_client *clp, *next; int count = 0; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); nfs4_lock_state(); list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { @@ -4897,8 +4910,8 @@ __nfs4_state_shutdown(struct net *net) unhash_delegation(dp); } - nfsd4_client_tracking_exit(&init_net); - put_net(&init_net); + nfsd4_client_tracking_exit(net); + put_net(net); } void diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 26a912c..bfe0106 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -470,7 +470,7 @@ void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *) extern void nfs4_release_reclaim(struct nfsd_net *); extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn); -extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions); +extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn); extern void nfs4_free_openowner(struct nfs4_openowner *); extern void nfs4_free_lockowner(struct nfs4_lockowner *); extern int set_callback_cred(void); diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 71c5c47..3c414c1 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -581,7 +581,7 @@ extern __be32 nfsd4_destroy_session(struct svc_rqst *, extern __be32 nfsd4_destroy_clientid(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_destroy_clientid *); __be32 nfsd4_reclaim_complete(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_reclaim_complete *); extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *, - struct nfsd4_open *open); + struct nfsd4_open *open, struct nfsd_net *nn); extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open); extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status); -- cgit v0.10.2 From 12760c6685624d65f8de078485c21b6a08e83409 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:22:12 +0300 Subject: nfsd: pass nfsd_net instead of net to grace enders Passing net context looks as overkill. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 376692a..b657b62 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -58,7 +58,7 @@ struct nfsd4_client_tracking_ops { void (*create)(struct nfs4_client *); void (*remove)(struct nfs4_client *); int (*check)(struct nfs4_client *); - void (*grace_done)(struct net *, time_t); + void (*grace_done)(struct nfsd_net *, time_t); }; /* Globals */ @@ -391,10 +391,9 @@ purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) } static void -nfsd4_recdir_purge_old(struct net *net, time_t boot_time) +nfsd4_recdir_purge_old(struct nfsd_net *nn, time_t boot_time) { int status; - struct nfsd_net *nn = net_generic(net, nfsd_net_id); in_grace = false; if (!rec_file) @@ -1017,11 +1016,10 @@ nfsd4_cld_check(struct nfs4_client *clp) } static void -nfsd4_cld_grace_done(struct net *net, time_t boot_time) +nfsd4_cld_grace_done(struct nfsd_net *nn, time_t boot_time) { int ret; struct cld_upcall *cup; - struct nfsd_net *nn = net_generic(net, nfsd_net_id); struct cld_net *cn = nn->cld_net; cup = alloc_cld_upcall(cn); @@ -1241,7 +1239,7 @@ nfsd4_umh_cltrack_check(struct nfs4_client *clp) } static void -nfsd4_umh_cltrack_grace_done(struct net __attribute__((unused)) *net, +nfsd4_umh_cltrack_grace_done(struct nfsd_net __attribute__((unused)) *nn, time_t boot_time) { char *legacy; @@ -1343,10 +1341,10 @@ nfsd4_client_record_check(struct nfs4_client *clp) } void -nfsd4_record_grace_done(struct net *net, time_t boot_time) +nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time) { if (client_tracking_ops) - client_tracking_ops->grace_done(net, boot_time); + client_tracking_ops->grace_done(nn, boot_time); } static int diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 996a8a5..2e4ed69 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3157,17 +3157,15 @@ out: } static void -nfsd4_end_grace(struct net *net) +nfsd4_end_grace(struct nfsd_net *nn) { - struct nfsd_net *nn = net_generic(net, nfsd_net_id); - /* do nothing if grace period already ended */ if (nn->grace_ended) return; dprintk("NFSD: end of grace period\n"); nn->grace_ended = true; - nfsd4_record_grace_done(net, nn->boot_time); + nfsd4_record_grace_done(nn, nn->boot_time); locks_end_grace(&nn->nfsd4_manager); /* * Now that every NFSv4 client has had the chance to recover and @@ -3192,7 +3190,7 @@ nfs4_laundromat(void) nfs4_lock_state(); dprintk("NFSD: laundromat service - starting\n"); - nfsd4_end_grace(&init_net); + nfsd4_end_grace(nn); INIT_LIST_HEAD(&reaplist); spin_lock(&client_lock); list_for_each_safe(pos, next, &nn->client_lru) { diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index bfe0106..2deb6a8 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -495,5 +495,5 @@ extern void nfsd4_client_tracking_exit(struct net *net); extern void nfsd4_client_record_create(struct nfs4_client *clp); extern void nfsd4_client_record_remove(struct nfs4_client *clp); extern int nfsd4_client_record_check(struct nfs4_client *clp); -extern void nfsd4_record_grace_done(struct net *net, time_t boot_time); +extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time); #endif /* NFSD4_STATE_H */ -- cgit v0.10.2 From 0912128149e86b48ed946371298d7fe61120d627 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 14 Nov 2012 18:22:17 +0300 Subject: nfsd: make laundromat network namespace aware This patch moves laundromat_work to nfsd per-net context, thus allowing to run multiple laundries. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index a356ea3..227b93e 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -79,6 +79,8 @@ struct nfsd_net { */ struct list_head client_lru; struct list_head close_lru; + + struct delayed_work laundromat_work; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2e4ed69..e75872f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3176,7 +3176,7 @@ nfsd4_end_grace(struct nfsd_net *nn) } static time_t -nfs4_laundromat(void) +nfs4_laundromat(struct nfsd_net *nn) { struct nfs4_client *clp; struct nfs4_openowner *oo; @@ -3185,7 +3185,6 @@ nfs4_laundromat(void) time_t cutoff = get_seconds() - nfsd4_lease; time_t t, clientid_val = nfsd4_lease; time_t u, test_val = nfsd4_lease; - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); nfs4_lock_state(); @@ -3251,16 +3250,19 @@ nfs4_laundromat(void) static struct workqueue_struct *laundry_wq; static void laundromat_main(struct work_struct *); -static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); static void -laundromat_main(struct work_struct *not_used) +laundromat_main(struct work_struct *laundry) { time_t t; + struct delayed_work *dwork = container_of(laundry, struct delayed_work, + work); + struct nfsd_net *nn = container_of(dwork, struct nfsd_net, + laundromat_work); - t = nfs4_laundromat(); + t = nfs4_laundromat(nn); dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); - queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); + queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); } static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) @@ -4791,6 +4793,8 @@ static int nfs4_state_start_net(struct net *net) INIT_LIST_HEAD(&nn->client_lru); INIT_LIST_HEAD(&nn->close_lru); + INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); + return 0; err_sessionid: @@ -4875,7 +4879,8 @@ nfs4_state_start(void) ret = nfsd4_create_callback_queue(); if (ret) goto out_free_laundry; - queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ); + + queue_delayed_work(laundry_wq, &nn->laundromat_work, nfsd4_grace * HZ); set_max_delegations(); return 0; out_free_laundry: @@ -4918,7 +4923,7 @@ nfs4_state_shutdown(void) struct net *net = &init_net; struct nfsd_net *nn = net_generic(net, nfsd_net_id); - cancel_delayed_work_sync(&laundromat_work); + cancel_delayed_work_sync(&nn->laundromat_work); destroy_workqueue(laundry_wq); locks_end_grace(&nn->nfsd4_manager); nfs4_lock_state(); -- cgit v0.10.2 From 438db5a92b7526a12591f764042528a86d2ebb4b Mon Sep 17 00:00:00 2001 From: Shmulik Ladkani Date: Sun, 23 Sep 2012 09:52:29 +0200 Subject: mtd: cmdlinepart: Simplify parse_cmdline_partitions Simply 'parse_cmdline_partitions': the outer loop iterating over 'partitions' is actually a search loop, it does not execute the inner loop for each partition, only for the matched partition. Let's break when search is successful, and move all inner code (relevant only for the matched partition) outside of the outer loop. Resulting code is much more readable, and makes the indent level sane. Signed-off-by: Shmulik Ladkani Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index aed1b8a..4baab3b 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -308,48 +308,52 @@ static int parse_cmdline_partitions(struct mtd_info *master, return err; } + /* + * Search for the partition definition matching master->name. + * If master->name is not set, stop at first partition definition. + */ for (part = partitions; part; part = part->next) { - if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) { - for (i = 0, offset = 0; i < part->num_parts; i++) { - if (part->parts[i].offset == OFFSET_CONTINUOUS) - part->parts[i].offset = offset; - else - offset = part->parts[i].offset; - - if (part->parts[i].size == SIZE_REMAINING) - part->parts[i].size = master->size - offset; - - if (part->parts[i].size == 0) { - printk(KERN_WARNING ERRP - "%s: skipping zero sized partition\n", - part->mtd_id); - part->num_parts--; - memmove(&part->parts[i], - &part->parts[i + 1], - sizeof(*part->parts) * (part->num_parts - i)); - continue; - } - - if (offset + part->parts[i].size > master->size) { - printk(KERN_WARNING ERRP - "%s: partitioning exceeds flash size, truncating\n", - part->mtd_id); - part->parts[i].size = master->size - offset; - } - offset += part->parts[i].size; - } - - *pparts = kmemdup(part->parts, - sizeof(*part->parts) * part->num_parts, - GFP_KERNEL); - if (!*pparts) - return -ENOMEM; - - return part->num_parts; + if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) + break; + } + + if (!part) + return 0; + + for (i = 0, offset = 0; i < part->num_parts; i++) { + if (part->parts[i].offset == OFFSET_CONTINUOUS) + part->parts[i].offset = offset; + else + offset = part->parts[i].offset; + + if (part->parts[i].size == SIZE_REMAINING) + part->parts[i].size = master->size - offset; + + if (part->parts[i].size == 0) { + printk(KERN_WARNING ERRP + "%s: skipping zero sized partition\n", + part->mtd_id); + part->num_parts--; + memmove(&part->parts[i], &part->parts[i + 1], + sizeof(*part->parts) * (part->num_parts - i)); + continue; } + + if (offset + part->parts[i].size > master->size) { + printk(KERN_WARNING ERRP + "%s: partitioning exceeds flash size, truncating\n", + part->mtd_id); + part->parts[i].size = master->size - offset; + } + offset += part->parts[i].size; } - return 0; + *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts, + GFP_KERNEL); + if (!*pparts) + return -ENOMEM; + + return part->num_parts; } -- cgit v0.10.2 From 2d350e5adb44b3fbc3b6d7ff5b8d086e7730c9b4 Mon Sep 17 00:00:00 2001 From: Vikram Narayanan Date: Sun, 23 Sep 2012 15:18:32 +0530 Subject: mtd: gpmi-nand: make debug prints more clear Make the error messages more debugging friendly Signed-off-by: Vikram Narayanan Acked-by: Huang Shijie Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index d79696b..e2c56fc 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -222,7 +222,7 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) ret = dma_map_sg(this->dev, sgl, 1, dr); if (ret == 0) - pr_err("map failed.\n"); + pr_err("DMA mapping failed.\n"); this->direct_dma_map_ok = false; } @@ -456,7 +456,7 @@ static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); if (!dma_chan) { - pr_err("dma_request_channel failed.\n"); + pr_err("Failed to request DMA channel.\n"); goto acquire_err; } @@ -625,7 +625,8 @@ static int read_page_prepare(struct gpmi_nand_data *this, length, DMA_FROM_DEVICE); if (dma_mapping_error(dev, dest_phys)) { if (alt_size < length) { - pr_err("Alternate buffer is too small\n"); + pr_err("%s, Alternate buffer is too small\n", + __func__); return -ENOMEM; } goto map_failed; @@ -675,7 +676,8 @@ static int send_page_prepare(struct gpmi_nand_data *this, DMA_TO_DEVICE); if (dma_mapping_error(dev, source_phys)) { if (alt_size < length) { - pr_err("Alternate buffer is too small\n"); + pr_err("%s, Alternate buffer is too small\n", + __func__); return -ENOMEM; } goto map_failed; @@ -763,7 +765,7 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) error_alloc: gpmi_free_dma_buffer(this); - pr_err("allocate DMA buffer ret!!\n"); + pr_err("Error allocating DMA buffers!\n"); return -ENOMEM; } @@ -1474,7 +1476,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) /* Set up the NFC geometry which is used by BCH. */ ret = bch_set_geometry(this); if (ret) { - pr_err("set geometry ret : %d\n", ret); + pr_err("Error setting BCH geometry : %d\n", ret); return ret; } -- cgit v0.10.2 From 12ad2be9d1db3dcce08f29bdc5415db3af58fa60 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 24 Sep 2012 03:39:39 +0200 Subject: mtd: m25p80: Make fast read configurable via DT Add DT property "m25p,fast-read" that signalises the particular chip supports "fast read" opcode. Signed-off-by: Marek Vasut Signed-off-by: Artem Bityutskiy diff --git a/Documentation/devicetree/bindings/mtd/m25p80.txt b/Documentation/devicetree/bindings/mtd/m25p80.txt new file mode 100644 index 0000000..6d3d576 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/m25p80.txt @@ -0,0 +1,29 @@ +* MTD SPI driver for ST M25Pxx (and similar) serial flash chips + +Required properties: +- #address-cells, #size-cells : Must be present if the device has sub-nodes + representing partitions. +- compatible : Should be the manufacturer and the name of the chip. Bear in mind + the DT binding is not Linux-only, but in case of Linux, see the + "m25p_ids" table in drivers/mtd/devices/m25p80.c for the list of + supported chips. +- reg : Chip-Select number +- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at + +Optional properties: +- m25p,fast-read : Use the "fast read" opcode to read data from the chip instead + of the usual "read" opcode. This opcode is not supported by + all chips and support for it can not be detected at runtime. + Refer to your chips' datasheet to check if this is supported + by your chip. + +Example: + + flash: m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,m25p80"; + reg = <0>; + spi-max-frequency = <40000000>; + m25p,fast-read; + }; diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 03838ba..82f9774 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -73,14 +73,6 @@ #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ #define MAX_CMD_SIZE 5 -#ifdef CONFIG_M25PXX_USE_FAST_READ -#define OPCODE_READ OPCODE_FAST_READ -#define FAST_READ_DUMMY_BYTE 1 -#else -#define OPCODE_READ OPCODE_NORM_READ -#define FAST_READ_DUMMY_BYTE 0 -#endif - #define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) /****************************************************************************/ @@ -93,6 +85,7 @@ struct m25p { u16 addr_width; u8 erase_opcode; u8 *command; + bool fast_read; }; static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) @@ -342,6 +335,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, struct m25p *flash = mtd_to_m25p(mtd); struct spi_transfer t[2]; struct spi_message m; + uint8_t opcode; pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), __func__, (u32)from, len); @@ -354,7 +348,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, * Should add 1 byte DUMMY_BYTE. */ t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE; + t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0); spi_message_add_tail(&t[0], &m); t[1].rx_buf = buf; @@ -376,12 +370,14 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, */ /* Set up the write data buffer. */ - flash->command[0] = OPCODE_READ; + opcode = flash->fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ; + flash->command[0] = opcode; m25p_addr2cmd(flash, from, flash->command); spi_sync(flash->spi, &m); - *retlen = m.actual_length - m25p_cmdsz(flash) - FAST_READ_DUMMY_BYTE; + *retlen = m.actual_length - m25p_cmdsz(flash) - + (flash->fast_read ? 1 : 0); mutex_unlock(&flash->lock); @@ -809,9 +805,10 @@ static int __devinit m25p_probe(struct spi_device *spi) struct flash_info *info; unsigned i; struct mtd_part_parser_data ppdata; + struct device_node __maybe_unused *np = spi->dev.of_node; #ifdef CONFIG_MTD_OF_PARTS - if (!of_device_is_available(spi->dev.of_node)) + if (!of_device_is_available(np)) return -ENODEV; #endif @@ -863,7 +860,8 @@ static int __devinit m25p_probe(struct spi_device *spi) flash = kzalloc(sizeof *flash, GFP_KERNEL); if (!flash) return -ENOMEM; - flash->command = kmalloc(MAX_CMD_SIZE + FAST_READ_DUMMY_BYTE, GFP_KERNEL); + flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0), + GFP_KERNEL); if (!flash->command) { kfree(flash); return -ENOMEM; @@ -920,6 +918,16 @@ static int __devinit m25p_probe(struct spi_device *spi) flash->page_size = info->page_size; flash->mtd.writebufsize = flash->page_size; + flash->fast_read = false; +#ifdef CONFIG_OF + if (np && of_property_read_bool(np, "m25p,fast-read")) + flash->fast_read = true; +#endif + +#ifdef CONFIG_M25PXX_USE_FAST_READ + flash->fast_read = true; +#endif + if (info->addr_width) flash->addr_width = info->addr_width; else { -- cgit v0.10.2 From 0aa87b7563f138149429f35727b975ec25a494a6 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Tue, 25 Sep 2012 11:05:27 +0200 Subject: mtd: m25p80: add support for the windbond w25q256 chip Signed-off-by: Matthieu CASTET Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 82f9774..7e2d8f9 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -161,6 +161,7 @@ static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable) { switch (JEDEC_MFR(jedec_id)) { case CFI_MFR_MACRONIX: + case 0xEF /* winbond */: flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B; return spi_write(flash->spi, flash->command, 1); default: @@ -741,6 +742,7 @@ static const struct spi_device_id m25p_ids[] = { { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) }, /* Catalyst / On Semiconductor -- non-JEDEC */ { "cat25c11", CAT25_INFO( 16, 8, 16, 1) }, -- cgit v0.10.2 From ecbcbc7b75bb1b7596fca2d588d2f7539dc4e581 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 25 Sep 2012 15:27:13 +0530 Subject: mtd: ofpart: Fix incorrect NULL check in parse_ofoldpart_partitions() The pointer returned by kzalloc should be tested for NULL to avoid potential NULL pointer dereference later. Incorrect pointer was being tested for NULL. Bug introduced by commit fbcf62a3 (mtd: physmap_of: move parse_obsolete_partitions to become separate parser). This patch fixes this bug. Signed-off-by: Sachin Kamat Cc: stable@vger.kernel.org [3.2+] Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 64be8f0..d9127e2 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -121,7 +121,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, nr_parts = plen / sizeof(part[0]); *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL); - if (!pparts) + if (!*pparts) return -ENOMEM; names = of_get_property(dp, "partition-names", &plen); -- cgit v0.10.2 From 30fad64325ba368ffe1f92bd37f4b96c1fa4da83 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 26 Sep 2012 16:15:27 -0700 Subject: mtd: fsl_elbc_nand: remove unnecessary badblock_pattern Since the introduction of nand_create_default_bbt_descr() (now known as nand_create_badblock_pattern()) in commit 58373ff0afff4cc8ac40608872995f4d87eb72ec nand_chip.badblock_pattern will be dynamically calculated to the same 1-byte-length pattern that is required by fsl_elbc_nand. This custom badblock_pattern is no longer needed, then, and its removal may help facilitate further nand_bbt.c/nand_base.c cleanup in the future (one down, many to go?) Anyway, with nand_bbt.c fixed, this effectively reverts: commit 452db2724351ff3d9416a183a7955e00ab4e6ab4 [MTD] [NAND] fsl_elbc_nand: fix OOB workability for large page NAND chips Signed-off-by: Brian Norris Cc: Scott Wood Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index cc1480a..4c4d3e5 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -109,20 +109,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { }; /* - * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset - * 1, so we have to adjust bad block pattern. This pattern should be used for - * x8 chips only. So far hardware does not support x16 chips anyway. - */ -static u8 scan_ff_pattern[] = { 0xff, }; - -static struct nand_bbt_descr largepage_memorybased = { - .options = 0, - .offs = 0, - .len = 1, - .pattern = scan_ff_pattern, -}; - -/* * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, * interfere with ECC positions, that's why we implement our own descriptors. * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0. @@ -699,7 +685,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) chip->ecc.layout = (priv->fmr & FMR_ECCM) ? &fsl_elbc_oob_lp_eccm1 : &fsl_elbc_oob_lp_eccm0; - chip->badblock_pattern = &largepage_memorybased; } } else { dev_err(priv->dev, -- cgit v0.10.2 From 2a0a288ec258bd38d8855fad9419aeb45b7e8499 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Thu, 27 Sep 2012 10:58:05 -0600 Subject: mtd: denali: split the generic driver and PCI layer The Denali controller can also be found in SoC devices attached to a simple bus. Move the PCI specific parts into denali_pci so that we can add a denali_dt that uses the same driver but for a device tree driver instead of a PCI based device. Signed-off-by: Jamie Iles Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 4883139..5102e87 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -57,8 +57,15 @@ config MTD_NAND_AUTCPU12 access the SmartMediaCard. config MTD_NAND_DENALI - depends on PCI + tristate "Support Denali NAND controller" + help + Enable support for the Denali NAND controller. This should be + combined with either the PCI or platform drivers to provide device + registration. + +config MTD_NAND_DENALI_PCI tristate "Support Denali NAND controller on Intel Moorestown" + depends on PCI && MTD_NAND_DENALI help Enable the driver for NAND flash on Intel Moorestown, using the Denali NAND controller core. @@ -66,7 +73,7 @@ config MTD_NAND_DENALI config MTD_NAND_DENALI_SCRATCH_REG_ADDR hex "Denali NAND size scratch register address" default "0xFF108018" - depends on MTD_NAND_DENALI + depends on MTD_NAND_DENALI_PCI help Some platforms place the NAND chip size in a scratch register because (some versions of) the driver aren't able to automatically diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 2cbd091..96a6171 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_NAND_SPIA) += spia.o obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_DENALI) += denali.o +obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index e706a23..0c8bb6b 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -16,14 +16,12 @@ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ - #include #include #include #include #include #include -#include #include #include @@ -89,13 +87,6 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." * format the bank into the proper bits for the controller */ #define BANK(x) ((x) << 24) -/* List of platforms this NAND controller has be integrated into */ -static const struct pci_device_id denali_pci_ids[] = { - { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, - { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, - { /* end: all zeroes */ } -}; - /* forward declarations */ static void clear_interrupts(struct denali_nand_info *denali); static uint32_t wait_for_irq(struct denali_nand_info *denali, @@ -699,7 +690,7 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) if (comp_res == 0) { /* timeout */ - printk(KERN_ERR "timeout occurred, status = 0x%x, mask = 0x%x\n", + pr_err("timeout occurred, status = 0x%x, mask = 0x%x\n", intr_status, irq_mask); intr_status = 0; @@ -1305,8 +1296,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, /* TODO: Read OOB data */ break; default: - printk(KERN_ERR ": unsupported command" - " received 0x%x\n", cmd); + pr_err(": unsupported command received 0x%x\n", cmd); break; } } @@ -1425,107 +1415,48 @@ void denali_drv_init(struct denali_nand_info *denali) denali->irq_status = 0; } -/* driver entry point */ -static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +int denali_init(struct denali_nand_info *denali) { - int ret = -ENODEV; - resource_size_t csr_base, mem_base; - unsigned long csr_len, mem_len; - struct denali_nand_info *denali; - - denali = kzalloc(sizeof(*denali), GFP_KERNEL); - if (!denali) - return -ENOMEM; + int ret; - ret = pci_enable_device(dev); - if (ret) { - printk(KERN_ERR "Spectra: pci_enable_device failed.\n"); - goto failed_alloc_memery; - } - - if (id->driver_data == INTEL_CE4100) { + if (denali->platform == INTEL_CE4100) { /* Due to a silicon limitation, we can only support * ONFI timing mode 1 and below. */ if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { - printk(KERN_ERR "Intel CE4100 only supports" - " ONFI timing mode 1 or below\n"); - ret = -EINVAL; - goto failed_enable_dev; - } - denali->platform = INTEL_CE4100; - mem_base = pci_resource_start(dev, 0); - mem_len = pci_resource_len(dev, 1); - csr_base = pci_resource_start(dev, 1); - csr_len = pci_resource_len(dev, 1); - } else { - denali->platform = INTEL_MRST; - csr_base = pci_resource_start(dev, 0); - csr_len = pci_resource_len(dev, 0); - mem_base = pci_resource_start(dev, 1); - mem_len = pci_resource_len(dev, 1); - if (!mem_len) { - mem_base = csr_base + csr_len; - mem_len = csr_len; + pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n"); + return -EINVAL; } } /* Is 32-bit DMA supported? */ - ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32)); + ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32)); if (ret) { - printk(KERN_ERR "Spectra: no usable DMA configuration\n"); - goto failed_enable_dev; + pr_err("Spectra: no usable DMA configuration\n"); + return ret; } - denali->buf.dma_buf = dma_map_single(&dev->dev, denali->buf.buf, + denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, DENALI_BUF_SIZE, DMA_BIDIRECTIONAL); - if (dma_mapping_error(&dev->dev, denali->buf.dma_buf)) { - dev_err(&dev->dev, "Spectra: failed to map DMA buffer\n"); - goto failed_enable_dev; - } - - pci_set_master(dev); - denali->dev = &dev->dev; - denali->mtd.dev.parent = &dev->dev; - - ret = pci_request_regions(dev, DENALI_NAND_NAME); - if (ret) { - printk(KERN_ERR "Spectra: Unable to request memory regions\n"); - goto failed_dma_map; - } - - denali->flash_reg = ioremap_nocache(csr_base, csr_len); - if (!denali->flash_reg) { - printk(KERN_ERR "Spectra: Unable to remap memory region\n"); - ret = -ENOMEM; - goto failed_req_regions; - } - - denali->flash_mem = ioremap_nocache(mem_base, mem_len); - if (!denali->flash_mem) { - printk(KERN_ERR "Spectra: ioremap_nocache failed!"); - ret = -ENOMEM; - goto failed_remap_reg; + if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { + dev_err(denali->dev, "Spectra: failed to map DMA buffer\n"); + return -EIO; } - + denali->mtd.dev.parent = denali->dev; denali_hw_init(denali); denali_drv_init(denali); /* denali_isr register is done after all the hardware * initilization is finished*/ - if (request_irq(dev->irq, denali_isr, IRQF_SHARED, + if (request_irq(denali->irq, denali_isr, IRQF_SHARED, DENALI_NAND_NAME, denali)) { - printk(KERN_ERR "Spectra: Unable to allocate IRQ\n"); - ret = -ENODEV; - goto failed_remap_mem; + pr_err("Spectra: Unable to allocate IRQ\n"); + return -ENODEV; } /* now that our ISR is registered, we can enable interrupts */ denali_set_intr_modes(denali, true); - - pci_set_drvdata(dev, denali); - denali->mtd.name = "denali-nand"; denali->mtd.owner = THIS_MODULE; denali->mtd.priv = &denali->nand; @@ -1549,8 +1480,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) */ if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) { ret = -ENODEV; - printk(KERN_ERR "Spectra: device size not supported by this " - "version of MTD."); + pr_err("Spectra: device size not supported by this version of MTD."); goto failed_req_irq; } @@ -1602,8 +1532,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) } else if (denali->mtd.oobsize < (denali->bbtskipbytes + ECC_8BITS * (denali->mtd.writesize / ECC_SECTOR_SIZE))) { - printk(KERN_ERR "Your NAND chip OOB is not large enough to" - " contain 8bit ECC correction codes"); + pr_err("Your NAND chip OOB is not large enough to \ + contain 8bit ECC correction codes"); goto failed_req_irq; } else { denali->nand.ecc.strength = 8; @@ -1655,56 +1585,24 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ret = mtd_device_register(&denali->mtd, NULL, 0); if (ret) { - dev_err(&dev->dev, "Spectra: Failed to register MTD: %d\n", + dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n", ret); goto failed_req_irq; } return 0; failed_req_irq: - denali_irq_cleanup(dev->irq, denali); -failed_remap_mem: - iounmap(denali->flash_mem); -failed_remap_reg: - iounmap(denali->flash_reg); -failed_req_regions: - pci_release_regions(dev); -failed_dma_map: - dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, - DMA_BIDIRECTIONAL); -failed_enable_dev: - pci_disable_device(dev); -failed_alloc_memery: - kfree(denali); + denali_irq_cleanup(denali->irq, denali); + return ret; } +EXPORT_SYMBOL(denali_init); /* driver exit point */ -static void denali_pci_remove(struct pci_dev *dev) +void denali_remove(struct denali_nand_info *denali) { - struct denali_nand_info *denali = pci_get_drvdata(dev); - - nand_release(&denali->mtd); - - denali_irq_cleanup(dev->irq, denali); - - iounmap(denali->flash_reg); - iounmap(denali->flash_mem); - pci_release_regions(dev); - pci_disable_device(dev); - dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, - DMA_BIDIRECTIONAL); - pci_set_drvdata(dev, NULL); - kfree(denali); + denali_irq_cleanup(denali->irq, denali); + dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, + DMA_BIDIRECTIONAL); } - -MODULE_DEVICE_TABLE(pci, denali_pci_ids); - -static struct pci_driver denali_pci_driver = { - .name = DENALI_NAND_NAME, - .id_table = denali_pci_ids, - .probe = denali_pci_probe, - .remove = denali_pci_remove, -}; - -module_pci_driver(denali_pci_driver); +EXPORT_SYMBOL(denali_remove); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index fabb9d5..e5aa995 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -487,6 +487,7 @@ struct denali_nand_info { uint32_t irq_status; int irq_debug_array[32]; int idx; + int irq; uint32_t devnum; /* represent how many nands connected */ uint32_t fwblks; /* represent how many blocks FW used */ @@ -496,4 +497,7 @@ struct denali_nand_info { uint32_t max_banks; }; +extern int denali_init(struct denali_nand_info *denali); +extern void denali_remove(struct denali_nand_info *denali); + #endif /*_LLD_NAND_*/ diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c new file mode 100644 index 0000000..ea074e6 --- /dev/null +++ b/drivers/mtd/nand/denali_pci.c @@ -0,0 +1,144 @@ +/* + * NAND Flash Controller Device Driver + * Copyright © 2009-2010, Intel Corporation and its suppliers. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ +#include +#include +#include +#include + +#include "denali.h" + +#define DENALI_NAND_NAME "denali-nand-pci" + +/* List of platforms this NAND controller has be integrated into */ +static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = { + { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, + { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, + { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, denali_pci_ids); + +static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int ret = -ENODEV; + resource_size_t csr_base, mem_base; + unsigned long csr_len, mem_len; + struct denali_nand_info *denali; + + denali = kzalloc(sizeof(*denali), GFP_KERNEL); + if (!denali) + return -ENOMEM; + + ret = pci_enable_device(dev); + if (ret) { + pr_err("Spectra: pci_enable_device failed.\n"); + goto failed_alloc_memery; + } + + if (id->driver_data == INTEL_CE4100) { + denali->platform = INTEL_CE4100; + mem_base = pci_resource_start(dev, 0); + mem_len = pci_resource_len(dev, 1); + csr_base = pci_resource_start(dev, 1); + csr_len = pci_resource_len(dev, 1); + } else { + denali->platform = INTEL_MRST; + csr_base = pci_resource_start(dev, 0); + csr_len = pci_resource_len(dev, 0); + mem_base = pci_resource_start(dev, 1); + mem_len = pci_resource_len(dev, 1); + if (!mem_len) { + mem_base = csr_base + csr_len; + mem_len = csr_len; + } + } + + pci_set_master(dev); + denali->dev = &dev->dev; + denali->irq = dev->irq; + + ret = pci_request_regions(dev, DENALI_NAND_NAME); + if (ret) { + pr_err("Spectra: Unable to request memory regions\n"); + goto failed_enable_dev; + } + + denali->flash_reg = ioremap_nocache(csr_base, csr_len); + if (!denali->flash_reg) { + pr_err("Spectra: Unable to remap memory region\n"); + ret = -ENOMEM; + goto failed_req_regions; + } + + denali->flash_mem = ioremap_nocache(mem_base, mem_len); + if (!denali->flash_mem) { + pr_err("Spectra: ioremap_nocache failed!"); + ret = -ENOMEM; + goto failed_remap_reg; + } + + ret = denali_init(denali); + if (ret) + goto failed_remap_mem; + + pci_set_drvdata(dev, denali); + + return 0; + +failed_remap_mem: + iounmap(denali->flash_mem); +failed_remap_reg: + iounmap(denali->flash_reg); +failed_req_regions: + pci_release_regions(dev); +failed_enable_dev: + pci_disable_device(dev); +failed_alloc_memery: + kfree(denali); + + return ret; +} + +/* driver exit point */ +static void denali_pci_remove(struct pci_dev *dev) +{ + struct denali_nand_info *denali = pci_get_drvdata(dev); + + denali_remove(denali); + iounmap(denali->flash_reg); + iounmap(denali->flash_mem); + pci_release_regions(dev); + pci_disable_device(dev); + pci_set_drvdata(dev, NULL); + kfree(denali); +} + +static struct pci_driver denali_pci_driver = { + .name = DENALI_NAND_NAME, + .id_table = denali_pci_ids, + .probe = denali_pci_probe, + .remove = denali_pci_remove, +}; + +static int __devinit denali_init_pci(void) +{ + pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__); + return pci_register_driver(&denali_pci_driver); +} +module_init(denali_init_pci); + +static void __devexit denali_exit_pci(void) +{ + pci_unregister_driver(&denali_pci_driver); +} +module_exit(denali_exit_pci); -- cgit v0.10.2 From 30f9f2fb7ba032665c8cea7694c815f18ed47a34 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Thu, 27 Sep 2012 10:58:06 -0600 Subject: mtd: denali: add a DT driver Add a device tree version of the Denali NAND driver. Based on an original patch from Jamie Iles to add a MMIO version of this driver. Signed-off-by: Dinh Nguyen Signed-off-by: Artem Bityutskiy diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt new file mode 100644 index 0000000..b04d03a --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt @@ -0,0 +1,23 @@ +* Denali NAND controller + +Required properties: + - compatible : should be "denali,denali-nand-dt" + - reg : should contain registers location and length for data and reg. + - reg-names: Should contain the reg names "nand_data" and "denali_reg" + - interrupts : The interrupt number. + - dm-mask : DMA bit mask + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Examples: + +nand: nand@ff900000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "denali,denali-nand-dt"; + reg = <0xff900000 0x100000>, <0xffb80000 0x10000>; + reg-names = "nand_data", "denali_reg"; + interrupts = <0 144 4>; + dma-mask = <0xffffffff>; +}; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 5102e87..ee803d6 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -69,7 +69,14 @@ config MTD_NAND_DENALI_PCI help Enable the driver for NAND flash on Intel Moorestown, using the Denali NAND controller core. - + +config MTD_NAND_DENALI_DT + tristate "Support Denali NAND controller as a DT device" + depends on HAVE_CLK && MTD_NAND_DENALI + help + Enable the driver for NAND flash on platforms using a Denali NAND + controller as a DT device. + config MTD_NAND_DENALI_SCRATCH_REG_ADDR hex "Denali NAND size scratch register address" default "0xFF108018" diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 96a6171..38358c9 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_DENALI) += denali.o obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o +obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index e5aa995..cec5712 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -466,6 +466,7 @@ struct nand_buf { #define INTEL_CE4100 1 #define INTEL_MRST 2 +#define DT 3 struct denali_nand_info { struct mtd_info mtd; diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c new file mode 100644 index 0000000..fbabbaa --- /dev/null +++ b/drivers/mtd/nand/denali_dt.c @@ -0,0 +1,167 @@ +/* + * NAND Flash Controller Device Driver for DT + * + * Copyright © 2011, Picochip. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "denali.h" + +struct denali_dt { + struct denali_nand_info denali; + struct clk *clk; +}; + +static void __iomem *request_and_map(struct device *dev, + const struct resource *res) +{ + void __iomem *ptr; + + if (!devm_request_mem_region(dev, res->start, resource_size(res), + "denali-dt")) { + dev_err(dev, "unable to request %s\n", res->name); + return NULL; + } + + ptr = devm_ioremap_nocache(dev, res->start, resource_size(res)); + if (!res) + dev_err(dev, "ioremap_nocache of %s failed!", res->name); + + return ptr; +} + +static const struct of_device_id denali_nand_dt_ids[] = { + { .compatible = "denali,denali-nand-dt" }, + { /* sentinel */ } + }; + +MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); + +static u64 denali_dma_mask; + +static int __devinit denali_dt_probe(struct platform_device *ofdev) +{ + struct resource *denali_reg, *nand_data; + struct denali_dt *dt; + struct denali_nand_info *denali; + int ret; + const struct of_device_id *of_id; + + of_id = of_match_device(denali_nand_dt_ids, &ofdev->dev); + if (of_id) { + ofdev->id_entry = of_id->data; + } else { + pr_err("Failed to find the right device id.\n"); + return -ENOMEM; + } + + dt = devm_kzalloc(&ofdev->dev, sizeof(*dt), GFP_KERNEL); + if (!dt) + return -ENOMEM; + denali = &dt->denali; + + denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg"); + nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data"); + if (!denali_reg || !nand_data) { + dev_err(&ofdev->dev, "resources not completely defined\n"); + return -EINVAL; + } + + denali->platform = DT; + denali->dev = &ofdev->dev; + denali->irq = platform_get_irq(ofdev, 0); + if (denali->irq < 0) { + dev_err(&ofdev->dev, "no irq defined\n"); + return -ENXIO; + } + + denali->flash_reg = request_and_map(&ofdev->dev, denali_reg); + if (!denali->flash_reg) + return -ENOMEM; + + denali->flash_mem = request_and_map(&ofdev->dev, nand_data); + if (!denali->flash_mem) + return -ENOMEM; + + if (!of_property_read_u32(ofdev->dev.of_node, + "dma-mask", (u32 *)&denali_dma_mask)) { + denali->dev->dma_mask = &denali_dma_mask; + } else { + denali->dev->dma_mask = NULL; + } + + dt->clk = clk_get(&ofdev->dev, NULL); + if (IS_ERR(dt->clk)) { + dev_err(&ofdev->dev, "no clk available\n"); + return PTR_ERR(dt->clk); + } + clk_prepare_enable(dt->clk); + + ret = denali_init(denali); + if (ret) + goto out_disable_clk; + + platform_set_drvdata(ofdev, dt); + return 0; + +out_disable_clk: + clk_disable_unprepare(dt->clk); + clk_put(dt->clk); + + return ret; +} + +static int __devexit denali_dt_remove(struct platform_device *ofdev) +{ + struct denali_dt *dt = platform_get_drvdata(ofdev); + + denali_remove(&dt->denali); + clk_disable(dt->clk); + clk_put(dt->clk); + + return 0; +} + +static struct platform_driver denali_dt_driver = { + .probe = denali_dt_probe, + .remove = __devexit_p(denali_dt_remove), + .driver = { + .name = "denali-nand-dt", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(denali_nand_dt_ids), + }, +}; + +static int __init denali_init_dt(void) +{ + return platform_driver_register(&denali_dt_driver); +} +module_init(denali_init_dt); + +static void __exit denali_exit_dt(void) +{ + platform_driver_unregister(&denali_dt_driver); +} +module_exit(denali_exit_dt); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jamie Iles"); +MODULE_DESCRIPTION("DT driver for Denali NAND controller"); -- cgit v0.10.2 From 41863f730ff8aad86c038aabee1292d1b04c8876 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 4 Oct 2012 09:28:29 +0200 Subject: ARM: nomadik: switch over to using the FSMC driver The Nomadik NAND driver is really just a subset of the existing FSMC driver, so let's switch over to using that driver instead, since it handles more variants of this chip. The callbacks for setting up the chip is doing stuff now handled by the FSMC driver. Signed-off-by: Linus Walleij Acked-by: Alessandro Rubini Signed-off-by: Artem Bityutskiy diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig index 240b25e..86cfd29 100644 --- a/arch/arm/configs/nhk8815_defconfig +++ b/arch/arm/configs/nhk8815_defconfig @@ -57,7 +57,7 @@ CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ECC_SMC=y -CONFIG_MTD_NAND_NOMADIK=y +CONFIG_MTD_NAND_FSMC=y CONFIG_MTD_ONENAND=y CONFIG_MTD_ONENAND_VERIFY_WRITE=y CONFIG_MTD_ONENAND_GENERIC=y diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c index bfa1eab..a105d1b 100644 --- a/arch/arm/mach-nomadik/board-nhk8815.c +++ b/arch/arm/mach-nomadik/board-nhk8815.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,6 @@ #include #include -#include #include #include "cpu-8815.h" @@ -48,36 +48,18 @@ /* These addresses span 16MB, so use three individual pages */ static struct resource nhk8815_nand_resources[] = { { - .name = "nand_addr", - .start = NAND_IO_ADDR, - .end = NAND_IO_ADDR + 0xfff, - .flags = IORESOURCE_MEM, - }, { - .name = "nand_cmd", - .start = NAND_IO_CMD, - .end = NAND_IO_CMD + 0xfff, + .name = "nand_data", + .start = 0x40000000, + .end = 0x40000000 + SZ_16K - 1, .flags = IORESOURCE_MEM, }, { - .name = "nand_data", - .start = NAND_IO_DATA, - .end = NAND_IO_DATA + 0xfff, + .name = "fsmc_regs", + .start = NOMADIK_FSMC_BASE, + .end = NOMADIK_FSMC_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, - } + }, }; -static int nhk8815_nand_init(void) -{ - /* FSMC setup for nand chip select (8-bit nand in 8815NHK) */ - writel(0x0000000E, FSMC_PCR(0)); - writel(0x000D0A00, FSMC_PMEM(0)); - writel(0x00100A00, FSMC_PATT(0)); - - /* enable access to the chip select area */ - writel(readl(FSMC_PCR(0)) | 0x04, FSMC_PCR(0)); - - return 0; -} - /* * These partitions are the same as those used in the 2.6.20 release * shipped by the vendor; the first two partitions are mandated @@ -111,20 +93,30 @@ static struct mtd_partition nhk8815_partitions[] = { } }; -static struct nomadik_nand_platform_data nhk8815_nand_data = { - .parts = nhk8815_partitions, - .nparts = ARRAY_SIZE(nhk8815_partitions), - .options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING, - .init = nhk8815_nand_init, +static struct fsmc_nand_timings nhk8815_nand_timings = { + .thiz = 0, + .thold = 0x10, + .twait = 0x0A, + .tset = 0, +}; + +static struct fsmc_nand_platform_data nhk8815_nand_platform_data = { + .nand_timings = &nhk8815_nand_timings, + .partitions = nhk8815_partitions, + .nr_partitions = ARRAY_SIZE(nhk8815_partitions), + .width = FSMC_NAND_BW8, + .ale_off = 0x1000000, + .cle_off = 0x800000, }; static struct platform_device nhk8815_nand_device = { - .name = "nomadik_nand", - .dev = { - .platform_data = &nhk8815_nand_data, + .name = "fsmc-nand", + .id = -1, + .resource = nhk8815_nand_resources, + .num_resources = ARRAY_SIZE(nhk8815_nand_resources), + .dev = { + .platform_data = &nhk8815_nand_platform_data, }, - .resource = nhk8815_nand_resources, - .num_resources = ARRAY_SIZE(nhk8815_nand_resources), }; /* These are the partitions for the OneNand device, different from above */ diff --git a/arch/arm/mach-nomadik/include/mach/fsmc.h b/arch/arm/mach-nomadik/include/mach/fsmc.h deleted file mode 100644 index 8c2c051..0000000 --- a/arch/arm/mach-nomadik/include/mach/fsmc.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* Definitions for the Nomadik FSMC "Flexible Static Memory controller" */ - -#ifndef __ASM_ARCH_FSMC_H -#define __ASM_ARCH_FSMC_H - -#include -/* - * Register list - */ - -/* bus control reg. and bus timing reg. for CS0..CS3 */ -#define FSMC_BCR(x) (NOMADIK_FSMC_VA + (x << 3)) -#define FSMC_BTR(x) (NOMADIK_FSMC_VA + (x << 3) + 0x04) - -/* PC-card and NAND: - * PCR = control register - * PMEM = memory timing - * PATT = attribute timing - * PIO = I/O timing - * PECCR = ECC result - */ -#define FSMC_PCR(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x00) -#define FSMC_PMEM(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x08) -#define FSMC_PATT(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x0c) -#define FSMC_PIO(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x10) -#define FSMC_PECCR(x) (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x14) - -#endif /* __ASM_ARCH_FSMC_H */ diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c index 517a8ff..6b4c70f 100644 --- a/drivers/clk/clk-nomadik.c +++ b/drivers/clk/clk-nomadik.c @@ -20,6 +20,7 @@ void __init nomadik_clk_init(void) clk_register_clkdev(clk, NULL, "gpio.2"); clk_register_clkdev(clk, NULL, "gpio.3"); clk_register_clkdev(clk, NULL, "rng"); + clk_register_clkdev(clk, NULL, "fsmc-nand"); /* * The 2.4 MHz TIMCLK reference clock is active at boot time, this is -- cgit v0.10.2 From fc05d5a30dc19dd4c6d161e551719a8c597c7890 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 4 Oct 2012 09:28:49 +0200 Subject: mtd: delete nomadik_nand driver The nomadik_nand driver is really just a subset of the FSMC NAND driver, and there are no users anymore so let's delete it. Signed-off-by: Linus Walleij Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index ee803d6..a803d9b 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -526,12 +526,6 @@ config MTD_NAND_MXC This enables the driver for the NAND flash controller on the MXC processors. -config MTD_NAND_NOMADIK - tristate "ST Nomadik 8815 NAND support" - depends on ARCH_NOMADIK - help - Driver for the NAND flash controller on the Nomadik, with ECC. - config MTD_NAND_SH_FLCTL tristate "Support for NAND on Renesas SuperH FLCTL" depends on SUPERH || ARCH_SHMOBILE diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 38358c9..44fca05 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -49,7 +49,6 @@ obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o -obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o obj-$(CONFIG_MTD_NAND_RICOH) += r852.o obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c deleted file mode 100644 index 9ee0c4e..0000000 --- a/drivers/mtd/nand/nomadik_nand.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * drivers/mtd/nand/nomadik_nand.c - * - * Overview: - * Driver for on-board NAND flash on Nomadik Platforms - * - * Copyright © 2007 STMicroelectronics Pvt. Ltd. - * Author: Sachin Verma - * - * Copyright © 2009 Alessandro Rubini - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -struct nomadik_nand_host { - struct mtd_info mtd; - struct nand_chip nand; - void __iomem *data_va; - void __iomem *cmd_va; - void __iomem *addr_va; - struct nand_bbt_descr *bbt_desc; -}; - -static struct nand_ecclayout nomadik_ecc_layout = { - .eccbytes = 3 * 4, - .eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */ - 0x02, 0x03, 0x04, - 0x12, 0x13, 0x14, - 0x22, 0x23, 0x24, - 0x32, 0x33, 0x34}, - /* let's keep bytes 5,6,7 for us, just in case we change ECC algo */ - .oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} }, -}; - -static void nomadik_ecc_control(struct mtd_info *mtd, int mode) -{ - /* No need to enable hw ecc, it's on by default */ -} - -static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *nand = mtd->priv; - struct nomadik_nand_host *host = nand->priv; - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - writeb(cmd, host->cmd_va); - else - writeb(cmd, host->addr_va); -} - -static int nomadik_nand_probe(struct platform_device *pdev) -{ - struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data; - struct nomadik_nand_host *host; - struct mtd_info *mtd; - struct nand_chip *nand; - struct resource *res; - int ret = 0; - - /* Allocate memory for the device structure (and zero it) */ - host = kzalloc(sizeof(struct nomadik_nand_host), GFP_KERNEL); - if (!host) { - dev_err(&pdev->dev, "Failed to allocate device structure.\n"); - return -ENOMEM; - } - - /* Call the client's init function, if any */ - if (pdata->init) - ret = pdata->init(); - if (ret < 0) { - dev_err(&pdev->dev, "Init function failed\n"); - goto err; - } - - /* ioremap three regions */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr"); - if (!res) { - ret = -EIO; - goto err_unmap; - } - host->addr_va = ioremap(res->start, resource_size(res)); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); - if (!res) { - ret = -EIO; - goto err_unmap; - } - host->data_va = ioremap(res->start, resource_size(res)); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd"); - if (!res) { - ret = -EIO; - goto err_unmap; - } - host->cmd_va = ioremap(res->start, resource_size(res)); - - if (!host->addr_va || !host->data_va || !host->cmd_va) { - ret = -ENOMEM; - goto err_unmap; - } - - /* Link all private pointers */ - mtd = &host->mtd; - nand = &host->nand; - mtd->priv = nand; - nand->priv = host; - - host->mtd.owner = THIS_MODULE; - nand->IO_ADDR_R = host->data_va; - nand->IO_ADDR_W = host->data_va; - nand->cmd_ctrl = nomadik_cmd_ctrl; - - /* - * This stanza declares ECC_HW but uses soft routines. It's because - * HW claims to make the calculation but not the correction. However, - * I haven't managed to get the desired data out of it until now. - */ - nand->ecc.mode = NAND_ECC_SOFT; - nand->ecc.layout = &nomadik_ecc_layout; - nand->ecc.hwctl = nomadik_ecc_control; - nand->ecc.size = 512; - nand->ecc.bytes = 3; - - nand->options = pdata->options; - - /* - * Scan to find existence of the device - */ - if (nand_scan(&host->mtd, 1)) { - ret = -ENXIO; - goto err_unmap; - } - - mtd_device_register(&host->mtd, pdata->parts, pdata->nparts); - - platform_set_drvdata(pdev, host); - return 0; - - err_unmap: - if (host->cmd_va) - iounmap(host->cmd_va); - if (host->data_va) - iounmap(host->data_va); - if (host->addr_va) - iounmap(host->addr_va); - err: - kfree(host); - return ret; -} - -/* - * Clean up routine - */ -static int nomadik_nand_remove(struct platform_device *pdev) -{ - struct nomadik_nand_host *host = platform_get_drvdata(pdev); - struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data; - - if (pdata->exit) - pdata->exit(); - - if (host) { - nand_release(&host->mtd); - iounmap(host->cmd_va); - iounmap(host->data_va); - iounmap(host->addr_va); - kfree(host); - } - return 0; -} - -static int nomadik_nand_suspend(struct device *dev) -{ - struct nomadik_nand_host *host = dev_get_drvdata(dev); - int ret = 0; - if (host) - ret = mtd_suspend(&host->mtd); - return ret; -} - -static int nomadik_nand_resume(struct device *dev) -{ - struct nomadik_nand_host *host = dev_get_drvdata(dev); - if (host) - mtd_resume(&host->mtd); - return 0; -} - -static const struct dev_pm_ops nomadik_nand_pm_ops = { - .suspend = nomadik_nand_suspend, - .resume = nomadik_nand_resume, -}; - -static struct platform_driver nomadik_nand_driver = { - .probe = nomadik_nand_probe, - .remove = nomadik_nand_remove, - .driver = { - .owner = THIS_MODULE, - .name = "nomadik_nand", - .pm = &nomadik_nand_pm_ops, - }, -}; - -module_platform_driver(nomadik_nand_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("ST Microelectronics (sachin.verma@st.com)"); -MODULE_DESCRIPTION("NAND driver for Nomadik Platform"); diff --git a/include/linux/platform_data/mtd-nomadik-nand.h b/include/linux/platform_data/mtd-nomadik-nand.h deleted file mode 100644 index c3c8254..0000000 --- a/include/linux/platform_data/mtd-nomadik-nand.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __ASM_ARCH_NAND_H -#define __ASM_ARCH_NAND_H - -struct nomadik_nand_platform_data { - struct mtd_partition *parts; - int nparts; - int options; - int (*init) (void); - int (*exit) (void); -}; - -#define NAND_IO_DATA 0x40000000 -#define NAND_IO_CMD 0x40800000 -#define NAND_IO_ADDR 0x41000000 - -#endif /* __ASM_ARCH_NAND_H */ -- cgit v0.10.2 From 6d7b42a447f92eb3e7e410bbf62042693eb040f7 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Thu, 4 Oct 2012 15:14:16 +0200 Subject: mtd: fsmc_nand: pass the ale and cmd resource via resource Do not use the platform_data to pass resource and be smart in the drivers. Just pass it via resource Switch to devm_request_and_ioremap at the sametime Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Linus Walleij Reviewed-By: Vipin Kumar Signed-off-by: Artem Bityutskiy diff --git a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt index e2c663b..e3ea32e 100644 --- a/Documentation/devicetree/bindings/mtd/fsmc-nand.txt +++ b/Documentation/devicetree/bindings/mtd/fsmc-nand.txt @@ -3,9 +3,7 @@ Required properties: - compatible : "st,spear600-fsmc-nand" - reg : Address range of the mtd chip -- reg-names: Should contain the reg names "fsmc_regs" and "nand_data" -- st,ale-off : Chip specific offset to ALE -- st,cle-off : Chip specific offset to CLE +- reg-names: Should contain the reg names "fsmc_regs", "nand_data", "nand_addr" and "nand_cmd" Optional properties: - bank-width : Width (in bytes) of the device. If not present, the width @@ -19,10 +17,10 @@ Example: #address-cells = <1>; #size-cells = <1>; reg = <0xd1800000 0x1000 /* FSMC Register */ - 0xd2000000 0x4000>; /* NAND Base */ - reg-names = "fsmc_regs", "nand_data"; - st,ale-off = <0x20000>; - st,cle-off = <0x10000>; + 0xd2000000 0x0010 /* NAND Base DATA */ + 0xd2020000 0x0010 /* NAND Base ADDR */ + 0xd2010000 0x0010>; /* NAND Base CMD */ + reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd"; bank-width = <1>; nand-skip-bbtscan; diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi index f7b84ac..14a6d15 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -104,15 +104,15 @@ compatible = "st,spear600-fsmc-nand"; #address-cells = <1>; #size-cells = <1>; - reg = <0xb0000000 0x1000 /* FSMC Register */ - 0xb0800000 0x0010>; /* NAND Base */ - reg-names = "fsmc_regs", "nand_data"; + reg = <0xb0000000 0x1000 /* FSMC Register*/ + 0xb0800000 0x0010 /* NAND Base DATA */ + 0xb0820000 0x0010 /* NAND Base ADDR */ + 0xb0810000 0x0010>; /* NAND Base CMD */ + reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd"; interrupts = <0 20 0x4 0 21 0x4 0 22 0x4 0 23 0x4>; - st,ale-off = <0x20000>; - st,cle-off = <0x10000>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear300.dtsi b/arch/arm/boot/dts/spear300.dtsi index ed3627c..bc43638 100644 --- a/arch/arm/boot/dts/spear300.dtsi +++ b/arch/arm/boot/dts/spear300.dtsi @@ -38,10 +38,10 @@ #address-cells = <1>; #size-cells = <1>; reg = <0x94000000 0x1000 /* FSMC Register */ - 0x80000000 0x0010>; /* NAND Base */ - reg-names = "fsmc_regs", "nand_data"; - st,ale-off = <0x20000>; - st,cle-off = <0x10000>; + 0x80000000 0x0010 /* NAND Base DATA */ + 0x80020000 0x0010 /* NAND Base ADDR */ + 0x80010000 0x0010>; /* NAND Base CMD */ + reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear310.dtsi b/arch/arm/boot/dts/spear310.dtsi index 62fc4fb..7840e52 100644 --- a/arch/arm/boot/dts/spear310.dtsi +++ b/arch/arm/boot/dts/spear310.dtsi @@ -32,10 +32,10 @@ #address-cells = <1>; #size-cells = <1>; reg = <0x44000000 0x1000 /* FSMC Register */ - 0x40000000 0x0010>; /* NAND Base */ - reg-names = "fsmc_regs", "nand_data"; - st,ale-off = <0x10000>; - st,cle-off = <0x20000>; + 0x40000000 0x0010 /* NAND Base DATA */ + 0x40020000 0x0010 /* NAND Base ADDR */ + 0x40010000 0x0010>; /* NAND Base CMD */ + reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear320.dtsi b/arch/arm/boot/dts/spear320.dtsi index 1f49d69..5ad8206 100644 --- a/arch/arm/boot/dts/spear320.dtsi +++ b/arch/arm/boot/dts/spear320.dtsi @@ -38,10 +38,10 @@ #address-cells = <1>; #size-cells = <1>; reg = <0x4c000000 0x1000 /* FSMC Register */ - 0x50000000 0x0010>; /* NAND Base */ - reg-names = "fsmc_regs", "nand_data"; - st,ale-off = <0x20000>; - st,cle-off = <0x10000>; + 0x50000000 0x0010 /* NAND Base DATA */ + 0x50020000 0x0010 /* NAND Base ADDR */ + 0x50010000 0x0010>; /* NAND Base CMD */ + reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi index a3c36e4..4ecc66f 100644 --- a/arch/arm/boot/dts/spear600.dtsi +++ b/arch/arm/boot/dts/spear600.dtsi @@ -67,10 +67,10 @@ #address-cells = <1>; #size-cells = <1>; reg = <0xd1800000 0x1000 /* FSMC Register */ - 0xd2000000 0x4000>; /* NAND Base */ - reg-names = "fsmc_regs", "nand_data"; - st,ale-off = <0x20000>; - st,cle-off = <0x10000>; + 0xd2000000 0x0010 /* NAND Base DATA */ + 0xd2020000 0x0010 /* NAND Base ADDR */ + 0xd2010000 0x0010>; /* NAND Base CMD */ + reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd"; status = "disabled"; }; diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index b8efac4..f642a15 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -252,6 +252,18 @@ static struct resource rtc_resources[] = { */ static struct resource fsmc_resources[] = { { + .name = "nand_addr", + .start = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_ALE, + .end = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_ALE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "nand_cmd", + .start = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_CLE, + .end = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_CLE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { .name = "nand_data", .start = U300_NAND_CS0_PHYS_BASE, .end = U300_NAND_CS0_PHYS_BASE + SZ_16K - 1, @@ -1496,8 +1508,6 @@ static struct fsmc_nand_platform_data nand_platform_data = { .nr_partitions = ARRAY_SIZE(u300_partitions), .options = NAND_SKIP_BBTSCAN, .width = FSMC_NAND_BW8, - .ale_off = PLAT_NAND_ALE, - .cle_off = PLAT_NAND_CLE, }; static struct platform_device nand_device = { diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 38d2624..cb86450 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -876,8 +876,6 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, return -EINVAL; } } - of_property_read_u32(np, "st,ale-off", &pdata->ale_off); - of_property_read_u32(np, "st,cle-off", &pdata->cle_off); if (of_get_property(np, "nand-skip-bbtscan", NULL)) pdata->options = NAND_SKIP_BBTSCAN; @@ -935,41 +933,28 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (!res) return -EINVAL; - if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - pdev->name)) { - dev_err(&pdev->dev, "Failed to get memory data resourse\n"); - return -ENOENT; - } - - host->data_pa = (dma_addr_t)res->start; - host->data_va = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); + host->data_va = devm_request_and_ioremap(&pdev->dev, res); if (!host->data_va) { dev_err(&pdev->dev, "data ioremap failed\n"); return -ENOMEM; } + host->data_pa = (dma_addr_t)res->start; - if (!devm_request_mem_region(&pdev->dev, res->start + pdata->ale_off, - resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "Failed to get memory ale resourse\n"); - return -ENOENT; - } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr"); + if (!res) + return -EINVAL; - host->addr_va = devm_ioremap(&pdev->dev, res->start + pdata->ale_off, - resource_size(res)); + host->addr_va = devm_request_and_ioremap(&pdev->dev, res); if (!host->addr_va) { dev_err(&pdev->dev, "ale ioremap failed\n"); return -ENOMEM; } - if (!devm_request_mem_region(&pdev->dev, res->start + pdata->cle_off, - resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "Failed to get memory cle resourse\n"); - return -ENOENT; - } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd"); + if (!res) + return -EINVAL; - host->cmd_va = devm_ioremap(&pdev->dev, res->start + pdata->cle_off, - resource_size(res)); + host->cmd_va = devm_request_and_ioremap(&pdev->dev, res); if (!host->cmd_va) { dev_err(&pdev->dev, "ale ioremap failed\n"); return -ENOMEM; @@ -979,14 +964,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (!res) return -EINVAL; - if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - pdev->name)) { - dev_err(&pdev->dev, "Failed to get memory regs resourse\n"); - return -ENOENT; - } - - host->regs_va = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); + host->regs_va = devm_request_and_ioremap(&pdev->dev, res); if (!host->regs_va) { dev_err(&pdev->dev, "regs ioremap failed\n"); return -ENOMEM; diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h index b200292..d6ed61e 100644 --- a/include/linux/mtd/fsmc.h +++ b/include/linux/mtd/fsmc.h @@ -155,9 +155,6 @@ struct fsmc_nand_platform_data { unsigned int width; unsigned int bank; - /* CLE, ALE offsets */ - unsigned int cle_off; - unsigned int ale_off; enum access_mode mode; void (*select_bank)(uint32_t bank, uint32_t busw); -- cgit v0.10.2 From db6364a650edcb076786092c7f85f1e1cdae8b20 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 12 Oct 2012 00:23:02 +0200 Subject: ARM: nomadik: fixup some FSMC merge problems Due to a clash between refactoring and due to loss of a header file that remained in my working tree the Nomadik stopped compiling after switching to the FSMC driver. This patch fixes it up. Cc: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Linus Walleij Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Artem Bityutskiy diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c index a105d1b..3f97ef4 100644 --- a/arch/arm/mach-nomadik/board-nhk8815.c +++ b/arch/arm/mach-nomadik/board-nhk8815.c @@ -37,14 +37,15 @@ #include #include -#include - #include "cpu-8815.h" /* Initial value for SRC control register: all timers use MXTAL/8 source */ #define SRC_CR_INIT_MASK 0x00007fff #define SRC_CR_INIT_VAL 0x2aaa8000 +#define ALE_OFF 0x1000000 +#define CLE_OFF 0x800000 + /* These addresses span 16MB, so use three individual pages */ static struct resource nhk8815_nand_resources[] = { { @@ -53,6 +54,16 @@ static struct resource nhk8815_nand_resources[] = { .end = 0x40000000 + SZ_16K - 1, .flags = IORESOURCE_MEM, }, { + .name = "nand_addr", + .start = 0x40000000 + ALE_OFF, + .end = 0x40000000 +ALE_OFF + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "nand_cmd", + .start = 0x40000000 + CLE_OFF, + .end = 0x40000000 + CLE_OFF + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, { .name = "fsmc_regs", .start = NOMADIK_FSMC_BASE, .end = NOMADIK_FSMC_BASE + SZ_4K - 1, @@ -105,8 +116,6 @@ static struct fsmc_nand_platform_data nhk8815_nand_platform_data = { .partitions = nhk8815_partitions, .nr_partitions = ARRAY_SIZE(nhk8815_partitions), .width = FSMC_NAND_BW8, - .ale_off = 0x1000000, - .cle_off = 0x800000, }; static struct platform_device nhk8815_nand_device = { @@ -171,6 +180,10 @@ static struct platform_device nhk8815_onenand_device = { .num_resources = ARRAY_SIZE(nhk8815_onenand_resource), }; +/* bus control reg. and bus timing reg. for CS0..CS3 */ +#define FSMC_BCR(x) (NOMADIK_FSMC_VA + (x << 3)) +#define FSMC_BTR(x) (NOMADIK_FSMC_VA + (x << 3) + 0x04) + static void __init nhk8815_onenand_init(void) { #ifdef CONFIG_MTD_ONENAND -- cgit v0.10.2 From 605add7db6e84ff78f7ca96541c0880f0166e387 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 9 Oct 2012 16:14:43 +0530 Subject: mtd: fsmc_nand: change the type for regs to void __iomem * Signed-off-by: Vipin Kumar Reviewed-by: Linus Walleij Reviewed-by: Viresh Kumar Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index cb86450..a5bc3d5 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -361,7 +361,7 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) struct nand_chip *this = mtd->priv; struct fsmc_nand_data *host = container_of(mtd, struct fsmc_nand_data, mtd); - void *__iomem *regs = host->regs_va; + void __iomem *regs = host->regs_va; unsigned int bank = host->bank; if (ctrl & NAND_CTRL_CHANGE) { -- cgit v0.10.2 From 928aa2aeb7269292ca1e3d0e5e2e5d08af13da3d Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 9 Oct 2012 16:14:48 +0530 Subject: mtd: fsmc_nand: modify the wait to uninterruptible Interruptible wait caused trouble in fsmc hardware state machine if the application was killed abruptly. To make fsmc operation safe turn wait in to un-interruptible. Signed-off-by: Vipin Kumar Reviewed-by: Linus Walleij Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index a5bc3d5..82c0371 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -601,7 +601,7 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len, dma_async_issue_pending(chan); ret = - wait_for_completion_interruptible_timeout(&host->dma_access_complete, + wait_for_completion_timeout(&host->dma_access_complete, msecs_to_jiffies(3000)); if (ret <= 0) { chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); -- cgit v0.10.2 From a4742d515071b8b7889a6b608da48d36c1dfcc71 Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 9 Oct 2012 16:14:50 +0530 Subject: mtd: fsmc_nand: use relaxed variants of io accessors Use relaxed variants of readl/writel accessors. readl/writel io accessors use explicit dsb instruction which causes stalls in the processor core resulting several cycles of delay for each access Use relaxed variants where ever possible. This also results in an improved read/write performance. Signed-off-by: Vipin Kumar Reviewed-by: Linus Walleij Reviewed-by: Viresh Kumar Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 82c0371..6b59223 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -383,13 +383,13 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) pc |= FSMC_ENABLE; else pc &= ~FSMC_ENABLE; - writel(pc, FSMC_NAND_REG(regs, bank, PC)); + writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC)); } mb(); if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); + writeb_relaxed(cmd, this->IO_ADDR_W); } /* @@ -426,14 +426,18 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank, tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT; if (busw) - writel(value | FSMC_DEVWID_16, FSMC_NAND_REG(regs, bank, PC)); + writel_relaxed(value | FSMC_DEVWID_16, + FSMC_NAND_REG(regs, bank, PC)); else - writel(value | FSMC_DEVWID_8, FSMC_NAND_REG(regs, bank, PC)); + writel_relaxed(value | FSMC_DEVWID_8, + FSMC_NAND_REG(regs, bank, PC)); - writel(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar, + writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar, FSMC_NAND_REG(regs, bank, PC)); - writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, COMM)); - writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, ATTRIB)); + writel_relaxed(thiz | thold | twait | tset, + FSMC_NAND_REG(regs, bank, COMM)); + writel_relaxed(thiz | thold | twait | tset, + FSMC_NAND_REG(regs, bank, ATTRIB)); } /* @@ -446,11 +450,11 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) void __iomem *regs = host->regs_va; uint32_t bank = host->bank; - writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256, + writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256, FSMC_NAND_REG(regs, bank, PC)); - writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN, + writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN, FSMC_NAND_REG(regs, bank, PC)); - writel(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN, + writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN, FSMC_NAND_REG(regs, bank, PC)); } @@ -470,7 +474,7 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT; do { - if (readl(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY) + if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY) break; else cond_resched(); @@ -481,25 +485,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, return -ETIMEDOUT; } - ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1)); + ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1)); ecc[0] = (uint8_t) (ecc_tmp >> 0); ecc[1] = (uint8_t) (ecc_tmp >> 8); ecc[2] = (uint8_t) (ecc_tmp >> 16); ecc[3] = (uint8_t) (ecc_tmp >> 24); - ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC2)); + ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2)); ecc[4] = (uint8_t) (ecc_tmp >> 0); ecc[5] = (uint8_t) (ecc_tmp >> 8); ecc[6] = (uint8_t) (ecc_tmp >> 16); ecc[7] = (uint8_t) (ecc_tmp >> 24); - ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC3)); + ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3)); ecc[8] = (uint8_t) (ecc_tmp >> 0); ecc[9] = (uint8_t) (ecc_tmp >> 8); ecc[10] = (uint8_t) (ecc_tmp >> 16); ecc[11] = (uint8_t) (ecc_tmp >> 24); - ecc_tmp = readl(FSMC_NAND_REG(regs, bank, STS)); + ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS)); ecc[12] = (uint8_t) (ecc_tmp >> 16); return 0; @@ -519,7 +523,7 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, uint32_t bank = host->bank; uint32_t ecc_tmp; - ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1)); + ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1)); ecc[0] = (uint8_t) (ecc_tmp >> 0); ecc[1] = (uint8_t) (ecc_tmp >> 8); ecc[2] = (uint8_t) (ecc_tmp >> 16); @@ -628,10 +632,10 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) uint32_t *p = (uint32_t *)buf; len = len >> 2; for (i = 0; i < len; i++) - writel(p[i], chip->IO_ADDR_W); + writel_relaxed(p[i], chip->IO_ADDR_W); } else { for (i = 0; i < len; i++) - writeb(buf[i], chip->IO_ADDR_W); + writeb_relaxed(buf[i], chip->IO_ADDR_W); } } @@ -651,10 +655,10 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) uint32_t *p = (uint32_t *)buf; len = len >> 2; for (i = 0; i < len; i++) - p[i] = readl(chip->IO_ADDR_R); + p[i] = readl_relaxed(chip->IO_ADDR_R); } else { for (i = 0; i < len; i++) - buf[i] = readb(chip->IO_ADDR_R); + buf[i] = readb_relaxed(chip->IO_ADDR_R); } } @@ -783,7 +787,7 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, uint32_t num_err, i; uint32_t ecc1, ecc2, ecc3, ecc4; - num_err = (readl(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF; + num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF; /* no bit flipping */ if (likely(num_err == 0)) @@ -826,10 +830,10 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, * uint64_t array and error offset indexes are populated in err_idx * array */ - ecc1 = readl(FSMC_NAND_REG(regs, bank, ECC1)); - ecc2 = readl(FSMC_NAND_REG(regs, bank, ECC2)); - ecc3 = readl(FSMC_NAND_REG(regs, bank, ECC3)); - ecc4 = readl(FSMC_NAND_REG(regs, bank, STS)); + ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1)); + ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2)); + ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3)); + ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS)); err_idx[0] = (ecc1 >> 0) & 0x1FFF; err_idx[1] = (ecc1 >> 13) & 0x1FFF; -- cgit v0.10.2 From 2f25ae97fe4b424d88d765797c46456c7c0f1bae Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Tue, 9 Oct 2012 16:14:53 +0530 Subject: mtd: nand: Increase the ecc placement locations to 640 Few devices like H27UBG8T2CTR have a writesize/oobsize of 8KB/640B. This means that the maximum oobsize has gone up to 640 bytes and consequently the maximum ecc placement locations have also gone up to 640. Signed-off-by: Vipin Kumar Signed-off-by: Artem Bityutskiy diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 81d61e7..f9ac289 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -98,7 +98,7 @@ struct mtd_oob_ops { }; #define MTD_MAX_OOBFREE_ENTRIES_LARGE 32 -#define MTD_MAX_ECCPOS_ENTRIES_LARGE 448 +#define MTD_MAX_ECCPOS_ENTRIES_LARGE 640 /* * Internal ECC layout control structure. For historical reasons, there is a * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained -- cgit v0.10.2 From a90019e25e0caed04d3704235b5ea984aaa28da8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 10 Oct 2012 19:39:59 +0100 Subject: mtd: spear_smi: use module_platform_driver macro This patch removes some code duplication by using module_platform_driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index dcc3c95..39e9567 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -1094,18 +1094,7 @@ static struct platform_driver spear_smi_driver = { .probe = spear_smi_probe, .remove = __devexit_p(spear_smi_remove), }; - -static int spear_smi_init(void) -{ - return platform_driver_register(&spear_smi_driver); -} -module_init(spear_smi_init); - -static void spear_smi_exit(void) -{ - platform_driver_unregister(&spear_smi_driver); -} -module_exit(spear_smi_exit); +module_platform_driver(spear_smi_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ashish Priyadarshi, Shiraz Hashim "); -- cgit v0.10.2 From 600ed67562e5349be92867825ab5505526eac139 Mon Sep 17 00:00:00 2001 From: Vikram Narayanan Date: Wed, 10 Oct 2012 23:04:41 +0530 Subject: mtd: tests: mtd_nandbiterrs: replace msg macro with pr_{info,err} Use pr_fmt instead of msg macro Signed-off-by: Vikram Narayanan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/tests/mtd_nandbiterrs.c b/drivers/mtd/tests/mtd_nandbiterrs.c index cc8d62c..207bf9a 100644 --- a/drivers/mtd/tests/mtd_nandbiterrs.c +++ b/drivers/mtd/tests/mtd_nandbiterrs.c @@ -39,6 +39,9 @@ * this program; see the file COPYING. If not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -47,8 +50,6 @@ #include #include -#define msg(FMT, VA...) pr_info("mtd_nandbiterrs: "FMT, ##VA) - static int dev; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -103,7 +104,7 @@ static int erase_block(void) struct erase_info ei; loff_t addr = eraseblock * mtd->erasesize; - msg("erase_block\n"); + pr_info("erase_block\n"); memset(&ei, 0, sizeof(struct erase_info)); ei.mtd = mtd; @@ -112,7 +113,7 @@ static int erase_block(void) err = mtd_erase(mtd, &ei); if (err || ei.state == MTD_ERASE_FAILED) { - msg("error %d while erasing\n", err); + pr_err("error %d while erasing\n", err); if (!err) err = -EIO; return err; @@ -128,11 +129,11 @@ static int write_page(int log) size_t written; if (log) - msg("write_page\n"); + pr_info("write_page\n"); err = mtd_write(mtd, offset, mtd->writesize, &written, wbuffer); if (err || written != mtd->writesize) { - msg("error: write failed at %#llx\n", (long long)offset); + pr_err("error: write failed at %#llx\n", (long long)offset); if (!err) err = -EIO; } @@ -147,7 +148,7 @@ static int rewrite_page(int log) struct mtd_oob_ops ops; if (log) - msg("rewrite page\n"); + pr_info("rewrite page\n"); ops.mode = MTD_OPS_RAW; /* No ECC */ ops.len = mtd->writesize; @@ -160,7 +161,7 @@ static int rewrite_page(int log) err = mtd_write_oob(mtd, offset, &ops); if (err || ops.retlen != mtd->writesize) { - msg("error: write_oob failed (%d)\n", err); + pr_err("error: write_oob failed (%d)\n", err); if (!err) err = -EIO; } @@ -177,7 +178,7 @@ static int read_page(int log) struct mtd_ecc_stats oldstats; if (log) - msg("read_page\n"); + pr_info("read_page\n"); /* Saving last mtd stats */ memcpy(&oldstats, &mtd->ecc_stats, sizeof(oldstats)); @@ -187,7 +188,7 @@ static int read_page(int log) err = mtd->ecc_stats.corrected - oldstats.corrected; if (err < 0 || read != mtd->writesize) { - msg("error: read failed at %#llx\n", (long long)offset); + pr_err("error: read failed at %#llx\n", (long long)offset); if (err >= 0) err = -EIO; } @@ -201,11 +202,11 @@ static int verify_page(int log) unsigned i, errs = 0; if (log) - msg("verify_page\n"); + pr_info("verify_page\n"); for (i = 0; i < mtd->writesize; i++) { if (rbuffer[i] != hash(i+seed)) { - msg("Error: page offset %u, expected %02x, got %02x\n", + pr_err("Error: page offset %u, expected %02x, got %02x\n", i, hash(i+seed), rbuffer[i]); errs++; } @@ -230,13 +231,13 @@ static int insert_biterror(unsigned byte) for (bit = 7; bit >= 0; bit--) { if (CBIT(wbuffer[byte], bit)) { BCLR(wbuffer[byte], bit); - msg("Inserted biterror @ %u/%u\n", byte, bit); + pr_info("Inserted biterror @ %u/%u\n", byte, bit); return 0; } } byte++; } - msg("biterror: Failed to find a '1' bit\n"); + pr_err("biterror: Failed to find a '1' bit\n"); return -EIO; } @@ -248,7 +249,7 @@ static int incremental_errors_test(void) unsigned i; unsigned errs_per_subpage = 0; - msg("incremental biterrors test\n"); + pr_info("incremental biterrors test\n"); for (i = 0; i < mtd->writesize; i++) wbuffer[i] = hash(i+seed); @@ -265,9 +266,9 @@ static int incremental_errors_test(void) err = read_page(1); if (err > 0) - msg("Read reported %d corrected bit errors\n", err); + pr_info("Read reported %d corrected bit errors\n", err); if (err < 0) { - msg("After %d biterrors per subpage, read reported error %d\n", + pr_err("After %d biterrors per subpage, read reported error %d\n", errs_per_subpage, err); err = 0; goto exit; @@ -275,11 +276,11 @@ static int incremental_errors_test(void) err = verify_page(1); if (err) { - msg("ECC failure, read data is incorrect despite read success\n"); + pr_err("ECC failure, read data is incorrect despite read success\n"); goto exit; } - msg("Successfully corrected %d bit errors per subpage\n", + pr_info("Successfully corrected %d bit errors per subpage\n", errs_per_subpage); for (i = 0; i < subcount; i++) { @@ -311,7 +312,7 @@ static int overwrite_test(void) memset(bitstats, 0, sizeof(bitstats)); - msg("overwrite biterrors test\n"); + pr_info("overwrite biterrors test\n"); for (i = 0; i < mtd->writesize; i++) wbuffer[i] = hash(i+seed); @@ -329,18 +330,18 @@ static int overwrite_test(void) err = read_page(0); if (err >= 0) { if (err >= MAXBITS) { - msg("Implausible number of bit errors corrected\n"); + pr_info("Implausible number of bit errors corrected\n"); err = -EIO; break; } bitstats[err]++; if (err > max_corrected) { max_corrected = err; - msg("Read reported %d corrected bit errors\n", + pr_info("Read reported %d corrected bit errors\n", err); } } else { /* err < 0 */ - msg("Read reported error %d\n", err); + pr_info("Read reported error %d\n", err); err = 0; break; } @@ -348,7 +349,7 @@ static int overwrite_test(void) err = verify_page(0); if (err) { bitstats[max_corrected] = opno; - msg("ECC failure, read data is incorrect despite read success\n"); + pr_info("ECC failure, read data is incorrect despite read success\n"); break; } @@ -357,9 +358,9 @@ static int overwrite_test(void) /* At this point bitstats[0] contains the number of ops with no bit * errors, bitstats[1] the number of ops with 1 bit error, etc. */ - msg("Bit error histogram (%d operations total):\n", opno); + pr_info("Bit error histogram (%d operations total):\n", opno); for (i = 0; i < max_corrected; i++) - msg("Page reads with %3d corrected bit errors: %d\n", + pr_info("Page reads with %3d corrected bit errors: %d\n", i, bitstats[i]); exit: @@ -370,36 +371,36 @@ static int __init mtd_nandbiterrs_init(void) { int err = 0; - msg("\n"); - msg("==================================================\n"); - msg("MTD device: %d\n", dev); + printk("\n"); + printk(KERN_INFO "==================================================\n"); + pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); - msg("error: cannot get MTD device\n"); + pr_err("error: cannot get MTD device\n"); goto exit_mtddev; } if (mtd->type != MTD_NANDFLASH) { - msg("this test requires NAND flash\n"); + pr_info("this test requires NAND flash\n"); err = -ENODEV; goto exit_nand; } - msg("MTD device size %llu, eraseblock=%u, page=%u, oob=%u\n", + pr_info("MTD device size %llu, eraseblock=%u, page=%u, oob=%u\n", (unsigned long long)mtd->size, mtd->erasesize, mtd->writesize, mtd->oobsize); subsize = mtd->writesize >> mtd->subpage_sft; subcount = mtd->writesize / subsize; - msg("Device uses %d subpages of %d bytes\n", subcount, subsize); + pr_info("Device uses %d subpages of %d bytes\n", subcount, subsize); offset = page_offset * mtd->writesize; eraseblock = mtd_div_by_eb(offset, mtd); - msg("Using page=%u, offset=%llu, eraseblock=%u\n", + pr_info("Using page=%u, offset=%llu, eraseblock=%u\n", page_offset, offset, eraseblock); wbuffer = kmalloc(mtd->writesize, GFP_KERNEL); @@ -432,8 +433,8 @@ static int __init mtd_nandbiterrs_init(void) goto exit_error; err = -EIO; - msg("finished successfully.\n"); - msg("==================================================\n"); + pr_info("finished successfully.\n"); + printk(KERN_INFO "==================================================\n"); exit_error: kfree(rbuffer); -- cgit v0.10.2 From b6489d9706ca6cb42892571ac82b71ad92675036 Mon Sep 17 00:00:00 2001 From: Vikram Narayanan Date: Wed, 10 Oct 2012 23:07:19 +0530 Subject: mtd: tests: mtd_nandecctest: Use pr_fmt macro Use KBUILD_MODNAME instead of hardcoding the filename Signed-off-by: Vikram Narayanan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c index b437fa4..1eee264 100644 --- a/drivers/mtd/tests/mtd_nandecctest.c +++ b/drivers/mtd/tests/mtd_nandecctest.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -264,13 +266,13 @@ static int nand_ecc_test_run(const size_t size) correct_data, size); if (err) { - pr_err("mtd_nandecctest: not ok - %s-%zd\n", + pr_err("not ok - %s-%zd\n", nand_ecc_test[i].name, size); dump_data_ecc(error_data, error_ecc, correct_data, correct_ecc, size); break; } - pr_info("mtd_nandecctest: ok - %s-%zd\n", + pr_info("ok - %s-%zd\n", nand_ecc_test[i].name, size); } error: -- cgit v0.10.2 From bb9984191ef9ba18a80d96c07919b782bdb65278 Mon Sep 17 00:00:00 2001 From: Vikram Narayanan Date: Wed, 10 Oct 2012 23:07:40 +0530 Subject: mtd: tests: mtd_pagetest: Replace printk with pr_{info,crit,err} Use pr_fmt instead of PRINT_PREF macro Signed-off-by: Vikram Narayanan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c index 252ddb0..3ba2a77 100644 --- a/drivers/mtd/tests/mtd_pagetest.c +++ b/drivers/mtd/tests/mtd_pagetest.c @@ -19,6 +19,8 @@ * Author: Adrian Hunter */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -28,8 +30,6 @@ #include #include -#define PRINT_PREF KERN_INFO "mtd_pagetest: " - static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -79,12 +79,12 @@ static int erase_eraseblock(int ebnum) err = mtd_erase(mtd, &ei); if (err) { - printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + pr_err("error %d while erasing EB %d\n", err, ebnum); return err; } if (ei.state == MTD_ERASE_FAILED) { - printk(PRINT_PREF "some erase error occurred at EB %d\n", + pr_err("some erase error occurred at EB %d\n", ebnum); return -EIO; } @@ -102,7 +102,7 @@ static int write_eraseblock(int ebnum) cond_resched(); err = mtd_write(mtd, addr, mtd->erasesize, &written, writebuf); if (err || written != mtd->erasesize) - printk(PRINT_PREF "error: write failed at %#llx\n", + pr_err("error: write failed at %#llx\n", (long long)addr); return err; @@ -131,7 +131,7 @@ static int verify_eraseblock(int ebnum) if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr0); return err; } @@ -139,7 +139,7 @@ static int verify_eraseblock(int ebnum) if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)(addrn - bufsize)); return err; } @@ -148,12 +148,12 @@ static int verify_eraseblock(int ebnum) if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr); break; } if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) { - printk(PRINT_PREF "error: verify failed at %#llx\n", + pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; } @@ -166,7 +166,7 @@ static int verify_eraseblock(int ebnum) if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr0); return err; } @@ -174,7 +174,7 @@ static int verify_eraseblock(int ebnum) if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)(addrn - bufsize)); return err; } @@ -183,14 +183,14 @@ static int verify_eraseblock(int ebnum) if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr); return err; } memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize); set_random_data(boundary + pgsize, pgsize); if (memcmp(twopages, boundary, bufsize)) { - printk(PRINT_PREF "error: verify failed at %#llx\n", + pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; } @@ -206,10 +206,10 @@ static int crosstest(void) loff_t addr, addr0, addrn; unsigned char *pp1, *pp2, *pp3, *pp4; - printk(PRINT_PREF "crosstest\n"); + pr_info("crosstest\n"); pp1 = kmalloc(pgsize * 4, GFP_KERNEL); if (!pp1) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); return -ENOMEM; } pp2 = pp1 + pgsize; @@ -231,7 +231,7 @@ static int crosstest(void) if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr); kfree(pp1); return err; @@ -243,7 +243,7 @@ static int crosstest(void) if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr); kfree(pp1); return err; @@ -251,12 +251,12 @@ static int crosstest(void) /* Read first page to pp2 */ addr = addr0; - printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); + pr_info("reading page at %#llx\n", (long long)addr); err = mtd_read(mtd, addr, pgsize, &read, pp2); if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr); kfree(pp1); return err; @@ -264,12 +264,12 @@ static int crosstest(void) /* Read last page to pp3 */ addr = addrn - pgsize; - printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); + pr_info("reading page at %#llx\n", (long long)addr); err = mtd_read(mtd, addr, pgsize, &read, pp3); if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr); kfree(pp1); return err; @@ -277,25 +277,25 @@ static int crosstest(void) /* Read first page again to pp4 */ addr = addr0; - printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); + pr_info("reading page at %#llx\n", (long long)addr); err = mtd_read(mtd, addr, pgsize, &read, pp4); if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr); kfree(pp1); return err; } /* pp2 and pp4 should be the same */ - printk(PRINT_PREF "verifying pages read at %#llx match\n", + pr_info("verifying pages read at %#llx match\n", (long long)addr0); if (memcmp(pp2, pp4, pgsize)) { - printk(PRINT_PREF "verify failed!\n"); + pr_err("verify failed!\n"); errcnt += 1; } else if (!err) - printk(PRINT_PREF "crosstest ok\n"); + pr_info("crosstest ok\n"); kfree(pp1); return err; } @@ -307,7 +307,7 @@ static int erasecrosstest(void) loff_t addr0; char *readbuf = twopages; - printk(PRINT_PREF "erasecrosstest\n"); + pr_info("erasecrosstest\n"); ebnum = 0; addr0 = 0; @@ -320,79 +320,79 @@ static int erasecrosstest(void) while (ebnum2 && bbt[ebnum2]) ebnum2 -= 1; - printk(PRINT_PREF "erasing block %d\n", ebnum); + pr_info("erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; - printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); + pr_info("writing 1st page of block %d\n", ebnum); set_random_data(writebuf, pgsize); strcpy(writebuf, "There is no data like this!"); err = mtd_write(mtd, addr0, pgsize, &written, writebuf); if (err || written != pgsize) { - printk(PRINT_PREF "error: write failed at %#llx\n", + pr_info("error: write failed at %#llx\n", (long long)addr0); return err ? err : -1; } - printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); + pr_info("reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtd_read(mtd, addr0, pgsize, &read, readbuf); if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr0); return err ? err : -1; } - printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum); + pr_info("verifying 1st page of block %d\n", ebnum); if (memcmp(writebuf, readbuf, pgsize)) { - printk(PRINT_PREF "verify failed!\n"); + pr_err("verify failed!\n"); errcnt += 1; return -1; } - printk(PRINT_PREF "erasing block %d\n", ebnum); + pr_info("erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; - printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); + pr_info("writing 1st page of block %d\n", ebnum); set_random_data(writebuf, pgsize); strcpy(writebuf, "There is no data like this!"); err = mtd_write(mtd, addr0, pgsize, &written, writebuf); if (err || written != pgsize) { - printk(PRINT_PREF "error: write failed at %#llx\n", + pr_err("error: write failed at %#llx\n", (long long)addr0); return err ? err : -1; } - printk(PRINT_PREF "erasing block %d\n", ebnum2); + pr_info("erasing block %d\n", ebnum2); err = erase_eraseblock(ebnum2); if (err) return err; - printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); + pr_info("reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtd_read(mtd, addr0, pgsize, &read, readbuf); if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr0); return err ? err : -1; } - printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum); + pr_info("verifying 1st page of block %d\n", ebnum); if (memcmp(writebuf, readbuf, pgsize)) { - printk(PRINT_PREF "verify failed!\n"); + pr_err("verify failed!\n"); errcnt += 1; return -1; } if (!err) - printk(PRINT_PREF "erasecrosstest ok\n"); + pr_info("erasecrosstest ok\n"); return err; } @@ -402,7 +402,7 @@ static int erasetest(void) int err = 0, i, ebnum, ok = 1; loff_t addr0; - printk(PRINT_PREF "erasetest\n"); + pr_info("erasetest\n"); ebnum = 0; addr0 = 0; @@ -411,40 +411,40 @@ static int erasetest(void) ebnum += 1; } - printk(PRINT_PREF "erasing block %d\n", ebnum); + pr_info("erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; - printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); + pr_info("writing 1st page of block %d\n", ebnum); set_random_data(writebuf, pgsize); err = mtd_write(mtd, addr0, pgsize, &written, writebuf); if (err || written != pgsize) { - printk(PRINT_PREF "error: write failed at %#llx\n", + pr_err("error: write failed at %#llx\n", (long long)addr0); return err ? err : -1; } - printk(PRINT_PREF "erasing block %d\n", ebnum); + pr_info("erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; - printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); + pr_info("reading 1st page of block %d\n", ebnum); err = mtd_read(mtd, addr0, pgsize, &read, twopages); if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr0); return err ? err : -1; } - printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n", + pr_info("verifying 1st page of block %d is all 0xff\n", ebnum); for (i = 0; i < pgsize; ++i) if (twopages[i] != 0xff) { - printk(PRINT_PREF "verifying all 0xff failed at %d\n", + pr_err("verifying all 0xff failed at %d\n", i); errcnt += 1; ok = 0; @@ -452,7 +452,7 @@ static int erasetest(void) } if (ok && !err) - printk(PRINT_PREF "erasetest ok\n"); + pr_info("erasetest ok\n"); return err; } @@ -464,7 +464,7 @@ static int is_block_bad(int ebnum) ret = mtd_block_isbad(mtd, addr); if (ret) - printk(PRINT_PREF "block %d is bad\n", ebnum); + pr_info("block %d is bad\n", ebnum); return ret; } @@ -474,18 +474,18 @@ static int scan_for_bad_eraseblocks(void) bbt = kzalloc(ebcnt, GFP_KERNEL); if (!bbt) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); return -ENOMEM; } - printk(PRINT_PREF "scanning for bad eraseblocks\n"); + pr_info("scanning for bad eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { bbt[i] = is_block_bad(i) ? 1 : 0; if (bbt[i]) bad += 1; cond_resched(); } - printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); return 0; } @@ -499,22 +499,22 @@ static int __init mtd_pagetest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); - printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } - printk(PRINT_PREF "MTD device: %d\n", dev); + pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); - printk(PRINT_PREF "error: cannot get MTD device\n"); + pr_err("error: cannot get MTD device\n"); return err; } if (mtd->type != MTD_NANDFLASH) { - printk(PRINT_PREF "this test requires NAND flash\n"); + pr_info("this test requires NAND flash\n"); goto out; } @@ -524,7 +524,7 @@ static int __init mtd_pagetest_init(void) pgcnt = mtd->erasesize / mtd->writesize; pgsize = mtd->writesize; - printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, @@ -534,17 +534,17 @@ static int __init mtd_pagetest_init(void) bufsize = pgsize * 2; writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!writebuf) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out; } twopages = kmalloc(bufsize, GFP_KERNEL); if (!twopages) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out; } boundary = kmalloc(bufsize, GFP_KERNEL); if (!boundary) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out; } @@ -553,7 +553,7 @@ static int __init mtd_pagetest_init(void) goto out; /* Erase all eraseblocks */ - printk(PRINT_PREF "erasing whole device\n"); + pr_info("erasing whole device\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -562,11 +562,11 @@ static int __init mtd_pagetest_init(void) goto out; cond_resched(); } - printk(PRINT_PREF "erased %u eraseblocks\n", i); + pr_info("erased %u eraseblocks\n", i); /* Write all eraseblocks */ simple_srand(1); - printk(PRINT_PREF "writing whole device\n"); + pr_info("writing whole device\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -574,14 +574,14 @@ static int __init mtd_pagetest_init(void) if (err) goto out; if (i % 256 == 0) - printk(PRINT_PREF "written up to eraseblock %u\n", i); + pr_info("written up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "written %u eraseblocks\n", i); + pr_info("written %u eraseblocks\n", i); /* Check all eraseblocks */ simple_srand(1); - printk(PRINT_PREF "verifying all eraseblocks\n"); + pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -589,10 +589,10 @@ static int __init mtd_pagetest_init(void) if (err) goto out; if (i % 256 == 0) - printk(PRINT_PREF "verified up to eraseblock %u\n", i); + pr_info("verified up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "verified %u eraseblocks\n", i); + pr_info("verified %u eraseblocks\n", i); err = crosstest(); if (err) @@ -606,7 +606,7 @@ static int __init mtd_pagetest_init(void) if (err) goto out; - printk(PRINT_PREF "finished with %d errors\n", errcnt); + pr_info("finished with %d errors\n", errcnt); out: kfree(bbt); @@ -615,7 +615,7 @@ out: kfree(writebuf); put_mtd_device(mtd); if (err) - printk(PRINT_PREF "error %d occurred\n", err); + pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; } -- cgit v0.10.2 From e45048a6a232de1dc6978f2f4df6369beafa79c0 Mon Sep 17 00:00:00 2001 From: Vikram Narayanan Date: Wed, 10 Oct 2012 23:08:01 +0530 Subject: mtd: tests: mtd_readtest: Replace printk with pr_{info,err} Use pr_fmt instead of PRINT_PREF macro Signed-off-by: Vikram Narayanan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c index 121aba1..ec3efb5 100644 --- a/drivers/mtd/tests/mtd_readtest.c +++ b/drivers/mtd/tests/mtd_readtest.c @@ -19,6 +19,8 @@ * Author: Adrian Hunter */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -27,8 +29,6 @@ #include #include -#define PRINT_PREF KERN_INFO "mtd_readtest: " - static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -56,7 +56,7 @@ static int read_eraseblock_by_page(int ebnum) if (ret == -EUCLEAN) ret = 0; if (ret || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr); if (!err) err = ret; @@ -77,7 +77,7 @@ static int read_eraseblock_by_page(int ebnum) ret = mtd_read_oob(mtd, addr, &ops); if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != mtd->oobsize) { - printk(PRINT_PREF "error: read oob failed at " + pr_err("error: read oob failed at " "%#llx\n", (long long)addr); if (!err) err = ret; @@ -99,7 +99,7 @@ static void dump_eraseblock(int ebnum) char line[128]; int pg, oob; - printk(PRINT_PREF "dumping eraseblock %d\n", ebnum); + pr_info("dumping eraseblock %d\n", ebnum); n = mtd->erasesize; for (i = 0; i < n;) { char *p = line; @@ -112,7 +112,7 @@ static void dump_eraseblock(int ebnum) } if (!mtd->oobsize) return; - printk(PRINT_PREF "dumping oob from eraseblock %d\n", ebnum); + pr_info("dumping oob from eraseblock %d\n", ebnum); n = mtd->oobsize; for (pg = 0, i = 0; pg < pgcnt; pg++) for (oob = 0; oob < n;) { @@ -134,7 +134,7 @@ static int is_block_bad(int ebnum) ret = mtd_block_isbad(mtd, addr); if (ret) - printk(PRINT_PREF "block %d is bad\n", ebnum); + pr_info("block %d is bad\n", ebnum); return ret; } @@ -144,21 +144,21 @@ static int scan_for_bad_eraseblocks(void) bbt = kzalloc(ebcnt, GFP_KERNEL); if (!bbt) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); return -ENOMEM; } if (!mtd_can_have_bb(mtd)) return 0; - printk(PRINT_PREF "scanning for bad eraseblocks\n"); + pr_info("scanning for bad eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { bbt[i] = is_block_bad(i) ? 1 : 0; if (bbt[i]) bad += 1; cond_resched(); } - printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); return 0; } @@ -171,21 +171,21 @@ static int __init mtd_readtest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + pr_info("Please specify a valid mtd-device via module paramter\n"); return -EINVAL; } - printk(PRINT_PREF "MTD device: %d\n", dev); + pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); - printk(PRINT_PREF "error: Cannot get MTD device\n"); + pr_err("error: Cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { - printk(PRINT_PREF "not NAND flash, assume page size is 512 " + pr_info("not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else @@ -196,7 +196,7 @@ static int __init mtd_readtest_init(void) ebcnt = tmp; pgcnt = mtd->erasesize / pgsize; - printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, @@ -205,12 +205,12 @@ static int __init mtd_readtest_init(void) err = -ENOMEM; iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!iobuf) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out; } iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL); if (!iobuf1) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out; } @@ -219,7 +219,7 @@ static int __init mtd_readtest_init(void) goto out; /* Read all eraseblocks 1 page at a time */ - printk(PRINT_PREF "testing page read\n"); + pr_info("testing page read\n"); for (i = 0; i < ebcnt; ++i) { int ret; @@ -235,9 +235,9 @@ static int __init mtd_readtest_init(void) } if (err) - printk(PRINT_PREF "finished with errors\n"); + pr_info("finished with errors\n"); else - printk(PRINT_PREF "finished\n"); + pr_info("finished\n"); out: @@ -246,7 +246,7 @@ out: kfree(bbt); put_mtd_device(mtd); if (err) - printk(PRINT_PREF "error %d occurred\n", err); + pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; } -- cgit v0.10.2 From ae0086cfeef14ec2b5aef625cb9be1d625aac33b Mon Sep 17 00:00:00 2001 From: Vikram Narayanan Date: Wed, 10 Oct 2012 23:10:22 +0530 Subject: mtd: tests: mtd_stresstest: Replace printk with pr_{info,crit,err} Use pr_fmt instead of PRINT_PREF macro Signed-off-by: Vikram Narayanan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c index cb268ce..fea1dd7 100644 --- a/drivers/mtd/tests/mtd_stresstest.c +++ b/drivers/mtd/tests/mtd_stresstest.c @@ -19,6 +19,8 @@ * Author: Adrian Hunter */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -29,8 +31,6 @@ #include #include -#define PRINT_PREF KERN_INFO "mtd_stresstest: " - static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -94,12 +94,12 @@ static int erase_eraseblock(int ebnum) err = mtd_erase(mtd, &ei); if (unlikely(err)) { - printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + pr_err("error %d while erasing EB %d\n", err, ebnum); return err; } if (unlikely(ei.state == MTD_ERASE_FAILED)) { - printk(PRINT_PREF "some erase error occurred at EB %d\n", + pr_err("some erase error occurred at EB %d\n", ebnum); return -EIO; } @@ -114,7 +114,7 @@ static int is_block_bad(int ebnum) ret = mtd_block_isbad(mtd, addr); if (ret) - printk(PRINT_PREF "block %d is bad\n", ebnum); + pr_info("block %d is bad\n", ebnum); return ret; } @@ -137,7 +137,7 @@ static int do_read(void) if (mtd_is_bitflip(err)) err = 0; if (unlikely(err || read != len)) { - printk(PRINT_PREF "error: read failed at 0x%llx\n", + pr_err("error: read failed at 0x%llx\n", (long long)addr); if (!err) err = -EINVAL; @@ -174,7 +174,7 @@ static int do_write(void) addr = eb * mtd->erasesize + offs; err = mtd_write(mtd, addr, len, &written, writebuf); if (unlikely(err || written != len)) { - printk(PRINT_PREF "error: write failed at 0x%llx\n", + pr_err("error: write failed at 0x%llx\n", (long long)addr); if (!err) err = -EINVAL; @@ -203,21 +203,21 @@ static int scan_for_bad_eraseblocks(void) bbt = kzalloc(ebcnt, GFP_KERNEL); if (!bbt) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); return -ENOMEM; } if (!mtd_can_have_bb(mtd)) return 0; - printk(PRINT_PREF "scanning for bad eraseblocks\n"); + pr_info("scanning for bad eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { bbt[i] = is_block_bad(i) ? 1 : 0; if (bbt[i]) bad += 1; cond_resched(); } - printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); return 0; } @@ -231,22 +231,22 @@ static int __init mtd_stresstest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); - printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } - printk(PRINT_PREF "MTD device: %d\n", dev); + pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); - printk(PRINT_PREF "error: cannot get MTD device\n"); + pr_err("error: cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { - printk(PRINT_PREF "not NAND flash, assume page size is 512 " + pr_info("not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else @@ -257,14 +257,14 @@ static int __init mtd_stresstest_init(void) ebcnt = tmp; pgcnt = mtd->erasesize / pgsize; - printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, pgsize, ebcnt, pgcnt, mtd->oobsize); if (ebcnt < 2) { - printk(PRINT_PREF "error: need at least 2 eraseblocks\n"); + pr_err("error: need at least 2 eraseblocks\n"); err = -ENOSPC; goto out_put_mtd; } @@ -277,7 +277,7 @@ static int __init mtd_stresstest_init(void) writebuf = vmalloc(bufsize); offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL); if (!readbuf || !writebuf || !offsets) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out; } for (i = 0; i < ebcnt; i++) @@ -290,16 +290,16 @@ static int __init mtd_stresstest_init(void) goto out; /* Do operations */ - printk(PRINT_PREF "doing operations\n"); + pr_info("doing operations\n"); for (op = 0; op < count; op++) { if ((op & 1023) == 0) - printk(PRINT_PREF "%d operations done\n", op); + pr_info("%d operations done\n", op); err = do_operation(); if (err) goto out; cond_resched(); } - printk(PRINT_PREF "finished, %d operations done\n", op); + pr_info("finished, %d operations done\n", op); out: kfree(offsets); @@ -309,7 +309,7 @@ out: out_put_mtd: put_mtd_device(mtd); if (err) - printk(PRINT_PREF "error %d occurred\n", err); + pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; } -- cgit v0.10.2 From 2c70d292825df639d7ac765424098bdc1882bd49 Mon Sep 17 00:00:00 2001 From: Vikram Narayanan Date: Wed, 10 Oct 2012 23:10:02 +0530 Subject: mtd: tests: mtd_speedtest: Replace printk with pr_{info,crit,err} Use pr_fmt instead of PRINT_PREF macro Signed-off-by: Vikram Narayanan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 42b0f74..8a5803b 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -19,6 +19,8 @@ * Author: Adrian Hunter */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -28,8 +30,6 @@ #include #include -#define PRINT_PREF KERN_INFO "mtd_speedtest: " - static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -70,12 +70,12 @@ static int erase_eraseblock(int ebnum) err = mtd_erase(mtd, &ei); if (err) { - printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + pr_err("error %d while erasing EB %d\n", err, ebnum); return err; } if (ei.state == MTD_ERASE_FAILED) { - printk(PRINT_PREF "some erase error occurred at EB %d\n", + pr_err("some erase error occurred at EB %d\n", ebnum); return -EIO; } @@ -96,13 +96,13 @@ static int multiblock_erase(int ebnum, int blocks) err = mtd_erase(mtd, &ei); if (err) { - printk(PRINT_PREF "error %d while erasing EB %d, blocks %d\n", + pr_err("error %d while erasing EB %d, blocks %d\n", err, ebnum, blocks); return err; } if (ei.state == MTD_ERASE_FAILED) { - printk(PRINT_PREF "some erase error occurred at EB %d," + pr_err("some erase error occurred at EB %d," "blocks %d\n", ebnum, blocks); return -EIO; } @@ -134,7 +134,7 @@ static int write_eraseblock(int ebnum) err = mtd_write(mtd, addr, mtd->erasesize, &written, iobuf); if (err || written != mtd->erasesize) { - printk(PRINT_PREF "error: write failed at %#llx\n", addr); + pr_err("error: write failed at %#llx\n", addr); if (!err) err = -EINVAL; } @@ -152,7 +152,7 @@ static int write_eraseblock_by_page(int ebnum) for (i = 0; i < pgcnt; i++) { err = mtd_write(mtd, addr, pgsize, &written, buf); if (err || written != pgsize) { - printk(PRINT_PREF "error: write failed at %#llx\n", + pr_err("error: write failed at %#llx\n", addr); if (!err) err = -EINVAL; @@ -175,7 +175,7 @@ static int write_eraseblock_by_2pages(int ebnum) for (i = 0; i < n; i++) { err = mtd_write(mtd, addr, sz, &written, buf); if (err || written != sz) { - printk(PRINT_PREF "error: write failed at %#llx\n", + pr_err("error: write failed at %#llx\n", addr); if (!err) err = -EINVAL; @@ -187,7 +187,7 @@ static int write_eraseblock_by_2pages(int ebnum) if (pgcnt % 2) { err = mtd_write(mtd, addr, pgsize, &written, buf); if (err || written != pgsize) { - printk(PRINT_PREF "error: write failed at %#llx\n", + pr_err("error: write failed at %#llx\n", addr); if (!err) err = -EINVAL; @@ -208,7 +208,7 @@ static int read_eraseblock(int ebnum) if (mtd_is_bitflip(err)) err = 0; if (err || read != mtd->erasesize) { - printk(PRINT_PREF "error: read failed at %#llx\n", addr); + pr_err("error: read failed at %#llx\n", addr); if (!err) err = -EINVAL; } @@ -229,7 +229,7 @@ static int read_eraseblock_by_page(int ebnum) if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", addr); if (!err) err = -EINVAL; @@ -255,7 +255,7 @@ static int read_eraseblock_by_2pages(int ebnum) if (mtd_is_bitflip(err)) err = 0; if (err || read != sz) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", addr); if (!err) err = -EINVAL; @@ -270,7 +270,7 @@ static int read_eraseblock_by_2pages(int ebnum) if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", addr); if (!err) err = -EINVAL; @@ -287,7 +287,7 @@ static int is_block_bad(int ebnum) ret = mtd_block_isbad(mtd, addr); if (ret) - printk(PRINT_PREF "block %d is bad\n", ebnum); + pr_info("block %d is bad\n", ebnum); return ret; } @@ -321,21 +321,21 @@ static int scan_for_bad_eraseblocks(void) bbt = kzalloc(ebcnt, GFP_KERNEL); if (!bbt) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); return -ENOMEM; } if (!mtd_can_have_bb(mtd)) goto out; - printk(PRINT_PREF "scanning for bad eraseblocks\n"); + pr_info("scanning for bad eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { bbt[i] = is_block_bad(i) ? 1 : 0; if (bbt[i]) bad += 1; cond_resched(); } - printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); out: goodebcnt = ebcnt - bad; return 0; @@ -351,25 +351,25 @@ static int __init mtd_speedtest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); - printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } if (count) - printk(PRINT_PREF "MTD device: %d count: %d\n", dev, count); + pr_info("MTD device: %d count: %d\n", dev, count); else - printk(PRINT_PREF "MTD device: %d\n", dev); + pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); - printk(PRINT_PREF "error: cannot get MTD device\n"); + pr_err("error: cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { - printk(PRINT_PREF "not NAND flash, assume page size is 512 " + pr_info("not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else @@ -380,7 +380,7 @@ static int __init mtd_speedtest_init(void) ebcnt = tmp; pgcnt = mtd->erasesize / pgsize; - printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, @@ -392,7 +392,7 @@ static int __init mtd_speedtest_init(void) err = -ENOMEM; iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!iobuf) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out; } @@ -407,7 +407,7 @@ static int __init mtd_speedtest_init(void) goto out; /* Write all eraseblocks, 1 eraseblock at a time */ - printk(PRINT_PREF "testing eraseblock write speed\n"); + pr_info("testing eraseblock write speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) @@ -419,10 +419,10 @@ static int __init mtd_speedtest_init(void) } stop_timing(); speed = calc_speed(); - printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed); + pr_info("eraseblock write speed is %ld KiB/s\n", speed); /* Read all eraseblocks, 1 eraseblock at a time */ - printk(PRINT_PREF "testing eraseblock read speed\n"); + pr_info("testing eraseblock read speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) @@ -434,14 +434,14 @@ static int __init mtd_speedtest_init(void) } stop_timing(); speed = calc_speed(); - printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed); + pr_info("eraseblock read speed is %ld KiB/s\n", speed); err = erase_whole_device(); if (err) goto out; /* Write all eraseblocks, 1 page at a time */ - printk(PRINT_PREF "testing page write speed\n"); + pr_info("testing page write speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) @@ -453,10 +453,10 @@ static int __init mtd_speedtest_init(void) } stop_timing(); speed = calc_speed(); - printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed); + pr_info("page write speed is %ld KiB/s\n", speed); /* Read all eraseblocks, 1 page at a time */ - printk(PRINT_PREF "testing page read speed\n"); + pr_info("testing page read speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) @@ -468,14 +468,14 @@ static int __init mtd_speedtest_init(void) } stop_timing(); speed = calc_speed(); - printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed); + pr_info("page read speed is %ld KiB/s\n", speed); err = erase_whole_device(); if (err) goto out; /* Write all eraseblocks, 2 pages at a time */ - printk(PRINT_PREF "testing 2 page write speed\n"); + pr_info("testing 2 page write speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) @@ -487,10 +487,10 @@ static int __init mtd_speedtest_init(void) } stop_timing(); speed = calc_speed(); - printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed); + pr_info("2 page write speed is %ld KiB/s\n", speed); /* Read all eraseblocks, 2 pages at a time */ - printk(PRINT_PREF "testing 2 page read speed\n"); + pr_info("testing 2 page read speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) @@ -502,10 +502,10 @@ static int __init mtd_speedtest_init(void) } stop_timing(); speed = calc_speed(); - printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed); + pr_info("2 page read speed is %ld KiB/s\n", speed); /* Erase all eraseblocks */ - printk(PRINT_PREF "Testing erase speed\n"); + pr_info("Testing erase speed\n"); start_timing(); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) @@ -517,12 +517,12 @@ static int __init mtd_speedtest_init(void) } stop_timing(); speed = calc_speed(); - printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed); + pr_info("erase speed is %ld KiB/s\n", speed); /* Multi-block erase all eraseblocks */ for (k = 1; k < 7; k++) { blocks = 1 << k; - printk(PRINT_PREF "Testing %dx multi-block erase speed\n", + pr_info("Testing %dx multi-block erase speed\n", blocks); start_timing(); for (i = 0; i < ebcnt; ) { @@ -541,16 +541,16 @@ static int __init mtd_speedtest_init(void) } stop_timing(); speed = calc_speed(); - printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n", + pr_info("%dx multi-block erase speed is %ld KiB/s\n", blocks, speed); } - printk(PRINT_PREF "finished\n"); + pr_info("finished\n"); out: kfree(iobuf); kfree(bbt); put_mtd_device(mtd); if (err) - printk(PRINT_PREF "error %d occurred\n", err); + pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; } -- cgit v0.10.2 From cd66a2df7c29e51ed90f298abbb6f698fa424a08 Mon Sep 17 00:00:00 2001 From: Vikram Narayanan Date: Wed, 10 Oct 2012 23:11:06 +0530 Subject: mtd: tests: mtd_subpagetest: replace printk with pr_{info,crit,err} Use pr_fmt instead of PRINT_PREF macro Signed-off-by: Vikram Narayanan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c index 9667bf5..8813b0e 100644 --- a/drivers/mtd/tests/mtd_subpagetest.c +++ b/drivers/mtd/tests/mtd_subpagetest.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -27,8 +29,6 @@ #include #include -#define PRINT_PREF KERN_INFO "mtd_subpagetest: " - static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -82,12 +82,12 @@ static int erase_eraseblock(int ebnum) err = mtd_erase(mtd, &ei); if (err) { - printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + pr_err("error %d while erasing EB %d\n", err, ebnum); return err; } if (ei.state == MTD_ERASE_FAILED) { - printk(PRINT_PREF "some erase error occurred at EB %d\n", + pr_err("some erase error occurred at EB %d\n", ebnum); return -EIO; } @@ -100,7 +100,7 @@ static int erase_whole_device(void) int err; unsigned int i; - printk(PRINT_PREF "erasing whole device\n"); + pr_info("erasing whole device\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -109,7 +109,7 @@ static int erase_whole_device(void) return err; cond_resched(); } - printk(PRINT_PREF "erased %u eraseblocks\n", i); + pr_info("erased %u eraseblocks\n", i); return 0; } @@ -122,11 +122,11 @@ static int write_eraseblock(int ebnum) set_random_data(writebuf, subpgsize); err = mtd_write(mtd, addr, subpgsize, &written, writebuf); if (unlikely(err || written != subpgsize)) { - printk(PRINT_PREF "error: write failed at %#llx\n", + pr_err("error: write failed at %#llx\n", (long long)addr); if (written != subpgsize) { - printk(PRINT_PREF " write size: %#x\n", subpgsize); - printk(PRINT_PREF " written: %#zx\n", written); + pr_err(" write size: %#x\n", subpgsize); + pr_err(" written: %#zx\n", written); } return err ? err : -1; } @@ -136,11 +136,11 @@ static int write_eraseblock(int ebnum) set_random_data(writebuf, subpgsize); err = mtd_write(mtd, addr, subpgsize, &written, writebuf); if (unlikely(err || written != subpgsize)) { - printk(PRINT_PREF "error: write failed at %#llx\n", + pr_err("error: write failed at %#llx\n", (long long)addr); if (written != subpgsize) { - printk(PRINT_PREF " write size: %#x\n", subpgsize); - printk(PRINT_PREF " written: %#zx\n", written); + pr_err(" write size: %#x\n", subpgsize); + pr_err(" written: %#zx\n", written); } return err ? err : -1; } @@ -160,12 +160,12 @@ static int write_eraseblock2(int ebnum) set_random_data(writebuf, subpgsize * k); err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf); if (unlikely(err || written != subpgsize * k)) { - printk(PRINT_PREF "error: write failed at %#llx\n", + pr_err("error: write failed at %#llx\n", (long long)addr); if (written != subpgsize) { - printk(PRINT_PREF " write size: %#x\n", + pr_err(" write size: %#x\n", subpgsize * k); - printk(PRINT_PREF " written: %#08zx\n", + pr_err(" written: %#08zx\n", written); } return err ? err : -1; @@ -198,23 +198,23 @@ static int verify_eraseblock(int ebnum) err = mtd_read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { if (mtd_is_bitflip(err) && read == subpgsize) { - printk(PRINT_PREF "ECC correction at %#llx\n", + pr_info("ECC correction at %#llx\n", (long long)addr); err = 0; } else { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr); return err ? err : -1; } } if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { - printk(PRINT_PREF "error: verify failed at %#llx\n", + pr_err("error: verify failed at %#llx\n", (long long)addr); - printk(PRINT_PREF "------------- written----------------\n"); + pr_info("------------- written----------------\n"); print_subpage(writebuf); - printk(PRINT_PREF "------------- read ------------------\n"); + pr_info("------------- read ------------------\n"); print_subpage(readbuf); - printk(PRINT_PREF "-------------------------------------\n"); + pr_info("-------------------------------------\n"); errcnt += 1; } @@ -225,23 +225,23 @@ static int verify_eraseblock(int ebnum) err = mtd_read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { if (mtd_is_bitflip(err) && read == subpgsize) { - printk(PRINT_PREF "ECC correction at %#llx\n", + pr_info("ECC correction at %#llx\n", (long long)addr); err = 0; } else { - printk(PRINT_PREF "error: read failed at %#llx\n", + pr_err("error: read failed at %#llx\n", (long long)addr); return err ? err : -1; } } if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { - printk(PRINT_PREF "error: verify failed at %#llx\n", + pr_info("error: verify failed at %#llx\n", (long long)addr); - printk(PRINT_PREF "------------- written----------------\n"); + pr_info("------------- written----------------\n"); print_subpage(writebuf); - printk(PRINT_PREF "------------- read ------------------\n"); + pr_info("------------- read ------------------\n"); print_subpage(readbuf); - printk(PRINT_PREF "-------------------------------------\n"); + pr_info("-------------------------------------\n"); errcnt += 1; } @@ -262,17 +262,17 @@ static int verify_eraseblock2(int ebnum) err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf); if (unlikely(err || read != subpgsize * k)) { if (mtd_is_bitflip(err) && read == subpgsize * k) { - printk(PRINT_PREF "ECC correction at %#llx\n", + pr_info("ECC correction at %#llx\n", (long long)addr); err = 0; } else { - printk(PRINT_PREF "error: read failed at " + pr_err("error: read failed at " "%#llx\n", (long long)addr); return err ? err : -1; } } if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) { - printk(PRINT_PREF "error: verify failed at %#llx\n", + pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; } @@ -295,17 +295,17 @@ static int verify_eraseblock_ff(int ebnum) err = mtd_read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { if (mtd_is_bitflip(err) && read == subpgsize) { - printk(PRINT_PREF "ECC correction at %#llx\n", + pr_info("ECC correction at %#llx\n", (long long)addr); err = 0; } else { - printk(PRINT_PREF "error: read failed at " + pr_err("error: read failed at " "%#llx\n", (long long)addr); return err ? err : -1; } } if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { - printk(PRINT_PREF "error: verify 0xff failed at " + pr_err("error: verify 0xff failed at " "%#llx\n", (long long)addr); errcnt += 1; } @@ -320,7 +320,7 @@ static int verify_all_eraseblocks_ff(void) int err; unsigned int i; - printk(PRINT_PREF "verifying all eraseblocks for 0xff\n"); + pr_info("verifying all eraseblocks for 0xff\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -328,10 +328,10 @@ static int verify_all_eraseblocks_ff(void) if (err) return err; if (i % 256 == 0) - printk(PRINT_PREF "verified up to eraseblock %u\n", i); + pr_info("verified up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "verified %u eraseblocks\n", i); + pr_info("verified %u eraseblocks\n", i); return 0; } @@ -342,7 +342,7 @@ static int is_block_bad(int ebnum) ret = mtd_block_isbad(mtd, addr); if (ret) - printk(PRINT_PREF "block %d is bad\n", ebnum); + pr_info("block %d is bad\n", ebnum); return ret; } @@ -352,18 +352,18 @@ static int scan_for_bad_eraseblocks(void) bbt = kzalloc(ebcnt, GFP_KERNEL); if (!bbt) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); return -ENOMEM; } - printk(PRINT_PREF "scanning for bad eraseblocks\n"); + pr_info("scanning for bad eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { bbt[i] = is_block_bad(i) ? 1 : 0; if (bbt[i]) bad += 1; cond_resched(); } - printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); return 0; } @@ -377,22 +377,22 @@ static int __init mtd_subpagetest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); - printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } - printk(PRINT_PREF "MTD device: %d\n", dev); + pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); - printk(PRINT_PREF "error: cannot get MTD device\n"); + pr_err("error: cannot get MTD device\n"); return err; } if (mtd->type != MTD_NANDFLASH) { - printk(PRINT_PREF "this test requires NAND flash\n"); + pr_info("this test requires NAND flash\n"); goto out; } @@ -402,7 +402,7 @@ static int __init mtd_subpagetest_init(void) ebcnt = tmp; pgcnt = mtd->erasesize / mtd->writesize; - printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, subpage size %u, count of eraseblocks %u, " "pages per eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, @@ -412,12 +412,12 @@ static int __init mtd_subpagetest_init(void) bufsize = subpgsize * 32; writebuf = kmalloc(bufsize, GFP_KERNEL); if (!writebuf) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_info("error: cannot allocate memory\n"); goto out; } readbuf = kmalloc(bufsize, GFP_KERNEL); if (!readbuf) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_info("error: cannot allocate memory\n"); goto out; } @@ -429,7 +429,7 @@ static int __init mtd_subpagetest_init(void) if (err) goto out; - printk(PRINT_PREF "writing whole device\n"); + pr_info("writing whole device\n"); simple_srand(1); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) @@ -438,13 +438,13 @@ static int __init mtd_subpagetest_init(void) if (unlikely(err)) goto out; if (i % 256 == 0) - printk(PRINT_PREF "written up to eraseblock %u\n", i); + pr_info("written up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "written %u eraseblocks\n", i); + pr_info("written %u eraseblocks\n", i); simple_srand(1); - printk(PRINT_PREF "verifying all eraseblocks\n"); + pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -452,10 +452,10 @@ static int __init mtd_subpagetest_init(void) if (unlikely(err)) goto out; if (i % 256 == 0) - printk(PRINT_PREF "verified up to eraseblock %u\n", i); + pr_info("verified up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "verified %u eraseblocks\n", i); + pr_info("verified %u eraseblocks\n", i); err = erase_whole_device(); if (err) @@ -467,7 +467,7 @@ static int __init mtd_subpagetest_init(void) /* Write all eraseblocks */ simple_srand(3); - printk(PRINT_PREF "writing whole device\n"); + pr_info("writing whole device\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -475,14 +475,14 @@ static int __init mtd_subpagetest_init(void) if (unlikely(err)) goto out; if (i % 256 == 0) - printk(PRINT_PREF "written up to eraseblock %u\n", i); + pr_info("written up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "written %u eraseblocks\n", i); + pr_info("written %u eraseblocks\n", i); /* Check all eraseblocks */ simple_srand(3); - printk(PRINT_PREF "verifying all eraseblocks\n"); + pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -490,10 +490,10 @@ static int __init mtd_subpagetest_init(void) if (unlikely(err)) goto out; if (i % 256 == 0) - printk(PRINT_PREF "verified up to eraseblock %u\n", i); + pr_info("verified up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "verified %u eraseblocks\n", i); + pr_info("verified %u eraseblocks\n", i); err = erase_whole_device(); if (err) @@ -503,7 +503,7 @@ static int __init mtd_subpagetest_init(void) if (err) goto out; - printk(PRINT_PREF "finished with %d errors\n", errcnt); + pr_info("finished with %d errors\n", errcnt); out: kfree(bbt); @@ -511,7 +511,7 @@ out: kfree(writebuf); put_mtd_device(mtd); if (err) - printk(PRINT_PREF "error %d occurred\n", err); + pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; } -- cgit v0.10.2 From 95637c3a0e2db200fd4030e7ed5f1138d81f16ae Mon Sep 17 00:00:00 2001 From: Vikram Narayanan Date: Wed, 10 Oct 2012 23:11:37 +0530 Subject: mtd: tests: mtd_torturetest: Replace printk with pr_{info,crit} Use pr_fmt instead of PRINT_PREF macro Signed-off-by: Vikram Narayanan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c index b65861b..98d2a82 100644 --- a/drivers/mtd/tests/mtd_torturetest.c +++ b/drivers/mtd/tests/mtd_torturetest.c @@ -23,6 +23,8 @@ * damage caused by this program. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -31,7 +33,6 @@ #include #include -#define PRINT_PREF KERN_INFO "mtd_torturetest: " #define RETRIES 3 static int eb = 8; @@ -107,12 +108,12 @@ static inline int erase_eraseblock(int ebnum) err = mtd_erase(mtd, &ei); if (err) { - printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + pr_err("error %d while erasing EB %d\n", err, ebnum); return err; } if (ei.state == MTD_ERASE_FAILED) { - printk(PRINT_PREF "some erase error occurred at EB %d\n", + pr_err("some erase error occurred at EB %d\n", ebnum); return -EIO; } @@ -139,40 +140,40 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf) retry: err = mtd_read(mtd, addr, len, &read, check_buf); if (mtd_is_bitflip(err)) - printk(PRINT_PREF "single bit flip occurred at EB %d " + pr_err("single bit flip occurred at EB %d " "MTD reported that it was fixed.\n", ebnum); else if (err) { - printk(PRINT_PREF "error %d while reading EB %d, " + pr_err("error %d while reading EB %d, " "read %zd\n", err, ebnum, read); return err; } if (read != len) { - printk(PRINT_PREF "failed to read %zd bytes from EB %d, " + pr_err("failed to read %zd bytes from EB %d, " "read only %zd, but no error reported\n", len, ebnum, read); return -EIO; } if (memcmp(buf, check_buf, len)) { - printk(PRINT_PREF "read wrong data from EB %d\n", ebnum); + pr_err("read wrong data from EB %d\n", ebnum); report_corrupt(check_buf, buf); if (retries++ < RETRIES) { /* Try read again */ yield(); - printk(PRINT_PREF "re-try reading data from EB %d\n", + pr_info("re-try reading data from EB %d\n", ebnum); goto retry; } else { - printk(PRINT_PREF "retried %d times, still errors, " + pr_info("retried %d times, still errors, " "give-up\n", RETRIES); return -EINVAL; } } if (retries != 0) - printk(PRINT_PREF "only attempt number %d was OK (!!!)\n", + pr_info("only attempt number %d was OK (!!!)\n", retries); return 0; @@ -191,12 +192,12 @@ static inline int write_pattern(int ebnum, void *buf) } err = mtd_write(mtd, addr, len, &written, buf); if (err) { - printk(PRINT_PREF "error %d while writing EB %d, written %zd" + pr_err("error %d while writing EB %d, written %zd" " bytes\n", err, ebnum, written); return err; } if (written != len) { - printk(PRINT_PREF "written only %zd bytes of %zd, but no error" + pr_info("written only %zd bytes of %zd, but no error" " reported\n", written, len); return -EIO; } @@ -211,64 +212,64 @@ static int __init tort_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); - printk(PRINT_PREF "Warning: this program is trying to wear out your " + pr_info("Warning: this program is trying to wear out your " "flash, stop it if this is not wanted.\n"); if (dev < 0) { - printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); - printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } - printk(PRINT_PREF "MTD device: %d\n", dev); - printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n", + pr_info("MTD device: %d\n", dev); + pr_info("torture %d eraseblocks (%d-%d) of mtd%d\n", ebcnt, eb, eb + ebcnt - 1, dev); if (pgcnt) - printk(PRINT_PREF "torturing just %d pages per eraseblock\n", + pr_info("torturing just %d pages per eraseblock\n", pgcnt); - printk(PRINT_PREF "write verify %s\n", check ? "enabled" : "disabled"); + pr_info("write verify %s\n", check ? "enabled" : "disabled"); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); - printk(PRINT_PREF "error: cannot get MTD device\n"); + pr_err("error: cannot get MTD device\n"); return err; } if (mtd->writesize == 1) { - printk(PRINT_PREF "not NAND flash, assume page size is 512 " + pr_info("not NAND flash, assume page size is 512 " "bytes.\n"); pgsize = 512; } else pgsize = mtd->writesize; if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) { - printk(PRINT_PREF "error: invalid pgcnt value %d\n", pgcnt); + pr_err("error: invalid pgcnt value %d\n", pgcnt); goto out_mtd; } err = -ENOMEM; patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL); if (!patt_5A5) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out_mtd; } patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL); if (!patt_A5A) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out_patt_5A5; } patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL); if (!patt_FF) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out_patt_A5A; } check_buf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!check_buf) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out_patt_FF; } @@ -295,13 +296,13 @@ static int __init tort_init(void) err = mtd_block_isbad(mtd, (loff_t)i * mtd->erasesize); if (err < 0) { - printk(PRINT_PREF "block_isbad() returned %d " + pr_info("block_isbad() returned %d " "for EB %d\n", err, i); goto out; } if (err) { - printk("EB %d is bad. Skip it.\n", i); + pr_err("EB %d is bad. Skip it.\n", i); bad_ebs[i - eb] = 1; } } @@ -329,7 +330,7 @@ static int __init tort_init(void) continue; err = check_eraseblock(i, patt_FF); if (err) { - printk(PRINT_PREF "verify failed" + pr_info("verify failed" " for 0xFF... pattern\n"); goto out; } @@ -362,7 +363,7 @@ static int __init tort_init(void) patt = patt_A5A; err = check_eraseblock(i, patt); if (err) { - printk(PRINT_PREF "verify failed for %s" + pr_info("verify failed for %s" " pattern\n", ((eb + erase_cycles) & 1) ? "0x55AA55..." : "0xAA55AA..."); @@ -380,7 +381,7 @@ static int __init tort_init(void) stop_timing(); ms = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000; - printk(PRINT_PREF "%08u erase cycles done, took %lu " + pr_info("%08u erase cycles done, took %lu " "milliseconds (%lu seconds)\n", erase_cycles, ms, ms / 1000); start_timing(); @@ -391,7 +392,7 @@ static int __init tort_init(void) } out: - printk(PRINT_PREF "finished after %u erase cycles\n", + pr_info("finished after %u erase cycles\n", erase_cycles); kfree(check_buf); out_patt_FF: @@ -403,7 +404,7 @@ out_patt_5A5: out_mtd: put_mtd_device(mtd); if (err) - printk(PRINT_PREF "error %d occurred during torturing\n", err); + pr_info("error %d occurred during torturing\n", err); printk(KERN_INFO "=================================================\n"); return err; } @@ -441,9 +442,9 @@ static void report_corrupt(unsigned char *read, unsigned char *written) &bits) >= 0) pages++; - printk(PRINT_PREF "verify fails on %d pages, %d bytes/%d bits\n", + pr_info("verify fails on %d pages, %d bytes/%d bits\n", pages, bytes, bits); - printk(PRINT_PREF "The following is a list of all differences between" + pr_info("The following is a list of all differences between" " what was read from flash and what was expected\n"); for (i = 0; i < check_len; i += pgsize) { @@ -457,7 +458,7 @@ static void report_corrupt(unsigned char *read, unsigned char *written) printk("-------------------------------------------------------" "----------------------------------\n"); - printk(PRINT_PREF "Page %zd has %d bytes/%d bits failing verify," + pr_info("Page %zd has %d bytes/%d bits failing verify," " starting at offset 0x%x\n", (mtd->erasesize - check_len + i) / pgsize, bytes, bits, first); -- cgit v0.10.2 From 04810274a982009ab26e2f15c32149c184e9e8e5 Mon Sep 17 00:00:00 2001 From: Vikram Narayanan Date: Wed, 10 Oct 2012 23:12:02 +0530 Subject: mtd: mtd_oobtest: printk -> pr_{info,err,crit} Use pr_info() and pr_err() while defining pr_fmt(). This saves a few characters, joins a few lines, and makes the code a little more readable (and grep-able). Signed-off-by: Brian Norris Signed-off-by: Vikram Narayanan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c index ed9b628..e86bb29 100644 --- a/drivers/mtd/tests/mtd_oobtest.c +++ b/drivers/mtd/tests/mtd_oobtest.c @@ -19,6 +19,8 @@ * Author: Adrian Hunter */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -28,8 +30,6 @@ #include #include -#define PRINT_PREF KERN_INFO "mtd_oobtest: " - static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -80,13 +80,12 @@ static int erase_eraseblock(int ebnum) err = mtd_erase(mtd, &ei); if (err) { - printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + pr_err("error %d while erasing EB %d\n", err, ebnum); return err; } if (ei.state == MTD_ERASE_FAILED) { - printk(PRINT_PREF "some erase error occurred at EB %d\n", - ebnum); + pr_err("some erase error occurred at EB %d\n", ebnum); return -EIO; } @@ -98,7 +97,7 @@ static int erase_whole_device(void) int err; unsigned int i; - printk(PRINT_PREF "erasing whole device\n"); + pr_info("erasing whole device\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -107,7 +106,7 @@ static int erase_whole_device(void) return err; cond_resched(); } - printk(PRINT_PREF "erased %u eraseblocks\n", i); + pr_info("erased %u eraseblocks\n", i); return 0; } @@ -141,9 +140,9 @@ static int write_eraseblock(int ebnum) ops.oobbuf = writebuf; err = mtd_write_oob(mtd, addr, &ops); if (err || ops.oobretlen != use_len) { - printk(PRINT_PREF "error: writeoob failed at %#llx\n", + pr_err("error: writeoob failed at %#llx\n", (long long)addr); - printk(PRINT_PREF "error: use_len %d, use_offset %d\n", + pr_err("error: use_len %d, use_offset %d\n", use_len, use_offset); errcnt += 1; return err ? err : -1; @@ -160,7 +159,7 @@ static int write_whole_device(void) int err; unsigned int i; - printk(PRINT_PREF "writing OOBs of whole device\n"); + pr_info("writing OOBs of whole device\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -168,10 +167,10 @@ static int write_whole_device(void) if (err) return err; if (i % 256 == 0) - printk(PRINT_PREF "written up to eraseblock %u\n", i); + pr_info("written up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "written %u eraseblocks\n", i); + pr_info("written %u eraseblocks\n", i); return 0; } @@ -194,17 +193,17 @@ static int verify_eraseblock(int ebnum) ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); if (err || ops.oobretlen != use_len) { - printk(PRINT_PREF "error: readoob failed at %#llx\n", + pr_err("error: readoob failed at %#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } if (memcmp(readbuf, writebuf, use_len)) { - printk(PRINT_PREF "error: verify failed at %#llx\n", + pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { - printk(PRINT_PREF "error: too many errors\n"); + pr_err("error: too many errors\n"); return -1; } } @@ -221,29 +220,28 @@ static int verify_eraseblock(int ebnum) ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); if (err || ops.oobretlen != mtd->ecclayout->oobavail) { - printk(PRINT_PREF "error: readoob failed at " - "%#llx\n", (long long)addr); + pr_err("error: readoob failed at %#llx\n", + (long long)addr); errcnt += 1; return err ? err : -1; } if (memcmp(readbuf + use_offset, writebuf, use_len)) { - printk(PRINT_PREF "error: verify failed at " - "%#llx\n", (long long)addr); + pr_err("error: verify failed at %#llx\n", + (long long)addr); errcnt += 1; if (errcnt > 1000) { - printk(PRINT_PREF "error: too many " - "errors\n"); + pr_err("error: too many errors\n"); return -1; } } for (k = 0; k < use_offset; ++k) if (readbuf[k] != 0xff) { - printk(PRINT_PREF "error: verify 0xff " + pr_err("error: verify 0xff " "failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { - printk(PRINT_PREF "error: too " + pr_err("error: too " "many errors\n"); return -1; } @@ -251,12 +249,12 @@ static int verify_eraseblock(int ebnum) for (k = use_offset + use_len; k < mtd->ecclayout->oobavail; ++k) if (readbuf[k] != 0xff) { - printk(PRINT_PREF "error: verify 0xff " + pr_err("error: verify 0xff " "failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { - printk(PRINT_PREF "error: too " + pr_err("error: too " "many errors\n"); return -1; } @@ -286,17 +284,17 @@ static int verify_eraseblock_in_one_go(int ebnum) ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); if (err || ops.oobretlen != len) { - printk(PRINT_PREF "error: readoob failed at %#llx\n", + pr_err("error: readoob failed at %#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } if (memcmp(readbuf, writebuf, len)) { - printk(PRINT_PREF "error: verify failed at %#llx\n", + pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { - printk(PRINT_PREF "error: too many errors\n"); + pr_err("error: too many errors\n"); return -1; } } @@ -309,7 +307,7 @@ static int verify_all_eraseblocks(void) int err; unsigned int i; - printk(PRINT_PREF "verifying all eraseblocks\n"); + pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -317,10 +315,10 @@ static int verify_all_eraseblocks(void) if (err) return err; if (i % 256 == 0) - printk(PRINT_PREF "verified up to eraseblock %u\n", i); + pr_info("verified up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "verified %u eraseblocks\n", i); + pr_info("verified %u eraseblocks\n", i); return 0; } @@ -331,7 +329,7 @@ static int is_block_bad(int ebnum) ret = mtd_block_isbad(mtd, addr); if (ret) - printk(PRINT_PREF "block %d is bad\n", ebnum); + pr_info("block %d is bad\n", ebnum); return ret; } @@ -341,18 +339,18 @@ static int scan_for_bad_eraseblocks(void) bbt = kmalloc(ebcnt, GFP_KERNEL); if (!bbt) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); return -ENOMEM; } - printk(PRINT_PREF "scanning for bad eraseblocks\n"); + pr_info("scanning for bad eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { bbt[i] = is_block_bad(i) ? 1 : 0; if (bbt[i]) bad += 1; cond_resched(); } - printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); return 0; } @@ -368,22 +366,22 @@ static int __init mtd_oobtest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); - printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_crit(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } - printk(PRINT_PREF "MTD device: %d\n", dev); + pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); - printk(PRINT_PREF "error: cannot get MTD device\n"); + pr_err("error: cannot get MTD device\n"); return err; } if (mtd->type != MTD_NANDFLASH) { - printk(PRINT_PREF "this test requires NAND flash\n"); + pr_info("this test requires NAND flash\n"); goto out; } @@ -392,7 +390,7 @@ static int __init mtd_oobtest_init(void) ebcnt = tmp; pgcnt = mtd->erasesize / mtd->writesize; - printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, @@ -401,12 +399,12 @@ static int __init mtd_oobtest_init(void) err = -ENOMEM; readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!readbuf) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out; } writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!writebuf) { - printk(PRINT_PREF "error: cannot allocate memory\n"); + pr_err("error: cannot allocate memory\n"); goto out; } @@ -420,7 +418,7 @@ static int __init mtd_oobtest_init(void) vary_offset = 0; /* First test: write all OOB, read it back and verify */ - printk(PRINT_PREF "test 1 of 5\n"); + pr_info("test 1 of 5\n"); err = erase_whole_device(); if (err) @@ -440,7 +438,7 @@ static int __init mtd_oobtest_init(void) * Second test: write all OOB, a block at a time, read it back and * verify. */ - printk(PRINT_PREF "test 2 of 5\n"); + pr_info("test 2 of 5\n"); err = erase_whole_device(); if (err) @@ -453,7 +451,7 @@ static int __init mtd_oobtest_init(void) /* Check all eraseblocks */ simple_srand(3); - printk(PRINT_PREF "verifying all eraseblocks\n"); + pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; @@ -461,16 +459,16 @@ static int __init mtd_oobtest_init(void) if (err) goto out; if (i % 256 == 0) - printk(PRINT_PREF "verified up to eraseblock %u\n", i); + pr_info("verified up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "verified %u eraseblocks\n", i); + pr_info("verified %u eraseblocks\n", i); /* * Third test: write OOB at varying offsets and lengths, read it back * and verify. */ - printk(PRINT_PREF "test 3 of 5\n"); + pr_info("test 3 of 5\n"); err = erase_whole_device(); if (err) @@ -503,7 +501,7 @@ static int __init mtd_oobtest_init(void) vary_offset = 0; /* Fourth test: try to write off end of device */ - printk(PRINT_PREF "test 4 of 5\n"); + pr_info("test 4 of 5\n"); err = erase_whole_device(); if (err) @@ -522,14 +520,14 @@ static int __init mtd_oobtest_init(void) ops.ooboffs = mtd->ecclayout->oobavail; ops.datbuf = NULL; ops.oobbuf = writebuf; - printk(PRINT_PREF "attempting to start write past end of OOB\n"); - printk(PRINT_PREF "an error is expected...\n"); + pr_info("attempting to start write past end of OOB\n"); + pr_info("an error is expected...\n"); err = mtd_write_oob(mtd, addr0, &ops); if (err) { - printk(PRINT_PREF "error occurred as expected\n"); + pr_info("error occurred as expected\n"); err = 0; } else { - printk(PRINT_PREF "error: can write past end of OOB\n"); + pr_err("error: can write past end of OOB\n"); errcnt += 1; } @@ -542,19 +540,19 @@ static int __init mtd_oobtest_init(void) ops.ooboffs = mtd->ecclayout->oobavail; ops.datbuf = NULL; ops.oobbuf = readbuf; - printk(PRINT_PREF "attempting to start read past end of OOB\n"); - printk(PRINT_PREF "an error is expected...\n"); + pr_info("attempting to start read past end of OOB\n"); + pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, addr0, &ops); if (err) { - printk(PRINT_PREF "error occurred as expected\n"); + pr_info("error occurred as expected\n"); err = 0; } else { - printk(PRINT_PREF "error: can read past end of OOB\n"); + pr_err("error: can read past end of OOB\n"); errcnt += 1; } if (bbt[ebcnt - 1]) - printk(PRINT_PREF "skipping end of device tests because last " + pr_info("skipping end of device tests because last " "block is bad\n"); else { /* Attempt to write off end of device */ @@ -566,14 +564,14 @@ static int __init mtd_oobtest_init(void) ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = writebuf; - printk(PRINT_PREF "attempting to write past end of device\n"); - printk(PRINT_PREF "an error is expected...\n"); + pr_info("attempting to write past end of device\n"); + pr_info("an error is expected...\n"); err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { - printk(PRINT_PREF "error occurred as expected\n"); + pr_info("error occurred as expected\n"); err = 0; } else { - printk(PRINT_PREF "error: wrote past end of device\n"); + pr_err("error: wrote past end of device\n"); errcnt += 1; } @@ -586,14 +584,14 @@ static int __init mtd_oobtest_init(void) ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; - printk(PRINT_PREF "attempting to read past end of device\n"); - printk(PRINT_PREF "an error is expected...\n"); + pr_info("attempting to read past end of device\n"); + pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { - printk(PRINT_PREF "error occurred as expected\n"); + pr_info("error occurred as expected\n"); err = 0; } else { - printk(PRINT_PREF "error: read past end of device\n"); + pr_err("error: read past end of device\n"); errcnt += 1; } @@ -610,14 +608,14 @@ static int __init mtd_oobtest_init(void) ops.ooboffs = 1; ops.datbuf = NULL; ops.oobbuf = writebuf; - printk(PRINT_PREF "attempting to write past end of device\n"); - printk(PRINT_PREF "an error is expected...\n"); + pr_info("attempting to write past end of device\n"); + pr_info("an error is expected...\n"); err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { - printk(PRINT_PREF "error occurred as expected\n"); + pr_info("error occurred as expected\n"); err = 0; } else { - printk(PRINT_PREF "error: wrote past end of device\n"); + pr_err("error: wrote past end of device\n"); errcnt += 1; } @@ -630,20 +628,20 @@ static int __init mtd_oobtest_init(void) ops.ooboffs = 1; ops.datbuf = NULL; ops.oobbuf = readbuf; - printk(PRINT_PREF "attempting to read past end of device\n"); - printk(PRINT_PREF "an error is expected...\n"); + pr_info("attempting to read past end of device\n"); + pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { - printk(PRINT_PREF "error occurred as expected\n"); + pr_info("error occurred as expected\n"); err = 0; } else { - printk(PRINT_PREF "error: read past end of device\n"); + pr_err("error: read past end of device\n"); errcnt += 1; } } /* Fifth test: write / read across block boundaries */ - printk(PRINT_PREF "test 5 of 5\n"); + pr_info("test 5 of 5\n"); /* Erase all eraseblocks */ err = erase_whole_device(); @@ -652,7 +650,7 @@ static int __init mtd_oobtest_init(void) /* Write all eraseblocks */ simple_srand(11); - printk(PRINT_PREF "writing OOBs of whole device\n"); + pr_info("writing OOBs of whole device\n"); for (i = 0; i < ebcnt - 1; ++i) { int cnt = 2; int pg; @@ -674,17 +672,16 @@ static int __init mtd_oobtest_init(void) if (err) goto out; if (i % 256 == 0) - printk(PRINT_PREF "written up to eraseblock " - "%u\n", i); + pr_info("written up to eraseblock %u\n", i); cond_resched(); addr += mtd->writesize; } } - printk(PRINT_PREF "written %u eraseblocks\n", i); + pr_info("written %u eraseblocks\n", i); /* Check all eraseblocks */ simple_srand(11); - printk(PRINT_PREF "verifying all eraseblocks\n"); + pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt - 1; ++i) { if (bbt[i] || bbt[i + 1]) continue; @@ -702,28 +699,28 @@ static int __init mtd_oobtest_init(void) if (err) goto out; if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) { - printk(PRINT_PREF "error: verify failed at %#llx\n", + pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { - printk(PRINT_PREF "error: too many errors\n"); + pr_err("error: too many errors\n"); goto out; } } if (i % 256 == 0) - printk(PRINT_PREF "verified up to eraseblock %u\n", i); + pr_info("verified up to eraseblock %u\n", i); cond_resched(); } - printk(PRINT_PREF "verified %u eraseblocks\n", i); + pr_info("verified %u eraseblocks\n", i); - printk(PRINT_PREF "finished with %d errors\n", errcnt); + pr_info("finished with %d errors\n", errcnt); out: kfree(bbt); kfree(writebuf); kfree(readbuf); put_mtd_device(mtd); if (err) - printk(PRINT_PREF "error %d occurred\n", err); + pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; } -- cgit v0.10.2 From 7483096665161d2567c2717e001654ad653d944e Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Sun, 14 Oct 2012 23:47:24 -0400 Subject: mtd: use the NAND_STATUS_FAIL to replace the hardcode Use the NAND_STATUS_FAIL to replace the hardcode "0x01", which make the code more readable. Signed-off-by: Huang Shijie Acked-by: Brian Norris Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1a03b7f..1d5c951 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -899,7 +899,7 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, /* Call wait ready function */ status = chip->waitfunc(mtd, chip); /* See if device thinks it succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { pr_debug("%s: error status = 0x%08x\n", __func__, status); ret = -EIO; @@ -1004,7 +1004,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Call wait ready function */ status = chip->waitfunc(mtd, chip); /* See if device thinks it succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { pr_debug("%s: error status = 0x%08x\n", __func__, status); ret = -EIO; -- cgit v0.10.2 From 18afbc54c4944b6c93f3888d97db0d1257a4b5e9 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 17 Oct 2012 10:08:27 +0400 Subject: mtd: gpio-nand: Ability to use driver for configurations without RDY-pin In some configurations of "gpio-nand" RDY-pin may be not connected. This patch allow to use driver for these configurations. In this case we are assume that device always ready. Signed-off-by: Alexander Shiyan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index bc73bc5..0b3c815 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -134,7 +134,11 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len) static int gpio_nand_devready(struct mtd_info *mtd) { struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); - return gpio_get_value(gpiomtd->plat.gpio_rdy); + + if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) + return gpio_get_value(gpiomtd->plat.gpio_rdy); + + return 1; } #ifdef CONFIG_OF @@ -252,7 +256,8 @@ static int __devexit gpio_nand_remove(struct platform_device *dev) gpio_free(gpiomtd->plat.gpio_nce); if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) gpio_free(gpiomtd->plat.gpio_nwp); - gpio_free(gpiomtd->plat.gpio_rdy); + if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) + gpio_free(gpiomtd->plat.gpio_rdy); kfree(gpiomtd); @@ -336,10 +341,12 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) if (ret) goto err_cle; gpio_direction_output(gpiomtd->plat.gpio_cle, 0); - ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY"); - if (ret) - goto err_rdy; - gpio_direction_input(gpiomtd->plat.gpio_rdy); + if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) { + ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY"); + if (ret) + goto err_rdy; + gpio_direction_input(gpiomtd->plat.gpio_rdy); + } this->IO_ADDR_W = this->IO_ADDR_R; @@ -386,7 +393,8 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) err_wp: if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) gpio_set_value(gpiomtd->plat.gpio_nwp, 0); - gpio_free(gpiomtd->plat.gpio_rdy); + if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) + gpio_free(gpiomtd->plat.gpio_rdy); err_rdy: gpio_free(gpiomtd->plat.gpio_cle); err_cle: -- cgit v0.10.2 From 5de0b52ea8f8f5149502867acff2efb5efaf1fc2 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Sat, 13 Oct 2012 13:03:29 -0400 Subject: mtd: gpmi: remove unneccessary header The whole gpmi-nand driver has turned to pure devicetree supported. So the linux/mtd/gpmi-nand.h is not neccessary now. Just remove it, and move some macros to the gpmi-nand driver itself. Signed-off-by: Huang Shijie Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 3502acc..1585c5b 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -18,7 +18,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include #include diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index e2c56fc..d376198 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -33,6 +32,12 @@ #include #include "gpmi-nand.h" +/* Resource names for the GPMI NAND driver. */ +#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand" +#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch" +#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch" +#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "gpmi-dma" + /* add our owner bbt descriptor */ static uint8_t scan_ff_pattern[] = { 0xff }; static struct nand_bbt_descr gpmi_bbt_descr = { diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 7ac25c1..3d93a5e 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -130,7 +130,6 @@ struct gpmi_nand_data { /* System Interface */ struct device *dev; struct platform_device *pdev; - struct gpmi_nand_platform_data *pdata; /* Resources */ struct resources resources; diff --git a/include/linux/mtd/gpmi-nand.h b/include/linux/mtd/gpmi-nand.h deleted file mode 100644 index ed3c4e0..0000000 --- a/include/linux/mtd/gpmi-nand.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef __MACH_MXS_GPMI_NAND_H__ -#define __MACH_MXS_GPMI_NAND_H__ - -/* The size of the resources is fixed. */ -#define GPMI_NAND_RES_SIZE 6 - -/* Resource names for the GPMI NAND driver. */ -#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand" -#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME "GPMI NAND GPMI Interrupt" -#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch" -#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch" -#define GPMI_NAND_DMA_CHANNELS_RES_NAME "GPMI NAND DMA Channels" -#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "gpmi-dma" - -/** - * struct gpmi_nand_platform_data - GPMI NAND driver platform data. - * - * This structure communicates platform-specific information to the GPMI NAND - * driver that can't be expressed as resources. - * - * @platform_init: A pointer to a function the driver will call to - * initialize the platform (e.g., set up the pin mux). - * @min_prop_delay_in_ns: Minimum propagation delay of GPMI signals to and - * from the NAND Flash device, in nanoseconds. - * @max_prop_delay_in_ns: Maximum propagation delay of GPMI signals to and - * from the NAND Flash device, in nanoseconds. - * @max_chip_count: The maximum number of chips for which the driver - * should configure the hardware. This value most - * likely reflects the number of pins that are - * connected to a NAND Flash device. If this is - * greater than the SoC hardware can support, the - * driver will print a message and fail to initialize. - * @partitions: An optional pointer to an array of partition - * descriptions. - * @partition_count: The number of elements in the partitions array. - */ -struct gpmi_nand_platform_data { - /* SoC hardware information. */ - int (*platform_init)(void); - - /* NAND Flash information. */ - unsigned int min_prop_delay_in_ns; - unsigned int max_prop_delay_in_ns; - unsigned int max_chip_count; - - /* Medium information. */ - struct mtd_partition *partitions; - unsigned partition_count; -}; -#endif -- cgit v0.10.2 From e8a9d8f31c592eea89f1b0d3fd425e7a96944e88 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Fri, 19 Oct 2012 12:15:34 +0200 Subject: mtd: sh_flctl: Minor cleanups Some small fixes to avoid sparse and smatch complain. Other cosmetic fixes as well. - Change of the type of the member index in struct sh_flctl from signed to unsigned. We use index by addressing array members, so unsigned is more concise here. Adapt functions relying on sh_flctl::index. - Remove a blurring cast in write_fiforeg(). - Apply consistent naming scheme when refering to the data buffer. - Shorten some unnecessarily verbose functions. - Remove spaces at start of lines. Signed-off-by: Bastian Hecht Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 4fbfe96..78d18c0f 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -225,7 +225,7 @@ static enum flctl_ecc_res_t wait_recfifo_ready for (i = 0; i < 3; i++) { uint8_t org; - int index; + unsigned int index; data = readl(ecc_reg[i]); @@ -305,28 +305,29 @@ static enum flctl_ecc_res_t read_ecfiforeg return res; } -static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) +static void write_fiforeg(struct sh_flctl *flctl, int rlen, + unsigned int offset) { int i, len_4align; - unsigned long *data = (unsigned long *)&flctl->done_buff[offset]; - void *fifo_addr = (void *)FLDTFIFO(flctl); + unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; len_4align = (rlen + 3) / 4; for (i = 0; i < len_4align; i++) { wait_wfifo_ready(flctl); - writel(cpu_to_be32(data[i]), fifo_addr); + writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl)); } } -static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset) +static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, + unsigned int offset) { int i, len_4align; - unsigned long *data = (unsigned long *)&flctl->done_buff[offset]; + unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; len_4align = (rlen + 3) / 4; for (i = 0; i < len_4align; i++) { wait_wecfifo_ready(flctl); - writel(cpu_to_be32(data[i]), FLECFIFO(flctl)); + writel(cpu_to_be32(buf[i]), FLECFIFO(flctl)); } } @@ -748,41 +749,35 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr) static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { struct sh_flctl *flctl = mtd_to_flctl(mtd); - int index = flctl->index; - memcpy(&flctl->done_buff[index], buf, len); + memcpy(&flctl->done_buff[flctl->index], buf, len); flctl->index += len; } static uint8_t flctl_read_byte(struct mtd_info *mtd) { struct sh_flctl *flctl = mtd_to_flctl(mtd); - int index = flctl->index; uint8_t data; - data = flctl->done_buff[index]; + data = flctl->done_buff[flctl->index]; flctl->index++; return data; } static uint16_t flctl_read_word(struct mtd_info *mtd) { - struct sh_flctl *flctl = mtd_to_flctl(mtd); - int index = flctl->index; - uint16_t data; - uint16_t *buf = (uint16_t *)&flctl->done_buff[index]; + struct sh_flctl *flctl = mtd_to_flctl(mtd); + uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index]; - data = *buf; - flctl->index += 2; - return data; + flctl->index += 2; + return *buf; } static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { struct sh_flctl *flctl = mtd_to_flctl(mtd); - int index = flctl->index; - memcpy(buf, &flctl->done_buff[index], len); + memcpy(buf, &flctl->done_buff[flctl->index], len); flctl->index += len; } diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index 01e4b15..4815576 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -147,7 +147,7 @@ struct sh_flctl { uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */ int read_bytes; - int index; + unsigned int index; int seqin_column; /* column in SEQIN cmd */ int seqin_page_addr; /* page_addr in SEQIN cmd */ uint32_t seqin_read_cmd; /* read cmd in SEQIN cmd */ -- cgit v0.10.2 From 83738d87e3a0a4096e1419a65b8228130d183df6 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Fri, 19 Oct 2012 12:15:35 +0200 Subject: mtd: sh_flctl: Add DMA capabilty The code probes if DMA channels can get allocated and tears them down at removal/failure if needed. If available it uses them to transfer the data part (not ECC). On failure we fall back to PIO mode. Based on Guennadi Liakhovetski's code from the sh_mmcif driver. Signed-off-by: Bastian Hecht Reviewed-by: Guennadi Liakhovetski Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 78d18c0f..6dc0369 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -23,11 +23,15 @@ #include #include +#include #include +#include +#include #include #include #include #include +#include #include #include @@ -106,6 +110,84 @@ static void wait_completion(struct sh_flctl *flctl) writeb(0x0, FLTRCR(flctl)); } +static void flctl_dma_complete(void *param) +{ + struct sh_flctl *flctl = param; + + complete(&flctl->dma_complete); +} + +static void flctl_release_dma(struct sh_flctl *flctl) +{ + if (flctl->chan_fifo0_rx) { + dma_release_channel(flctl->chan_fifo0_rx); + flctl->chan_fifo0_rx = NULL; + } + if (flctl->chan_fifo0_tx) { + dma_release_channel(flctl->chan_fifo0_tx); + flctl->chan_fifo0_tx = NULL; + } +} + +static void flctl_setup_dma(struct sh_flctl *flctl) +{ + dma_cap_mask_t mask; + struct dma_slave_config cfg; + struct platform_device *pdev = flctl->pdev; + struct sh_flctl_platform_data *pdata = pdev->dev.platform_data; + int ret; + + if (!pdata) + return; + + if (pdata->slave_id_fifo0_tx <= 0 || pdata->slave_id_fifo0_rx <= 0) + return; + + /* We can only either use DMA for both Tx and Rx or not use it at all */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter, + (void *)pdata->slave_id_fifo0_tx); + dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__, + flctl->chan_fifo0_tx); + + if (!flctl->chan_fifo0_tx) + return; + + memset(&cfg, 0, sizeof(cfg)); + cfg.slave_id = pdata->slave_id_fifo0_tx; + cfg.direction = DMA_MEM_TO_DEV; + cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl); + cfg.src_addr = 0; + ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg); + if (ret < 0) + goto err; + + flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter, + (void *)pdata->slave_id_fifo0_rx); + dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__, + flctl->chan_fifo0_rx); + + if (!flctl->chan_fifo0_rx) + goto err; + + cfg.slave_id = pdata->slave_id_fifo0_rx; + cfg.direction = DMA_DEV_TO_MEM; + cfg.dst_addr = 0; + cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl); + ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg); + if (ret < 0) + goto err; + + init_completion(&flctl->dma_complete); + + return; + +err: + flctl_release_dma(flctl); +} + static void set_addr(struct mtd_info *mtd, int column, int page_addr) { struct sh_flctl *flctl = mtd_to_flctl(mtd); @@ -261,6 +343,70 @@ static void wait_wecfifo_ready(struct sh_flctl *flctl) timeout_error(flctl, __func__); } +static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf, + int len, enum dma_data_direction dir) +{ + struct dma_async_tx_descriptor *desc = NULL; + struct dma_chan *chan; + enum dma_transfer_direction tr_dir; + dma_addr_t dma_addr; + dma_cookie_t cookie = -EINVAL; + uint32_t reg; + int ret; + + if (dir == DMA_FROM_DEVICE) { + chan = flctl->chan_fifo0_rx; + tr_dir = DMA_DEV_TO_MEM; + } else { + chan = flctl->chan_fifo0_tx; + tr_dir = DMA_MEM_TO_DEV; + } + + dma_addr = dma_map_single(chan->device->dev, buf, len, dir); + + if (dma_addr) + desc = dmaengine_prep_slave_single(chan, dma_addr, len, + tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + + if (desc) { + reg = readl(FLINTDMACR(flctl)); + reg |= DREQ0EN; + writel(reg, FLINTDMACR(flctl)); + + desc->callback = flctl_dma_complete; + desc->callback_param = flctl; + cookie = dmaengine_submit(desc); + + dma_async_issue_pending(chan); + } else { + /* DMA failed, fall back to PIO */ + flctl_release_dma(flctl); + dev_warn(&flctl->pdev->dev, + "DMA failed, falling back to PIO\n"); + ret = -EIO; + goto out; + } + + ret = + wait_for_completion_timeout(&flctl->dma_complete, + msecs_to_jiffies(3000)); + + if (ret <= 0) { + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n"); + } + +out: + reg = readl(FLINTDMACR(flctl)); + reg &= ~DREQ0EN; + writel(reg, FLINTDMACR(flctl)); + + dma_unmap_single(chan->device->dev, dma_addr, len, dir); + + /* ret > 0 is success */ + return ret; +} + static void read_datareg(struct sh_flctl *flctl, int offset) { unsigned long data; @@ -279,11 +425,20 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset) len_4align = (rlen + 3) / 4; + /* initiate DMA transfer */ + if (flctl->chan_fifo0_rx && rlen >= 32 && + flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0) + goto convert; /* DMA success */ + + /* do polling transfer */ for (i = 0; i < len_4align; i++) { wait_rfifo_ready(flctl); buf[i] = readl(FLDTFIFO(flctl)); - buf[i] = be32_to_cpu(buf[i]); } + +convert: + for (i = 0; i < len_4align; i++) + buf[i] = be32_to_cpu(buf[i]); } static enum flctl_ecc_res_t read_ecfiforeg @@ -325,9 +480,19 @@ static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; len_4align = (rlen + 3) / 4; + + for (i = 0; i < len_4align; i++) + buf[i] = cpu_to_be32(buf[i]); + + /* initiate DMA transfer */ + if (flctl->chan_fifo0_tx && rlen >= 32 && + flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0) + return; /* DMA success */ + + /* do polling transfer */ for (i = 0; i < len_4align; i++) { wait_wecfifo_ready(flctl); - writel(cpu_to_be32(buf[i]), FLECFIFO(flctl)); + writel(buf[i], FLECFIFO(flctl)); } } @@ -925,6 +1090,8 @@ static int __devinit flctl_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); + flctl_setup_dma(flctl); + ret = nand_scan_ident(flctl_mtd, 1, NULL); if (ret) goto err_chip; @@ -942,6 +1109,7 @@ static int __devinit flctl_probe(struct platform_device *pdev) return 0; err_chip: + flctl_release_dma(flctl); pm_runtime_disable(&pdev->dev); free_irq(irq, flctl); err_flste: @@ -955,6 +1123,7 @@ static int __devexit flctl_remove(struct platform_device *pdev) { struct sh_flctl *flctl = platform_get_drvdata(pdev); + flctl_release_dma(flctl); nand_release(&flctl->mtd); pm_runtime_disable(&pdev->dev); free_irq(platform_get_irq(pdev, 0), flctl); diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index 4815576..1c28f88 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -20,6 +20,7 @@ #ifndef __SH_FLCTL_H__ #define __SH_FLCTL_H__ +#include #include #include #include @@ -107,6 +108,7 @@ #define ESTERINTE (0x1 << 24) /* ECC error interrupt enable */ #define AC1CLR (0x1 << 19) /* ECC FIFO clear */ #define AC0CLR (0x1 << 18) /* Data FIFO clear */ +#define DREQ0EN (0x1 << 16) /* FLDTFIFODMA Request Enable */ #define ECERB (0x1 << 9) /* ECC error */ #define STERB (0x1 << 8) /* Status error */ #define STERINTE (0x1 << 4) /* Status error enable */ @@ -138,6 +140,8 @@ enum flctl_ecc_res_t { FL_TIMEOUT }; +struct dma_chan; + struct sh_flctl { struct mtd_info mtd; struct nand_chip chip; @@ -161,6 +165,11 @@ struct sh_flctl { unsigned hwecc:1; /* Hardware ECC (0 = disabled, 1 = enabled) */ unsigned holden:1; /* Hardware has FLHOLDCR and HOLDEN is set */ unsigned qos_request:1; /* QoS request to prevent deep power shutdown */ + + /* DMA related objects */ + struct dma_chan *chan_fifo0_rx; + struct dma_chan *chan_fifo0_tx; + struct completion dma_complete; }; struct sh_flctl_platform_data { @@ -170,6 +179,9 @@ struct sh_flctl_platform_data { unsigned has_hwecc:1; unsigned use_holden:1; + + unsigned int slave_id_fifo0_tx; + unsigned int slave_id_fifo0_rx; }; static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo) -- cgit v0.10.2 From 7c8f680e96edbd9896b13b5e6ff39bc5852dce2a Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Fri, 19 Oct 2012 12:15:36 +0200 Subject: mtd: sh_flctl: Add device tree support The flctl can now be probed via device tree setup in addition to the existing platform data way. SoC specific setup data is set in the .data member of the OF match, so kept within the driver itself, while board/user specific setup - like partitioning - is taken from the device tree. Actual configuration is added for the SoC sh7372. Signed-off-by: Bastian Hecht Signed-off-by: Artem Bityutskiy diff --git a/Documentation/devicetree/bindings/mtd/flctl-nand.txt b/Documentation/devicetree/bindings/mtd/flctl-nand.txt new file mode 100644 index 0000000..427f46d --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/flctl-nand.txt @@ -0,0 +1,49 @@ +FLCTL NAND controller + +Required properties: +- compatible : "renesas,shmobile-flctl-sh7372" +- reg : Address range of the FLCTL +- interrupts : flste IRQ number +- nand-bus-width : bus width to NAND chip + +Optional properties: +- dmas: DMA specifier(s) +- dma-names: name for each DMA specifier. Valid names are + "data_tx", "data_rx", "ecc_tx", "ecc_rx" + +The DMA fields are not used yet in the driver but are listed here for +completing the bindings. + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Example: + + flctl@e6a30000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "renesas,shmobile-flctl-sh7372"; + reg = <0xe6a30000 0x100>; + interrupts = <0x0d80>; + + nand-bus-width = <16>; + + dmas = <&dmac 1 /* data_tx */ + &dmac 2;> /* data_rx */ + dma-names = "data_tx", "data_rx"; + + system@0 { + label = "system"; + reg = <0x0 0x8000000>; + }; + + userdata@8000000 { + label = "userdata"; + reg = <0x8000000 0x10000000>; + }; + + cache@18000000 { + label = "cache"; + reg = <0x18000000 0x8000000>; + }; + }; diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 6dc0369..d51e3c1 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -1016,6 +1019,73 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_OF +struct flctl_soc_config { + unsigned long flcmncr_val; + unsigned has_hwecc:1; + unsigned use_holden:1; +}; + +static struct flctl_soc_config flctl_sh7372_config = { + .flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL, + .has_hwecc = 1, + .use_holden = 1, +}; + +static const struct of_device_id of_flctl_match[] = { + { .compatible = "renesas,shmobile-flctl-sh7372", + .data = &flctl_sh7372_config }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_flctl_match); + +static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) +{ + const struct of_device_id *match; + struct flctl_soc_config *config; + struct sh_flctl_platform_data *pdata; + struct device_node *dn = dev->of_node; + int ret; + + match = of_match_device(of_flctl_match, dev); + if (match) + config = (struct flctl_soc_config *)match->data; + else { + dev_err(dev, "%s: no OF configuration attached\n", __func__); + return NULL; + } + + pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(dev, "%s: failed to allocate config data\n", __func__); + return NULL; + } + + /* set SoC specific options */ + pdata->flcmncr_val = config->flcmncr_val; + pdata->has_hwecc = config->has_hwecc; + pdata->use_holden = config->use_holden; + + /* parse user defined options */ + ret = of_get_nand_bus_width(dn); + if (ret == 16) + pdata->flcmncr_val |= SEL_16BIT; + else if (ret != 8) { + dev_err(dev, "%s: invalid bus width\n", __func__); + return NULL; + } + + return pdata; +} +#else /* CONFIG_OF */ +#define of_flctl_match NULL +static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) +{ + return NULL; +} +#endif /* CONFIG_OF */ + static int __devinit flctl_probe(struct platform_device *pdev) { struct resource *res; @@ -1025,12 +1095,7 @@ static int __devinit flctl_probe(struct platform_device *pdev) struct sh_flctl_platform_data *pdata; int ret = -ENXIO; int irq; - - pdata = pdev->dev.platform_data; - if (pdata == NULL) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -EINVAL; - } + struct mtd_part_parser_data ppdata = {}; flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL); if (!flctl) { @@ -1062,6 +1127,17 @@ static int __devinit flctl_probe(struct platform_device *pdev) goto err_flste; } + if (pdev->dev.of_node) + pdata = flctl_parse_dt(&pdev->dev); + else + pdata = pdev->dev.platform_data; + + if (!pdata) { + dev_err(&pdev->dev, "no setup data defined\n"); + ret = -EINVAL; + goto err_pdata; + } + platform_set_drvdata(pdev, flctl); flctl_mtd = &flctl->mtd; nand = &flctl->chip; @@ -1104,13 +1180,16 @@ static int __devinit flctl_probe(struct platform_device *pdev) if (ret) goto err_chip; - mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts); + ppdata.of_node = pdev->dev.of_node; + ret = mtd_device_parse_register(flctl_mtd, NULL, &ppdata, pdata->parts, + pdata->nr_parts); return 0; err_chip: flctl_release_dma(flctl); pm_runtime_disable(&pdev->dev); +err_pdata: free_irq(irq, flctl); err_flste: iounmap(flctl->reg); @@ -1138,6 +1217,7 @@ static struct platform_driver flctl_driver = { .driver = { .name = "sh_flctl", .owner = THIS_MODULE, + .of_match_table = of_flctl_match, }, }; -- cgit v0.10.2 From cd409c61287b81d432024c1dbfad292304bf5df3 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Fri, 19 Oct 2012 17:29:33 +0200 Subject: mtdoops: don't erase flash at each boot The current version on mtdoops erase first block of mtdoops partition at each boot if there is no oops stored in flash. This can wear the flash. When mtdoops start, find_next_position is called to find the next free entry in the circular buffer. But if the flash is erased, find_next_position don't find anything (maxcount == 0xffffffff) and start with the first entry after erasing it. The scanning that is done in find_next_position already track free/used entries. So if at the end of the scanning we don't find anything, we can start at the first entry and erased the entry only if it is marked as used. Most of this is implemented in mtdoops_inc_counter, so to avoid duplicating code, if we don't find anything we set position to -1. mtdoops_inc_counter with increment it, erase the entry if needed and start as before with nextpage = 0 and nextcount = 1). Also during the scan phase, we use the MTDOOPS_KERNMSG_MAGIC to detect corruped entries. Signed-off-by: Matthieu Castet Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index f5b3f91..97bb8f6 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -271,7 +271,7 @@ static void find_next_position(struct mtdoops_context *cxt) if (count[0] == 0xffffffff && count[1] == 0xffffffff) mark_page_unused(cxt, page); - if (count[0] == 0xffffffff) + if (count[0] == 0xffffffff || count[1] != MTDOOPS_KERNMSG_MAGIC) continue; if (maxcount == 0xffffffff) { maxcount = count[0]; @@ -289,14 +289,13 @@ static void find_next_position(struct mtdoops_context *cxt) } } if (maxcount == 0xffffffff) { - cxt->nextpage = 0; - cxt->nextcount = 1; - schedule_work(&cxt->work_erase); - return; + cxt->nextpage = cxt->oops_pages - 1; + cxt->nextcount = 0; + } + else { + cxt->nextpage = maxpos; + cxt->nextcount = maxcount; } - - cxt->nextpage = maxpos; - cxt->nextcount = maxcount; mtdoops_inc_counter(cxt); } -- cgit v0.10.2 From 9ef525a9141b14d23613faad303cf48a20814f1b Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Thu, 25 Oct 2012 09:43:10 -0400 Subject: mtd: Fix kernel-doc content to avoid warning. Add missing colons to fix kernel-doc generation warnings. Signed-off-by: Robert P. J. Day Signed-off-by: Artem Bityutskiy diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 24e9159..9d8a604 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -471,8 +471,8 @@ struct nand_buffers { * non 0 if ONFI supported. * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is * supported, 0 otherwise. - * @onfi_set_features [REPLACEABLE] set the features for ONFI nand - * @onfi_get_features [REPLACEABLE] get the features for ONFI nand + * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand + * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand * @ecclayout: [REPLACEABLE] the default ECC placement scheme * @bbt: [INTERN] bad block table pointer * @bbt_td: [REPLACEABLE] bad block table descriptor for flash -- cgit v0.10.2 From 3e9ce49e0ef95e22790a74720f0068696b2477c9 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 29 Oct 2012 22:47:26 +0530 Subject: mtd: map: Fix compilation warning This patch is an attempt to fix following compilation warning. In file included from drivers/mtd/chips/cfi_cmdset_0001.c:35:0: drivers/mtd/chips/cfi_cmdset_0001.c: In function 'cfi_intelext_write_words': include/linux/mtd/map.h:331:11: warning: 'r.x[0]' may be used uninitialized in this function [-Wmaybe-uninitialized] I could have used uninitialized_var() too, but didn't used it as the final else part of map_word_load() is missing. So there is a chance that it might be passed uninitialized. Better initialize to zero. Signed-off-by: Viresh Kumar Signed-off-by: Artem Bityutskiy diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 3595a02..56c7936 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -328,7 +328,7 @@ static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word static inline map_word map_word_load(struct map_info *map, const void *ptr) { - map_word r; + map_word r = {{0} }; if (map_bankwidth_is_1(map)) r.x[0] = *(unsigned char *)ptr; -- cgit v0.10.2 From 6f9f59ee2e254a7e997985d8eb708930da49245a Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 1 Nov 2012 13:58:17 +0800 Subject: mtd: cmdlinepart: fix the overflow of big mtd partitions When the kernel parses the following cmdline #mtdparts=gpmi-nand:16m(boot),16m(kernel),1g(home),4g(test),-(usr) for a big nand chip Micron MT29F64G08AFAAAWP(8GB), we got the following wrong result: ............................................. "mtd: partition size too small (0)" ............................................. We can not get any partition. The "4g(test)" partition triggers a overflow of the "size". The memparse() returns 4g to the "size", but the size is "unsigned long" type, so a overflow occurs, the "size" becomes zero in the end. This patch changes the "size"/"offset" to "unsigned long long" type, and replaces the UINT_MAX with ULLONG_MAX for macros SIZE_REMAINING and OFFSET_CONTINUOUS. Signed-off-by: Huang Shijie Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 4baab3b..c533f27 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -56,8 +56,8 @@ /* special size referring to all the remaining space in a partition */ -#define SIZE_REMAINING UINT_MAX -#define OFFSET_CONTINUOUS UINT_MAX +#define SIZE_REMAINING ULLONG_MAX +#define OFFSET_CONTINUOUS ULLONG_MAX struct cmdline_mtd_partition { struct cmdline_mtd_partition *next; @@ -89,7 +89,7 @@ static struct mtd_partition * newpart(char *s, int extra_mem_size) { struct mtd_partition *parts; - unsigned long size, offset = OFFSET_CONTINUOUS; + unsigned long long size, offset = OFFSET_CONTINUOUS; char *name; int name_len; unsigned char *extra_mem; @@ -104,7 +104,8 @@ static struct mtd_partition * newpart(char *s, } else { size = memparse(s, &s); if (size < PAGE_SIZE) { - printk(KERN_ERR ERRP "partition size too small (%lx)\n", size); + printk(KERN_ERR ERRP "partition size too small (%llx)\n", + size); return ERR_PTR(-EINVAL); } } @@ -296,7 +297,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, struct mtd_part_parser_data *data) { - unsigned long offset; + unsigned long long offset; int i, err; struct cmdline_mtd_partition *part; const char *mtd_id = master->name; -- cgit v0.10.2 From 192afdbfbc5c3346e27b3c3e3be8337495b2a41b Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Fri, 2 Nov 2012 10:22:41 -0400 Subject: mtd: davinci: add support for parition binding nodes Enhance the driver to support partition subnodes inside the nand device bindings to describe partions on the nand device. Signed-off-by: Murali Karicheri Reviewed-by: Grant Likely Signed-off-by: Artem Bityutskiy diff --git a/Documentation/devicetree/bindings/arm/davinci/nand.txt b/Documentation/devicetree/bindings/arm/davinci/nand.txt index e37241f..4746452 100644 --- a/Documentation/devicetree/bindings/arm/davinci/nand.txt +++ b/Documentation/devicetree/bindings/arm/davinci/nand.txt @@ -23,6 +23,9 @@ Recommended properties : - ti,davinci-nand-buswidth: buswidth 8 or 16 - ti,davinci-nand-use-bbt: use flash based bad block table support. +nand device bindings may contain additional sub-nodes describing +partitions of the address space. See partition.txt for more detail. + Example (enbw_cmc board): aemif@60000000 { compatible = "ti,davinci-aemif"; @@ -47,5 +50,10 @@ aemif@60000000 { ti,davinci-ecc-mode = "hw"; ti,davinci-ecc-bits = <4>; ti,davinci-nand-use-bbt; + + partition@180000 { + label = "ubifs"; + reg = <0x180000 0x7e80000>; + }; }; }; diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 945047a..3502606 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -821,9 +821,16 @@ syndrome_done: if (ret < 0) goto err_scan; - ret = mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts, - pdata->nr_parts); - + if (pdata->parts) + ret = mtd_device_parse_register(&info->mtd, NULL, NULL, + pdata->parts, pdata->nr_parts); + else { + struct mtd_part_parser_data ppdata; + + ppdata.of_node = pdev->dev.of_node; + ret = mtd_device_parse_register(&info->mtd, NULL, &ppdata, + NULL, 0); + } if (ret < 0) goto err_scan; -- cgit v0.10.2 From f251b8dfdd0721255ea11751cdc282834e43b74e Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Mon, 5 Nov 2012 15:00:44 +0100 Subject: mtd: nand_wait: warn if the nand is busy on exit This patch allow to detect buggy driver/hardware with bad RnB (dev_ready) management or when timeout occurs in polling mode. This works when dev_ready is set or not set. There are 2 methods to wait for an erase/program command completion: 1. Wait until nand RnB pin goes high (that's what chip->dev_ready usually does) 2. Poll the device: send a status (0x70) command and read status byte in a loop until bit NAND_STATUS_READY is set In all cases, you should send a status command after completion, to check if the operation was successful. And if the operation completed, the status should have bit NAND_STATUS_READY set. Signed-off-by: Matthieu CASTET Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1d5c951..0150540 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -865,6 +865,8 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) led_trigger_event(nand_led_trigger, LED_OFF); status = (int)chip->read_byte(mtd); + /* This can happen if in case of timeout or buggy dev_ready */ + WARN_ON(!(status & NAND_STATUS_READY)); return status; } -- cgit v0.10.2 From d60da506cbeb3f1907a740547dd7ef04a93e908e Mon Sep 17 00:00:00 2001 From: Hiraku Toyooka Date: Wed, 17 Oct 2012 11:56:16 +0900 Subject: tracing: Add a resize function to make one buffer equivalent to another buffer Trace buffer size is now per-cpu, so that there are the following two patterns in resizing of buffers. (1) resize per-cpu buffers to same given size (2) resize per-cpu buffers to another trace_array's buffer size for each CPU (such as preparing the max_tr which is equivalent to the global_trace's size) __tracing_resize_ring_buffer() can be used for (1), and had implemented (2) inside it for resetting the global_trace to the original size. (2) was also implemented in another place. So this patch assembles them in a new function - resize_buffer_duplicate_size(). Link: http://lkml.kernel.org/r/20121017025616.2627.91226.stgit@falsita Signed-off-by: Hiraku Toyooka Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index b69cc38..64ad9bc 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3034,6 +3034,31 @@ static void set_buffer_entries(struct trace_array *tr, unsigned long val) tr->data[cpu]->entries = val; } +/* resize @tr's buffer to the size of @size_tr's entries */ +static int resize_buffer_duplicate_size(struct trace_array *tr, + struct trace_array *size_tr, int cpu_id) +{ + int cpu, ret = 0; + + if (cpu_id == RING_BUFFER_ALL_CPUS) { + for_each_tracing_cpu(cpu) { + ret = ring_buffer_resize(tr->buffer, + size_tr->data[cpu]->entries, cpu); + if (ret < 0) + break; + tr->data[cpu]->entries = size_tr->data[cpu]->entries; + } + } else { + ret = ring_buffer_resize(tr->buffer, + size_tr->data[cpu_id]->entries, cpu_id); + if (ret == 0) + tr->data[cpu_id]->entries = + size_tr->data[cpu_id]->entries; + } + + return ret; +} + static int __tracing_resize_ring_buffer(unsigned long size, int cpu) { int ret; @@ -3058,23 +3083,8 @@ static int __tracing_resize_ring_buffer(unsigned long size, int cpu) ret = ring_buffer_resize(max_tr.buffer, size, cpu); if (ret < 0) { - int r = 0; - - if (cpu == RING_BUFFER_ALL_CPUS) { - int i; - for_each_tracing_cpu(i) { - r = ring_buffer_resize(global_trace.buffer, - global_trace.data[i]->entries, - i); - if (r < 0) - break; - } - } else { - r = ring_buffer_resize(global_trace.buffer, - global_trace.data[cpu]->entries, - cpu); - } - + int r = resize_buffer_duplicate_size(&global_trace, + &global_trace, cpu); if (r < 0) { /* * AARGH! We are left with different @@ -3212,17 +3222,11 @@ static int tracing_set_tracer(const char *buf) topts = create_trace_option_files(t); if (t->use_max_tr) { - int cpu; /* we need to make per cpu buffer sizes equivalent */ - for_each_tracing_cpu(cpu) { - ret = ring_buffer_resize(max_tr.buffer, - global_trace.data[cpu]->entries, - cpu); - if (ret < 0) - goto out; - max_tr.data[cpu]->entries = - global_trace.data[cpu]->entries; - } + ret = resize_buffer_duplicate_size(&max_tr, &global_trace, + RING_BUFFER_ALL_CPUS); + if (ret < 0) + goto out; } if (t->init) { -- cgit v0.10.2 From 7b0e62920ac314eb819e68b7d2c51994b98b19ca Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 24 Oct 2012 19:56:51 +0900 Subject: i2c: i2c-sh_mobile: calculate clock parameters at driver probing time Currently SCL clock parameters (ICCH/ICCL) are calculated in activate_ch(), which gets called every time sh_mobile_i2c_xfer() is processed, while each I2C bus speed is system-defined and in general those parameters do not have to be updated over I2C transactions. The only reason I could see having it transaction-time is to adjust ICCH/ICCL values according to the operating frequency of the I2C hardware block, in the face of DFS (Dynamic Frequency Scaling). However, this won't be necessary. The operating frequency of the I2C hardware block can change _even_ in the middle of I2C transactions. There is no way to prevent it from happening, and I2C hardware block can work with such dynamic frequency change, of course. Another is that ICCH/ICCL clock parameters optimized for the faster operating frequency, can also be applied to the slower operating frequency, as long as slave devices work. However, the converse is not true. It would violate SCL timing specs of the I2C standard. What we can do now is to calculate the ICCH/ICCL clock parameters according to the fastest operating clock of the I2C hardware block. And if that's the case, that calculation should be done just once at driver-module-init time. This patch moves ICCH/ICCL calculating part from activate_ch() into sh_mobile_i2c_init(), and call it from sh_mobile_i2c_probe(). Note that sh_mobile_i2c_init() just prepares clock parameters using the clock rate and platform data provided, but does _not_ make any hardware I/O accesses. We don't have to care about run-time PM maintenance here. Signed-off-by: Shinya Kuribayashi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 8110ca4..309d0d5 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -187,18 +187,15 @@ static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs, iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr); } -static void activate_ch(struct sh_mobile_i2c_data *pd) +static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) { unsigned long i2c_clk; u_int32_t num; u_int32_t denom; u_int32_t tmp; - /* Wake up device and enable clock */ - pm_runtime_get_sync(pd->dev); - clk_enable(pd->clk); - /* Get clock rate after clock is enabled */ + clk_enable(pd->clk); i2c_clk = clk_get_rate(pd->clk); /* Calculate the value for iccl. From the data sheet: @@ -239,6 +236,15 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) pd->icic &= ~ICIC_ICCHB8; } + clk_disable(pd->clk); +} + +static void activate_ch(struct sh_mobile_i2c_data *pd) +{ + /* Wake up device and enable clock */ + pm_runtime_get_sync(pd->dev); + clk_enable(pd->clk); + /* Enable channel and configure rx ack */ iic_set_clr(pd, ICCR, ICCR_ICE, 0); @@ -632,6 +638,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) if (size > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; + sh_mobile_i2c_init(pd); + /* Enable Runtime PM for this device. * * Also tell the Runtime PM core to ignore children -- cgit v0.10.2 From 23a612916a51cc3772ff46c9dc34a86c9c50840e Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 24 Oct 2012 19:57:27 +0900 Subject: i2c: i2c-sh_mobile: optimize ICCH/ICCL values according to I2C bus speed ICCH/ICCL values is supposed to be calculated/optimized to strictly meet the timing specs required by the I2C standard. The resulting I2C bus speed does not matter at all, if it's less than 100 or 400 kHz. With this change, sh_mobile_i2c_icch() is virtually identical to sh_mobile_i2c_iccl(), but they're providing good descriptions of SH-/R-Mobile I2C hardware spec, and I'd leave them as separated. Also fix a typo in the comment, print icch/iccl values at probe, etc. Signed-off-by: Shinya Kuribayashi [wsa: squashed two patches for bisectability] Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 309d0d5..4dc0cc3 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -122,9 +122,9 @@ struct sh_mobile_i2c_data { unsigned long bus_speed; struct clk *clk; u_int8_t icic; - u_int8_t iccl; - u_int8_t icch; u_int8_t flags; + u_int16_t iccl; + u_int16_t icch; spinlock_t lock; wait_queue_head_t wait; @@ -135,7 +135,8 @@ struct sh_mobile_i2c_data { #define IIC_FLAG_HAS_ICIC67 (1 << 0) -#define NORMAL_SPEED 100000 /* FAST_SPEED 400000 */ +#define STANDARD_MODE 100000 +#define FAST_MODE 400000 /* Register offsets */ #define ICDR 0x00 @@ -187,55 +188,81 @@ static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs, iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr); } +static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf, int offset) +{ + /* + * Conditional expression: + * ICCL >= COUNT_CLK * (tLOW + tf) + * + * SH-Mobile IIC hardware starts counting the LOW period of + * the SCL signal (tLOW) as soon as it pulls the SCL line. + * In order to meet the tLOW timing spec, we need to take into + * account the fall time of SCL signal (tf). Default tf value + * should be 0.3 us, for safety. + */ + return (((count_khz * (tLOW + tf)) + 5000) / 10000) + offset; +} + +static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf, int offset) +{ + /* + * Conditional expression: + * ICCH >= COUNT_CLK * (tHIGH + tf) + * + * SH-Mobile IIC hardware is aware of SCL transition period 'tr', + * and can ignore it. SH-Mobile IIC controller starts counting + * the HIGH period of the SCL signal (tHIGH) after the SCL input + * voltage increases at VIH. + * + * Afterward it turned out calculating ICCH using only tHIGH spec + * will result in violation of the tHD;STA timing spec. We need + * to take into account the fall time of SDA signal (tf) at START + * condition, in order to meet both tHIGH and tHD;STA specs. + */ + return (((count_khz * (tHIGH + tf)) + 5000) / 10000) + offset; +} + static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) { - unsigned long i2c_clk; - u_int32_t num; - u_int32_t denom; - u_int32_t tmp; + unsigned long i2c_clk_khz; + u32 tHIGH, tLOW, tf; + int offset; /* Get clock rate after clock is enabled */ clk_enable(pd->clk); - i2c_clk = clk_get_rate(pd->clk); - - /* Calculate the value for iccl. From the data sheet: - * iccl = (p clock / transfer rate) * (L / (L + H)) - * where L and H are the SCL low/high ratio (5/4 in this case). - * We also round off the result. - */ - num = i2c_clk * 5; - denom = pd->bus_speed * 9; - tmp = num * 10 / denom; - if (tmp % 10 >= 5) - pd->iccl = (u_int8_t)((num/denom) + 1); - else - pd->iccl = (u_int8_t)(num/denom); - - /* one more bit of ICCL in ICIC */ - if (pd->flags & IIC_FLAG_HAS_ICIC67) { - if ((num/denom) > 0xff) - pd->icic |= ICIC_ICCLB8; - else - pd->icic &= ~ICIC_ICCLB8; + i2c_clk_khz = clk_get_rate(pd->clk) / 1000; + + if (pd->bus_speed == STANDARD_MODE) { + tLOW = 47; /* tLOW = 4.7 us */ + tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */ + tf = 3; /* tf = 0.3 us */ + offset = 0; /* No offset */ + } else if (pd->bus_speed == FAST_MODE) { + tLOW = 13; /* tLOW = 1.3 us */ + tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */ + tf = 3; /* tf = 0.3 us */ + offset = 0; /* No offset */ + } else { + dev_err(pd->dev, "unrecognized bus speed %lu Hz\n", + pd->bus_speed); + goto out; } - /* Calculate the value for icch. From the data sheet: - icch = (p clock / transfer rate) * (H / (L + H)) */ - num = i2c_clk * 4; - tmp = num * 10 / denom; - if (tmp % 10 >= 5) - pd->icch = (u_int8_t)((num/denom) + 1); + pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf, offset); + /* one more bit of ICCL in ICIC */ + if ((pd->iccl > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) + pd->icic |= ICIC_ICCLB8; else - pd->icch = (u_int8_t)(num/denom); + pd->icic &= ~ICIC_ICCLB8; + pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf, offset); /* one more bit of ICCH in ICIC */ - if (pd->flags & IIC_FLAG_HAS_ICIC67) { - if ((num/denom) > 0xff) - pd->icic |= ICIC_ICCHB8; - else - pd->icic &= ~ICIC_ICCHB8; - } + if ((pd->icch > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) + pd->icic |= ICIC_ICCHB8; + else + pd->icic &= ~ICIC_ICCHB8; +out: clk_disable(pd->clk); } @@ -252,8 +279,8 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) iic_wr(pd, ICIC, 0); /* Set the clock */ - iic_wr(pd, ICCL, pd->iccl); - iic_wr(pd, ICCH, pd->icch); + iic_wr(pd, ICCL, pd->iccl & 0xff); + iic_wr(pd, ICCH, pd->icch & 0xff); } static void deactivate_ch(struct sh_mobile_i2c_data *pd) @@ -457,8 +484,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) iic_set_clr(pd, ICCR, ICCR_ICE, 0); /* Set the clock */ - iic_wr(pd, ICCL, pd->iccl); - iic_wr(pd, ICCH, pd->icch); + iic_wr(pd, ICCL, pd->iccl & 0xff); + iic_wr(pd, ICCH, pd->icch & 0xff); pd->msg = usr_msg; pd->pos = -1; @@ -627,8 +654,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_irq; } - /* Use platformd data bus speed or NORMAL_SPEED */ - pd->bus_speed = NORMAL_SPEED; + /* Use platform data bus speed or STANDARD_MODE */ + pd->bus_speed = STANDARD_MODE; if (pdata && pdata->bus_speed) pd->bus_speed = pdata->bus_speed; @@ -675,8 +702,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_all; } - dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n", - adap->nr, pd->bus_speed); + dev_info(&dev->dev, + "I2C adapter %d with bus speed %lu Hz (L/H=%x/%x)\n", + adap->nr, pd->bus_speed, pd->iccl, pd->icch); of_i2c_register_devices(adap); return 0; -- cgit v0.10.2 From ebd5ac165f2aaefb767c53112c2010b0ff3df688 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 24 Oct 2012 19:58:10 +0900 Subject: i2c: i2c-sh_mobile: support I2C hardware block with a faster operating clock On newer SH-/R-Mobile SoCs, a clock supply to the I2C hardware block, which is used to generate the SCL clock output, is getting faster than before, while on the other hand, the SCL clock control registers, ICCH and ICCL, stay unchanged in 9-bit-wide (8+1). On such silicons, the internal SCL clock counter gets incremented every 2 clocks of the operating clock. This patch makes it configurable through platform data. Signed-off-by: Shinya Kuribayashi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 4dc0cc3..4c28358 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -120,6 +120,7 @@ struct sh_mobile_i2c_data { void __iomem *reg; struct i2c_adapter adap; unsigned long bus_speed; + unsigned int clks_per_count; struct clk *clk; u_int8_t icic; u_int8_t flags; @@ -231,6 +232,7 @@ static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) /* Get clock rate after clock is enabled */ clk_enable(pd->clk); i2c_clk_khz = clk_get_rate(pd->clk) / 1000; + i2c_clk_khz /= pd->clks_per_count; if (pd->bus_speed == STANDARD_MODE) { tLOW = 47; /* tLOW = 4.7 us */ @@ -658,6 +660,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->bus_speed = STANDARD_MODE; if (pdata && pdata->bus_speed) pd->bus_speed = pdata->bus_speed; + pd->clks_per_count = 1; + if (pdata && pdata->clks_per_count) + pd->clks_per_count = pdata->clks_per_count; /* The IIC blocks on SH-Mobile ARM processors * come with two new bits in ICIC. diff --git a/include/linux/i2c/i2c-sh_mobile.h b/include/linux/i2c/i2c-sh_mobile.h index beda708..06e3089 100644 --- a/include/linux/i2c/i2c-sh_mobile.h +++ b/include/linux/i2c/i2c-sh_mobile.h @@ -5,6 +5,7 @@ struct i2c_sh_mobile_platform_data { unsigned long bus_speed; + unsigned int clks_per_count; }; #endif /* __I2C_SH_MOBILE_H__ */ -- cgit v0.10.2 From 29fb08c300b5cb626b8a803440aab25d0983cab7 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 24 Oct 2012 19:58:31 +0900 Subject: i2c: i2c-sh_mobile: fix spurious transfer request timed out Ensure that any of preceding register write operations to the I2C hardware block reached the module, and the write data is reflected in the registers, before leaving the interrupt handler. Otherwise, we'll suffer from spurious WAIT interrupts that lead to 'Transfer request timed out' message, and the transaction failed. Reported-by: Teppei Kamijou Signed-off-by: Shinya Kuribayashi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 4c28358..9411c1b 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -469,6 +469,9 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) wake_up(&pd->wait); } + /* defeat write posting to avoid spurious WAIT interrupts */ + iic_rd(pd, ICSR); + return IRQ_HANDLED; } -- cgit v0.10.2 From 9b7a0c40de6c5c04371f8cdb9153a0a5a0af5243 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 25 Oct 2012 18:23:53 +0200 Subject: i2c: mux: Add dt support to i2c-mux-gpio driver Allow the i2c-mux-gpio to be used by a device tree enabled device. The bindings are inspired by the one found in the i2c-mux-pinctrl driver. Signed-off-by: Maxime Ripard Reviewed-by: Stephen Warren Acked-by: Peter Korsgaard [wsa: fixed some whitespace] Signed-off-by: Wolfram Sang diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt new file mode 100644 index 0000000..66709a8 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt @@ -0,0 +1,81 @@ +GPIO-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses GPIOs to +route the I2C signals. + + +-----+ +-----+ + | dev | | dev | + +------------+ +-----+ +-----+ + | SoC | | | + | | /--------+--------+ + | +------+ | +------+ child bus A, on GPIO value set to 0 + | | I2C |-|--| Mux | + | +------+ | +--+---+ child bus B, on GPIO value set to 1 + | | | \----------+--------+--------+ + | +------+ | | | | | + | | GPIO |-|-----+ +-----+ +-----+ +-----+ + | +------+ | | dev | | dev | | dev | + +------------+ +-----+ +-----+ +-----+ + +Required properties: +- compatible: i2c-mux-gpio +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. +- mux-gpios: list of gpios used to control the muxer +* Standard I2C mux properties. See mux.txt in this directory. +* I2C child bus nodes. See mux.txt in this directory. + +Optional properties: +- idle-state: value to set the muxer to when idle. When no value is + given, it defaults to the last value used. + +For each i2c child node, an I2C child bus will be created. They will +be numbered based on their order in the device tree. + +Whenever an access is made to a device on a child bus, the value set +in the revelant node's reg property will be output using the list of +GPIOs, the first in the list holding the least-significant value. + +If an idle state is defined, using the idle-state (optional) property, +whenever an access is not being made to a device on a child bus, the +GPIOs will be set according to the idle value. + +If an idle state is not defined, the most recently used value will be +left programmed into hardware whenever no access is being made to a +device on a child bus. + +Example: + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; + i2c-parent = <&i2c1>; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + compatible = "solomon,ssd1307fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7 1>; + reset-active-low; + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + pca9555: pca9555@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 566a675..3b7bc06 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include struct gpiomux { struct i2c_adapter *parent; @@ -57,29 +59,110 @@ static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, return !strcmp(chip->label, data); } +#ifdef CONFIG_OF +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *adapter_np, *child; + struct i2c_adapter *adapter; + unsigned *values, *gpios; + int i = 0; + + if (!np) + return -ENODEV; + + adapter_np = of_parse_phandle(np, "i2c-parent", 0); + if (!adapter_np) { + dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); + return -ENODEV; + } + adapter = of_find_i2c_adapter_by_node(adapter_np); + if (!adapter) { + dev_err(&pdev->dev, "Cannot find parent bus\n"); + return -ENODEV; + } + mux->data.parent = i2c_adapter_id(adapter); + put_device(&adapter->dev); + + mux->data.n_values = of_get_child_count(np); + + values = devm_kzalloc(&pdev->dev, + sizeof(*mux->data.values) * mux->data.n_values, + GFP_KERNEL); + if (!values) { + dev_err(&pdev->dev, "Cannot allocate values array"); + return -ENOMEM; + } + + for_each_child_of_node(np, child) { + of_property_read_u32(child, "reg", values + i); + i++; + } + mux->data.values = values; + + if (of_property_read_u32(np, "idle-state", &mux->data.idle)) + mux->data.idle = I2C_MUX_GPIO_NO_IDLE; + + mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios"); + if (mux->data.n_gpios < 0) { + dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n"); + return -EINVAL; + } + + gpios = devm_kzalloc(&pdev->dev, + sizeof(*mux->data.gpios) * mux->data.n_gpios, GFP_KERNEL); + if (!gpios) { + dev_err(&pdev->dev, "Cannot allocate gpios array"); + return -ENOMEM; + } + + for (i = 0; i < mux->data.n_gpios; i++) + gpios[i] = of_get_named_gpio(np, "mux-gpios", i); + + mux->data.gpios = gpios; + + return 0; +} +#else +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + return 0; +} +#endif + static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) { struct gpiomux *mux; - struct i2c_mux_gpio_platform_data *pdata; struct i2c_adapter *parent; int (*deselect) (struct i2c_adapter *, void *, u32); unsigned initial_state, gpio_base; int i, ret; - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Missing platform data\n"); - return -ENODEV; + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); + if (!mux) { + dev_err(&pdev->dev, "Cannot allocate gpiomux structure"); + return -ENOMEM; } + platform_set_drvdata(pdev, mux); + + if (!pdev->dev.platform_data) { + ret = i2c_mux_gpio_probe_dt(mux, pdev); + if (ret < 0) + return ret; + } else + memcpy(&mux->data, pdev->dev.platform_data, sizeof(mux->data)); + /* * If a GPIO chip name is provided, the GPIO pin numbers provided are * relative to its base GPIO number. Otherwise they are absolute. */ - if (pdata->gpio_chip) { + if (mux->data.gpio_chip) { struct gpio_chip *gpio; - gpio = gpiochip_find(pdata->gpio_chip, + gpio = gpiochip_find(mux->data.gpio_chip, match_gpio_chip_by_label); if (!gpio) return -EPROBE_DEFER; @@ -89,49 +172,44 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) gpio_base = 0; } - parent = i2c_get_adapter(pdata->parent); + parent = i2c_get_adapter(mux->data.parent); if (!parent) { dev_err(&pdev->dev, "Parent adapter (%d) not found\n", - pdata->parent); + mux->data.parent); return -ENODEV; } - mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); - if (!mux) { - ret = -ENOMEM; - goto alloc_failed; - } - mux->parent = parent; - mux->data = *pdata; mux->gpio_base = gpio_base; + mux->adap = devm_kzalloc(&pdev->dev, - sizeof(*mux->adap) * pdata->n_values, + sizeof(*mux->adap) * mux->data.n_values, GFP_KERNEL); if (!mux->adap) { + dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure"); ret = -ENOMEM; goto alloc_failed; } - if (pdata->idle != I2C_MUX_GPIO_NO_IDLE) { - initial_state = pdata->idle; + if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) { + initial_state = mux->data.idle; deselect = i2c_mux_gpio_deselect; } else { - initial_state = pdata->values[0]; + initial_state = mux->data.values[0]; deselect = NULL; } - for (i = 0; i < pdata->n_gpios; i++) { - ret = gpio_request(gpio_base + pdata->gpios[i], "i2c-mux-gpio"); + for (i = 0; i < mux->data.n_gpios; i++) { + ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio"); if (ret) goto err_request_gpio; - gpio_direction_output(gpio_base + pdata->gpios[i], + gpio_direction_output(gpio_base + mux->data.gpios[i], initial_state & (1 << i)); } - for (i = 0; i < pdata->n_values; i++) { - u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0; - unsigned int class = pdata->classes ? pdata->classes[i] : 0; + for (i = 0; i < mux->data.n_values; i++) { + u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; + unsigned int class = mux->data.classes ? mux->data.classes[i] : 0; mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, i, class, @@ -144,19 +222,17 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%d port mux on %s adapter\n", - pdata->n_values, parent->name); - - platform_set_drvdata(pdev, mux); + mux->data.n_values, parent->name); return 0; add_adapter_failed: for (; i > 0; i--) i2c_del_mux_adapter(mux->adap[i - 1]); - i = pdata->n_gpios; + i = mux->data.n_gpios; err_request_gpio: for (; i > 0; i--) - gpio_free(gpio_base + pdata->gpios[i - 1]); + gpio_free(gpio_base + mux->data.gpios[i - 1]); alloc_failed: i2c_put_adapter(parent); @@ -180,12 +256,19 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id i2c_mux_gpio_of_match[] __devinitconst = { + { .compatible = "i2c-mux-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match); + static struct platform_driver i2c_mux_gpio_driver = { .probe = i2c_mux_gpio_probe, .remove = __devexit_p(i2c_mux_gpio_remove), .driver = { .owner = THIS_MODULE, .name = "i2c-mux-gpio", + .of_match_table = of_match_ptr(i2c_mux_gpio_of_match), }, }; -- cgit v0.10.2 From ca796f85901880c1247e19053d70b640f996813e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 6 Nov 2012 22:55:26 +0100 Subject: mtd: diskonchip: don't warn about ARM architecture Enabling the diskonchip drivers on most architectures results in a pointless warning "#warning Unknown architecture for DiskOnChip. No default probe locations defined". The driver can in fact handle the default location already through the CONFIG_MTD_DOCPROBE_ADDRESS, which gets set on the platforms that need it, and we get a run-time error if this is not set correctly. Signed-off-by: Arnd Bergmann Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index 706b847..88b3fd3 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -70,8 +70,6 @@ static unsigned long __initdata doc_locations[] = { 0xe0000, 0xe2000, 0xe4000, 0xe6000, 0xe8000, 0xea000, 0xec000, 0xee000, #endif /* CONFIG_MTD_DOCPROBE_HIGH */ -#else -#warning Unknown architecture for DiskOnChip. No default probe locations defined #endif 0xffffffff }; diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 256eb30..81fa578 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -53,8 +53,6 @@ static unsigned long __initdata doc_locations[] = { 0xe0000, 0xe2000, 0xe4000, 0xe6000, 0xe8000, 0xea000, 0xec000, 0xee000, #endif /* CONFIG_MTD_DOCPROBE_HIGH */ -#else -#warning Unknown architecture for DiskOnChip. No default probe locations defined #endif 0xffffffff }; -- cgit v0.10.2 From d611d41b46c96195b9a168a21992782458826e07 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 6 Nov 2012 22:55:27 +0100 Subject: mtd: diskonchip: use inline functions for DocRead/DocWrite The diskonchip drivers traditionally use home-grown macros for doing MMIO accesses, which cause a lot of warnings, at least on ARM machines: drivers/mtd/devices/doc2000.c: In function 'doc_write': drivers/mtd/devices/doc2000.c:854:5: warning: value computed is not used [-Wunused-value] drivers/mtd/devices/doc2000.c: In function 'doc_erase': drivers/mtd/devices/doc2000.c:1123:5: warning: value computed is not used [-Wunused-value drivers/mtd/nand/diskonchip.c: In function 'doc2000_read_byte': drivers/mtd/nand/diskonchip.c:318:3: warning: value computed is not used [-Wunused-value] A nicer solution is to use the architecture-defined I/O accessors. Here, we use the __raw_readl/__raw_writel style, instead of the proper readl/writel ones, in order to preserve the odd semantics of the existing macros that have their own barrier implementation and no byte swap. It would be nice to fix this properly and use the correct accessors as well as make the word size independent from the architecture, but I guess the hardware is obsolete enough that we should better not mess the driver an more than necessary. Signed-off-by: Arnd Bergmann Signed-off-by: Artem Bityutskiy diff --git a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h index 0f6fea7..407d1e5 100644 --- a/include/linux/mtd/doc2000.h +++ b/include/linux/mtd/doc2000.h @@ -92,12 +92,26 @@ * Others use readb/writeb */ #if defined(__arm__) -#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)))) -#define WriteDOC_(d, adr, reg) do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0) +static inline u8 ReadDOC_(u32 __iomem *addr, unsigned long reg) +{ + return __raw_readl(addr + reg); +} +static inline void WriteDOC_(u8 data, u32 __iomem *addr, unsigned long reg) +{ + __raw_writel(data, addr + reg); + wmb(); +} #define DOC_IOREMAP_LEN 0x8000 #elif defined(__ppc__) -#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)))) -#define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0) +static inline u8 ReadDOC_(u16 __iomem *addr, unsigned long reg) +{ + return __raw_readw(addr + reg); +} +static inline void WriteDOC_(u8 data, u16 __iomem *addr, unsigned long reg) +{ + __raw_writew(data, addr + reg); + wmb(); +} #define DOC_IOREMAP_LEN 0x4000 #else #define ReadDOC_(adr, reg) readb((void __iomem *)(adr) + (reg)) -- cgit v0.10.2 From 5d27aa5af04f58f3020de1c224dcf8a62151fd58 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 6 Nov 2012 22:55:28 +0100 Subject: mtd: uninitialized variable warning in map.h The map_word_load() function initializes exactly as many words in the buffer as required, but gcc cannot figure this out and gives a misleading warning. Marking the local variable as uninitialized_var shuts up that warning. Without this patch, building acs5k_defconfig results in: drivers/mtd/chips/cfi_cmdset_0002.c: In function 'cfi_amdstd_panic_write': include/linux/mtd/map.h:331:11: warning: 'r.x[0]' may be used uninitialized in this function [-Wuninitialized] drivers/mtd/chips/cfi_cmdset_0002.c: In function 'cfi_amdstd_write_words': include/linux/mtd/map.h:331:11: warning: 'r.x[0]' may be used uninitialized in this function [-Wuninitialized] drivers/mtd/chips/cfi_cmdset_0001.c: In function 'cfi_intelext_write_words': include/linux/mtd/map.h:331:11: warning: 'r.x[0]' may be used uninitialized in this function [-Wuninitialized] Signed-off-by: Arnd Bergmann Signed-off-by: Artem Bityutskiy diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 56c7936..f6eb433 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -391,7 +391,7 @@ static inline map_word map_word_ff(struct map_info *map) static inline map_word inline_map_read(struct map_info *map, unsigned long ofs) { - map_word r; + map_word uninitialized_var(r); if (map_bankwidth_is_1(map)) r.x[0] = __raw_readb(map->virt + ofs); -- cgit v0.10.2 From d6ba745d0a073a0f48053fa4744ab2e86c310aad Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Thu, 8 Nov 2012 13:42:59 +0530 Subject: mtd: fsl_ifc_nand: wait tWB time, poll R/B before command execution IFC_FIR_OP_CMD0 issues command for execution without checking flash readiness. It may cause problem if flash is not ready. Instead use IFC_FIR_OP_CW0 which Wait for tWB time and poll R/B to return high or time-out, before issuing command. NAND_CMD_READID command implemention does not fulfill above requirement. So update its programming. Signed-off-by: Prabhakar Kushwaha Signed-off-by: Hemant Nautiyal Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 3551a99..5315231 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -389,7 +389,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, timing = IFC_FIR_OP_RBCD; out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | (timing << IFC_NAND_FIR0_OP2_SHIFT)); out_be32(&ifc->ifc_nand.nand_fcr0, @@ -754,7 +754,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) /* READID */ out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); out_be32(&ifc->ifc_nand.nand_fcr0, -- cgit v0.10.2 From d68cbdd4fb04d2b756ad53c22f36943167b16340 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Wed, 7 Nov 2012 16:32:16 +0100 Subject: mtd: physmap_of: allow to specify the mtd name for retro compatiblity linux,mtd-name allow to specify the mtd name for retro capability with physmap-flash drivers as boot loader pass the mtd partition via the old device name physmap-flash. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Artem Bityutskiy diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt index 94de19b..dab7847 100644 --- a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt +++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt @@ -23,6 +23,9 @@ file systems on embedded devices. unaligned accesses as implemented in the JFFS2 code via memcpy(). By defining "no-unaligned-direct-access", the flash will not be exposed directly to the MTD users (e.g. JFFS2) any more. + - linux,mtd-name: allow to specify the mtd name for retro capability with + physmap-flash drivers as boot loader pass the mtd partition via the old + device name physmap-flash. For JEDEC compatible devices, the following additional properties are defined: diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 6f19aca..d7f19bc 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -170,6 +170,7 @@ static int __devinit of_flash_probe(struct platform_device *dev) resource_size_t res_size; struct mtd_part_parser_data ppdata; bool map_indirect; + const char *mtd_name; match = of_match_device(of_flash_match, &dev->dev); if (!match) @@ -178,6 +179,8 @@ static int __devinit of_flash_probe(struct platform_device *dev) reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32); + of_property_read_string(dp, "linux,mtd-name", &mtd_name); + /* * Get number of "reg" tuples. Scan for MTD devices on area's * described by each "reg" region. This makes it possible (including @@ -234,7 +237,7 @@ static int __devinit of_flash_probe(struct platform_device *dev) goto err_out; } - info->list[i].map.name = dev_name(&dev->dev); + info->list[i].map.name = mtd_name ?: dev_name(&dev->dev); info->list[i].map.phys = res.start; info->list[i].map.size = res_size; info->list[i].map.bankwidth = be32_to_cpup(width); -- cgit v0.10.2 From 2935e0e05a3e348f046f1b485e933b85d1479aaa Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 5 Nov 2012 09:33:38 +0100 Subject: i2c: s3c2410: Refactor ifdefs for PM_SLEEP Use the PM_SLEEP ifdef for system suspend and resume. This is partly in preparation for adding runtime operations and partly because a user may in theory choose to enable runtime suspend but not system suspend. Signed-off-by: Mark Brown Reviewed-by: Shubhrajyoti D Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3e0335f..f01cdf3 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1118,7 +1118,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int s3c24xx_i2c_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -1141,10 +1141,14 @@ static int s3c24xx_i2c_resume(struct device *dev) return 0; } +#endif +#ifdef CONFIG_PM static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = { +#ifdef CONFIG_PM_SLEEP .suspend_noirq = s3c24xx_i2c_suspend_noirq, .resume = s3c24xx_i2c_resume, +#endif }; #define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops) -- cgit v0.10.2 From a72ad456bb93a0114b4d6702421b35a9c548bd46 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 5 Nov 2012 09:33:39 +0100 Subject: i2c: s3c2410: Convert to devm_request_and_ioremap() A small code saving and less error handling to worry about. Signed-off-by: Mark Brown Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index f01cdf3..f82d11f 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -78,7 +78,6 @@ struct s3c24xx_i2c { void __iomem *regs; struct clk *clk; struct device *dev; - struct resource *ioarea; struct i2c_adapter adap; struct s3c2410_platform_i2c *pdata; @@ -988,25 +987,16 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) goto err_clk; } - i2c->ioarea = request_mem_region(res->start, resource_size(res), - pdev->name); - - if (i2c->ioarea == NULL) { - dev_err(&pdev->dev, "cannot request IO\n"); - ret = -ENXIO; - goto err_clk; - } - - i2c->regs = ioremap(res->start, resource_size(res)); + i2c->regs = devm_request_and_ioremap(&pdev->dev, res); if (i2c->regs == NULL) { dev_err(&pdev->dev, "cannot map IO\n"); ret = -ENXIO; - goto err_ioarea; + goto err_clk; } - dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", - i2c->regs, i2c->ioarea, res); + dev_dbg(&pdev->dev, "registers %p (%p)\n", + i2c->regs, res); /* setup info block for the i2c core */ @@ -1017,7 +1007,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = s3c24xx_i2c_init(i2c); if (ret != 0) - goto err_iomap; + goto err_clk; /* find the IRQ for this unit (note, this relies on the init call to * ensure no current IRQs pending @@ -1026,7 +1016,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->irq = ret = platform_get_irq(pdev, 0); if (ret <= 0) { dev_err(&pdev->dev, "cannot find IRQ\n"); - goto err_iomap; + goto err_clk; } ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0, @@ -1034,7 +1024,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); - goto err_iomap; + goto err_clk; } ret = s3c24xx_i2c_register_cpufreq(i2c); @@ -1074,13 +1064,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) err_irq: free_irq(i2c->irq, i2c); - err_iomap: - iounmap(i2c->regs); - - err_ioarea: - release_resource(i2c->ioarea); - kfree(i2c->ioarea); - err_clk: clk_disable_unprepare(i2c->clk); clk_put(i2c->clk); @@ -1109,11 +1092,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) clk_disable_unprepare(i2c->clk); clk_put(i2c->clk); - iounmap(i2c->regs); - - release_resource(i2c->ioarea); s3c24xx_i2c_dt_gpio_free(i2c); - kfree(i2c->ioarea); return 0; } -- cgit v0.10.2 From 2693ac69880a33d4d9df6f128415b65e745f00ba Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 13 Nov 2012 11:33:40 +0100 Subject: i2c: s3c2410: Add support for pinctrl This patch adds support for pin configuration using pinctrl subsystem to the i2c-s3c2410 driver. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Signed-off-by: Wolfram Sang diff --git a/Documentation/devicetree/bindings/i2c/samsung-i2c.txt b/Documentation/devicetree/bindings/i2c/samsung-i2c.txt index b6cb5a1..e9611ac 100644 --- a/Documentation/devicetree/bindings/i2c/samsung-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/samsung-i2c.txt @@ -13,11 +13,17 @@ Required properties: - interrupts: interrupt number to the cpu. - samsung,i2c-sda-delay: Delay (in ns) applied to data line (SDA) edges. +Required for all cases except "samsung,s3c2440-hdmiphy-i2c": + - Samsung GPIO variant (deprecated): + - gpios: The order of the gpios should be the following: . + The gpio specifier depends on the gpio controller. Required in all + cases except for "samsung,s3c2440-hdmiphy-i2c" whose input/output + lines are permanently wired to the respective clienta + - Pinctrl variant (preferred, if available): + - pinctrl-0: Pin control group to be used for this controller. + - pinctrl-names: Should contain only one value - "default". + Optional properties: - - gpios: The order of the gpios should be the following: . - The gpio specifier depends on the gpio controller. Required in all - cases except for "samsung,s3c2440-hdmiphy-i2c" whose input/output - lines are permanently wired to the respective client - samsung,i2c-slave-addr: Slave address in multi-master enviroment. If not specified, default value is 0. - samsung,i2c-max-bus-freq: Desired frequency in Hz of the bus. If not @@ -31,8 +37,14 @@ Example: interrupts = <345>; samsung,i2c-sda-delay = <100>; samsung,i2c-max-bus-freq = <100000>; + /* Samsung GPIO variant begins here */ gpios = <&gpd1 2 0 /* SDA */ &gpd1 3 0 /* SCL */>; + /* Samsung GPIO variant ends here */ + /* Pinctrl variant begins here */ + pinctrl-0 = <&i2c3_bus>; + pinctrl-names = "default"; + /* Pinctrl variant ends here */ #address-cells = <1>; #size-cells = <0>; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index f82d11f..40e2d40 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -82,6 +83,7 @@ struct s3c24xx_i2c { struct s3c2410_platform_i2c *pdata; int gpios[2]; + struct pinctrl *pctrl; #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif @@ -860,9 +862,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) if (pdata->cfg_gpio) pdata->cfg_gpio(to_platform_device(i2c->dev)); - else - if (s3c24xx_i2c_parse_dt_gpio(i2c)) - return -EINVAL; + else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) + return -EINVAL; /* write slave address */ @@ -1003,6 +1004,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &pdev->dev; + i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev); + /* initialise the i2c controller */ ret = s3c24xx_i2c_init(i2c); @@ -1092,7 +1095,8 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) clk_disable_unprepare(i2c->clk); clk_put(i2c->clk); - s3c24xx_i2c_dt_gpio_free(i2c); + if (pdev->dev.of_node && IS_ERR(i2c->pctrl)) + s3c24xx_i2c_dt_gpio_free(i2c); return 0; } -- cgit v0.10.2 From 9bcd04bfbbd5599de011176b846ed00ac15a234c Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 15 Nov 2012 17:43:30 +0530 Subject: i2c: s3c2410: grab adapter lock while changing i2c clock We probably don't want to change I2C frequency while a transfer is in progress. The current implementation grabs a spinlock, but that only protected the writes to IICCON when starting a message, it didn't protect against clock changes in the middle of a transaction. Note: The i2c-core already grabs the adapter lock before calling s3c24xx_i2c_doxfer(), which ensures that only one caller is issuing a xfer at a time. This means it is not necessary to disable interrupts (spin_lock_irqsave) when changing frequencies, since there won't be any i2c interrupts if there is no on-going xfer. Lastly, i2c_lock_adapter() may cause the cpufreq_transition to sleep if if a xfer is in progress, but this is ok since cpufreq notifiers are called in a kernel thread, and there are already cases where it could sleep, such as when using i2c to update the output of a voltage regulator. Note: the cpufreq part of this change has no functional affect on exynos, where the i2c clock is independent of the cpufreq. But, there is a slight perfomance boost since we no longer need to lock/unlock an additional spinlock. Signed-off-by: Daniel Kurtz Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 40e2d40..86e60f5 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -60,7 +60,6 @@ enum s3c24xx_i2c_state { }; struct s3c24xx_i2c { - spinlock_t lock; wait_queue_head_t wait; unsigned int quirks; unsigned int suspended:1; @@ -541,8 +540,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, goto out; } - spin_lock_irq(&i2c->lock); - i2c->msg = msgs; i2c->msg_num = num; i2c->msg_ptr = 0; @@ -551,7 +548,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, s3c24xx_i2c_enable_irq(i2c); s3c24xx_i2c_message_start(i2c, msgs); - spin_unlock_irq(&i2c->lock); timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); @@ -741,7 +737,6 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data) { struct s3c24xx_i2c *i2c = freq_to_i2c(nb); - unsigned long flags; unsigned int got; int delta_f; int ret; @@ -755,9 +750,9 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) || (val == CPUFREQ_PRECHANGE && delta_f > 0)) { - spin_lock_irqsave(&i2c->lock, flags); + i2c_lock_adapter(&i2c->adap); ret = s3c24xx_i2c_clockrate(i2c, &got); - spin_unlock_irqrestore(&i2c->lock, flags); + i2c_unlock_adapter(&i2c->adap); if (ret < 0) dev_err(i2c->dev, "cannot find frequency\n"); @@ -962,7 +957,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; i2c->tx_setup = 50; - spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); /* find the clock and enable it */ -- cgit v0.10.2 From 0da2e7768b4c2b4dbbb148ebe1606b6b4698fca2 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 15 Nov 2012 17:43:31 +0530 Subject: i2c: s3c2410: do not generate STOP for QUIRK_HDMIPHY The datasheet says that the STOP sequence should be: 1) I2CSTAT.5 = 0 - Clear BUSY (or 'generate STOP') 2) I2CCON.4 = 0 - Clear IRQPEND 3) Wait until the stop condition takes effect. 4*) I2CSTAT.4 = 0 - Clear TXRXEN Where, step "4*" is only for buses with the "HDMIPHY" quirk. However, after much experimentation, it appears that: a) normal buses automatically clear BUSY and transition from Master->Slave when they complete generating a STOP condition. Therefore, step (3) can be done in doxfer() by polling I2CCON.4 after starting the STOP generation here. b) HDMIPHY bus does neither, so there is no way to do step 3. There is no indication when this bus has finished generating STOP. In fact, we have found that as soon as the IRQPEND bit is cleared in step 2, the HDMIPHY bus generates the STOP condition, and then immediately starts transferring another data byte, even though the bus is supposedly stopped. This is presumably because the bus is still in "Master" mode, and its BUSY bit is still set. To avoid these extra post-STOP transactions on HDMI phy devices, we just disable Serial Output on the bus (I2CSTAT.4 = 0) directly, instead of first generating a proper STOP condition. This should float SDA & SCK terminating the transfer. Subsequent transfers start with a proper START condition, and proceed normally. The HDMIPHY bus is an internal bus that always has exactly two devices, the host as Master and the HDMIPHY device as the slave. Skipping the STOP condition has been tested on this bus and works. Also, since we disable the bus directly from the isr, we can skip the bus idle polling loop at the end of doxfer(). Signed-off-by: Daniel Kurtz Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 86e60f5..a44e213 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -235,8 +235,47 @@ static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret) dev_dbg(i2c->dev, "STOP\n"); - /* stop the transfer */ - iicstat &= ~S3C2410_IICSTAT_START; + /* + * The datasheet says that the STOP sequence should be: + * 1) I2CSTAT.5 = 0 - Clear BUSY (or 'generate STOP') + * 2) I2CCON.4 = 0 - Clear IRQPEND + * 3) Wait until the stop condition takes effect. + * 4*) I2CSTAT.4 = 0 - Clear TXRXEN + * + * Where, step "4*" is only for buses with the "HDMIPHY" quirk. + * + * However, after much experimentation, it appears that: + * a) normal buses automatically clear BUSY and transition from + * Master->Slave when they complete generating a STOP condition. + * Therefore, step (3) can be done in doxfer() by polling I2CCON.4 + * after starting the STOP generation here. + * b) HDMIPHY bus does neither, so there is no way to do step 3. + * There is no indication when this bus has finished generating + * STOP. + * + * In fact, we have found that as soon as the IRQPEND bit is cleared in + * step 2, the HDMIPHY bus generates the STOP condition, and then + * immediately starts transferring another data byte, even though the + * bus is supposedly stopped. This is presumably because the bus is + * still in "Master" mode, and its BUSY bit is still set. + * + * To avoid these extra post-STOP transactions on HDMI phy devices, we + * just disable Serial Output on the bus (I2CSTAT.4 = 0) directly, + * instead of first generating a proper STOP condition. This should + * float SDA & SCK terminating the transfer. Subsequent transfers + * start with a proper START condition, and proceed normally. + * + * The HDMIPHY bus is an internal bus that always has exactly two + * devices, the host as Master and the HDMIPHY device as the slave. + * Skipping the STOP condition has been tested on this bus and works. + */ + if (i2c->quirks & QUIRK_HDMIPHY) { + /* Stop driving the I2C pins */ + iicstat &= ~S3C2410_IICSTAT_TXRXEN; + } else { + /* stop the transfer */ + iicstat &= ~S3C2410_IICSTAT_START; + } writel(iicstat, i2c->regs + S3C2410_IICSTAT); i2c->state = STATE_STOP; @@ -561,6 +600,10 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, else if (ret != num) dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); + /* For QUIRK_HDMIPHY, bus is already disabled */ + if (i2c->quirks & QUIRK_HDMIPHY) + goto out; + /* ensure the stop has been through the bus */ dev_dbg(i2c->dev, "waiting for bus idle\n"); -- cgit v0.10.2 From fe724bf9f023384eb14431c0e49ec46017ba8e30 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 15 Nov 2012 17:43:32 +0530 Subject: i2c: s3c2410: use exponential back off while polling for bus idle Usually, the i2c controller has finished emitting the i2c STOP before the driver reaches the bus idle polling loop. Optimize for this most common case by reading IICSTAT first and potentially skipping the loop. If the cpu is faster than the hardware, we wait for bus idle in a polling loop. However, since the duration of one iteration of the loop is dependent on cpu freq, and this i2c IP is used on many different systems, use a time based loop timeout (5 ms). We would like very low latencies to detect bus idle for the normal 'fast' case. However, if a device is slow to release the bus for some reason, it could hold off the STOP generation for up to several milliseconds. Rapidly polling for bus idle would seriously load the CPU while waiting for it to release the bus. So, use a partial exponential backoff as a compromise between idle detection latency and cpu load. Signed-off-by: Daniel Kurtz Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index a44e213..dd93d3d 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -50,6 +50,9 @@ #define QUIRK_HDMIPHY (1 << 1) #define QUIRK_NO_GPIO (1 << 2) +/* Max time to wait for bus to become idle after a xfer (in us) */ +#define S3C2410_IDLE_TIMEOUT 5000 + /* i2c controller state */ enum s3c24xx_i2c_state { STATE_IDLE, @@ -557,6 +560,48 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) return -ETIMEDOUT; } +/* s3c24xx_i2c_wait_idle + * + * wait for the i2c bus to become idle. +*/ + +static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c) +{ + unsigned long iicstat; + ktime_t start, now; + unsigned long delay; + + /* ensure the stop has been through the bus */ + + dev_dbg(i2c->dev, "waiting for bus idle\n"); + + start = now = ktime_get(); + + /* + * Most of the time, the bus is already idle within a few usec of the + * end of a transaction. However, really slow i2c devices can stretch + * the clock, delaying STOP generation. + * + * As a compromise between idle detection latency for the normal, fast + * case, and system load in the slow device case, use an exponential + * back off in the polling loop, up to 1/10th of the total timeout, + * then continue to poll at a constant rate up to the timeout. + */ + iicstat = readl(i2c->regs + S3C2410_IICSTAT); + delay = 1; + while ((iicstat & S3C2410_IICSTAT_START) && + ktime_us_delta(now, start) < S3C2410_IDLE_TIMEOUT) { + usleep_range(delay, 2 * delay); + if (delay < S3C2410_IDLE_TIMEOUT / 10) + delay <<= 1; + now = ktime_get(); + iicstat = readl(i2c->regs + S3C2410_IICSTAT); + } + + if (iicstat & S3C2410_IICSTAT_START) + dev_warn(i2c->dev, "timeout waiting for bus idle\n"); +} + /* s3c24xx_i2c_doxfer * * this starts an i2c transfer @@ -565,8 +610,7 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num) { - unsigned long iicstat, timeout; - int spins = 20; + unsigned long timeout; int ret; if (i2c->suspended) @@ -604,24 +648,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, if (i2c->quirks & QUIRK_HDMIPHY) goto out; - /* ensure the stop has been through the bus */ - - dev_dbg(i2c->dev, "waiting for bus idle\n"); - - /* first, try busy waiting briefly */ - do { - cpu_relax(); - iicstat = readl(i2c->regs + S3C2410_IICSTAT); - } while ((iicstat & S3C2410_IICSTAT_START) && --spins); - - /* if that timed out sleep */ - if (!spins) { - msleep(1); - iicstat = readl(i2c->regs + S3C2410_IICSTAT); - } - - if (iicstat & S3C2410_IICSTAT_START) - dev_warn(i2c->dev, "timeout waiting for bus idle\n"); + s3c24xx_i2c_wait_idle(i2c); out: return ret; -- cgit v0.10.2 From 79f678edfe48db1f234b8de41e24987d6d25ac1a Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 15 Nov 2012 17:43:33 +0530 Subject: i2c: s3c2410: do not special case HDMIPHY stuck bus detection Commit "i2c-s3c2410: Add HDMIPHY quirk for S3C2440" added support for HDMIPHY with some special handling in s3c24xx_i2c_set_master: "due to unknown reason (probably HW bug in HDMIPHY and/or the controller) a transfer fails to finish. The controller hangs after sending the last byte, the workaround for this bug is resetting the controller after each transfer" The "unknown reason" was that the proper sequence for generating a STOP condition wasn't being followed as per the datasheet. Since this is fixed by "PATCH: i2c-s3c2410: do not generate STOP for QUIRK_HDMIPHY buses", remove the special handling. Signed-off-by: Daniel Kurtz Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index dd93d3d..081e261 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -532,13 +532,6 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) unsigned long iicstat; int timeout = 400; - /* the timeout for HDMIPHY is reduced to 10 ms because - * the hangup is expected to happen, so waiting 400 ms - * causes only unnecessary system hangup - */ - if (i2c->quirks & QUIRK_HDMIPHY) - timeout = 10; - while (timeout-- > 0) { iicstat = readl(i2c->regs + S3C2410_IICSTAT); @@ -548,15 +541,6 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c) msleep(1); } - /* hang-up of bus dedicated for HDMIPHY occurred, resetting */ - if (i2c->quirks & QUIRK_HDMIPHY) { - writel(0, i2c->regs + S3C2410_IICCON); - writel(0, i2c->regs + S3C2410_IICSTAT); - writel(0, i2c->regs + S3C2410_IICDS); - - return 0; - } - return -ETIMEDOUT; } -- cgit v0.10.2 From 06e9eff129ec4251e5335ecaebe1aabba78091b6 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 25 Oct 2012 18:23:54 +0200 Subject: ARM: dts: cfa10049: Add the i2c muxer buses to the CFA-10049 This will allow to add the 3 Nuvoton NAU7802 ADCs and the NXP PCA9555 GPIO expander eventually. Signed-off-by: Maxime Ripard Acked-by: Shawn Guo Signed-off-by: Wolfram Sang diff --git a/arch/arm/boot/dts/imx28-cfa10049.dts b/arch/arm/boot/dts/imx28-cfa10049.dts index 05c892e..319a6db 100644 --- a/arch/arm/boot/dts/imx28-cfa10049.dts +++ b/arch/arm/boot/dts/imx28-cfa10049.dts @@ -70,6 +70,30 @@ status = "okay"; }; + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; + i2c-parent = <&i2c1>; + + i2c@0 { + reg = <0>; + }; + + i2c@1 { + reg = <1>; + }; + + i2c@2 { + reg = <2>; + }; + + i2c@3 { + reg = <3>; + }; + }; + usbphy1: usbphy@8007e000 { status = "okay"; }; -- cgit v0.10.2 From 1ab3604595af478e9feea430318c22899015550c Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Thu, 15 Nov 2012 14:19:21 +0530 Subject: i2c: omap: Move the remove constraint Currently we just queue the transfer and release the qos constraints, however we do not wait for the transfer to complete to release the constraint. Move the remove constraint after the bus busy as we are sure that the transfers are completed by then. Acked-by: Jean Pihet Signed-off-by: Shubhrajyoti D Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 49b12fb..2482801 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -654,13 +654,14 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) break; } - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, -1); - if (r == 0) r = num; omap_i2c_wait_for_bb(dev); + + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, -1); + out: pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); -- cgit v0.10.2 From f5f35a92e44a1f70fd8c77a42339318a5c8d9eb7 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 15 Nov 2012 16:50:58 +0100 Subject: i2c: ocores: Add irq support for sparc Add sparc support by using platform_get_irq instead of platform_get_resource. There are no platform resources of type IORESOURCE_IRQ for sparc, but platform_get_irq works for sparc. In the non-sparc case platform_get_irq internally uses platform_get_resource. Signed-off-by: Andreas Larsson Acked-by: Peter Korsgaard Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 1fad4ae..dafd26b 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -267,7 +267,8 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) { struct ocores_i2c *i2c; struct ocores_i2c_platform_data *pdata; - struct resource *res, *res2; + struct resource *res; + int irq; int ret; int i; @@ -275,9 +276,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) if (!res) return -ENODEV; - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) - return -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) @@ -304,7 +305,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) ocores_init(i2c); init_waitqueue_head(&i2c->wait); - ret = devm_request_irq(&pdev->dev, res2->start, ocores_isr, 0, + ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, pdev->name, i2c); if (ret) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); -- cgit v0.10.2 From a000b8c1e30115800d3de86b4b058cadd9cba59d Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Thu, 15 Nov 2012 16:50:59 +0100 Subject: i2c: ocores: Add support for the GRLIB port of the controller and use function pointers for getreg and setreg functions The registers in the GRLIB port of the controller are 32-bit and in big endian byte order. The PRELOW and PREHIGH registers are merged into one register. The subsequent registers have their offset decreased accordingly. Hence the register access needs to be handled in a non-standard manner using custom getreg and setreg functions. Add setreg and getreg functions for different register widths and let oc_setreg and oc_getreg use function pointers to call the appropriate functions. A type is added as the data of the of match table entries. A new entry with a different compatible string is added to the table. The type of that entry triggers usage of the custom grlib functions by setting the setreg and getreg function pointers. Signed-off-by: Andreas Larsson Signed-off-by: Wolfram Sang diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt index c15781f..1637c29 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -1,7 +1,7 @@ Device tree configuration for i2c-ocores Required properties: -- compatible : "opencores,i2c-ocores" +- compatible : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst" - reg : bus address start and address range size of device - interrupts : interrupt number - clock-frequency : frequency of bus clock in Hz diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index dafd26b..0ea8419 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -4,6 +4,9 @@ * * Peter Korsgaard * + * Support for the GRLIB port of the controller by + * Andreas Larsson + * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. @@ -38,6 +41,8 @@ struct ocores_i2c { int nmsgs; int state; /* see STATE_ */ int clock_khz; + void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); + u8 (*getreg)(struct ocores_i2c *i2c, int reg); }; /* registers */ @@ -71,24 +76,81 @@ struct ocores_i2c { #define STATE_READ 3 #define STATE_ERROR 4 -static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) +#define TYPE_OCORES 0 +#define TYPE_GRLIB 1 + +static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) { - if (i2c->reg_io_width == 4) - iowrite32(value, i2c->base + (reg << i2c->reg_shift)); - else if (i2c->reg_io_width == 2) - iowrite16(value, i2c->base + (reg << i2c->reg_shift)); + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg) +{ + return ioread8(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg) +{ + return ioread16(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) +{ + return ioread32(i2c->base + (reg << i2c->reg_shift)); +} + +/* Read and write functions for the GRLIB port of the controller. Registers are + * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one + * register. The subsequent registers has their offset decreased accordingly. */ +static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) +{ + u32 rd; + int rreg = reg; + if (reg != OCI2C_PRELOW) + rreg--; + rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PREHIGH) + return (u8)(rd >> 8); else - iowrite8(value, i2c->base + (reg << i2c->reg_shift)); + return (u8)rd; +} + +static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) +{ + u32 curr, wr; + int rreg = reg; + if (reg != OCI2C_PRELOW) + rreg--; + if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { + curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PRELOW) + wr = (curr & 0xff00) | value; + else + wr = (((u32)value) << 8) | (curr & 0xff); + } else { + wr = value; + } + iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); +} + +static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) +{ + i2c->setreg(i2c, reg, value); } static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) { - if (i2c->reg_io_width == 4) - return ioread32(i2c->base + (reg << i2c->reg_shift)); - else if (i2c->reg_io_width == 2) - return ioread16(i2c->base + (reg << i2c->reg_shift)); - else - return ioread8(i2c->base + (reg << i2c->reg_shift)); + return i2c->getreg(i2c, reg); } static void ocores_process(struct ocores_i2c *i2c) @@ -227,11 +289,25 @@ static struct i2c_adapter ocores_adapter = { .algo = &ocores_algorithm, }; +static struct of_device_id ocores_i2c_match[] = { + { + .compatible = "opencores,i2c-ocores", + .data = (void *)TYPE_OCORES, + }, + { + .compatible = "aeroflexgaisler,i2cmst", + .data = (void *)TYPE_GRLIB, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ocores_i2c_match); + #ifdef CONFIG_OF static int ocores_i2c_of_probe(struct platform_device *pdev, struct ocores_i2c *i2c) { struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; u32 val; if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { @@ -257,6 +333,14 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, of_property_read_u32(pdev->dev.of_node, "reg-io-width", &i2c->reg_io_width); + + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (int)match->data == TYPE_GRLIB) { + dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n"); + i2c->setreg = oc_setreg_grlib; + i2c->getreg = oc_getreg_grlib; + } + return 0; } #else @@ -302,6 +386,30 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) if (i2c->reg_io_width == 0) i2c->reg_io_width = 1; /* Set to default value */ + if (!i2c->setreg || !i2c->getreg) { + switch (i2c->reg_io_width) { + case 1: + i2c->setreg = oc_setreg_8; + i2c->getreg = oc_getreg_8; + break; + + case 2: + i2c->setreg = oc_setreg_16; + i2c->getreg = oc_getreg_16; + break; + + case 4: + i2c->setreg = oc_setreg_32; + i2c->getreg = oc_getreg_32; + break; + + default: + dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", + i2c->reg_io_width); + return -EINVAL; + } + } + ocores_init(i2c); init_waitqueue_head(&i2c->wait); @@ -379,12 +487,6 @@ static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); #define OCORES_I2C_PM NULL #endif -static struct of_device_id ocores_i2c_match[] = { - { .compatible = "opencores,i2c-ocores", }, - {}, -}; -MODULE_DEVICE_TABLE(of, ocores_i2c_match); - static struct platform_driver ocores_i2c_driver = { .probe = ocores_i2c_probe, .remove = __devexit_p(ocores_i2c_remove), -- cgit v0.10.2 From bfe0fb0f1a570ae72680d6d48655c98d1f4733f5 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Sat, 3 Nov 2012 17:00:07 -0600 Subject: dma-debug: fix to not have dependency on get_dma_ops() interface dma-debug depends on get_dma_ops() interface. Several architectures do not define dma_ops and get_dma_ops(). When dma debug interfaces are used on an architecture (e.g: c6x) that doesn't define get_dmap_ops(), compilation fails. Changing dma-debug to call dma_mapping_error() instead of defining its own that calls get_dma_ops(), such that the internal use of dma_mapping_error() doesn't interfere with the debug_dma_mapping_error() interface's mapping error checks. Moving dma_mapping_error() checks in check_unmap() under the dma debug entry not found is sufficient to fix the problem. Reference: https://lkml.org/lkml/2012/10/26/367 Signed-off-by: Shuah Khan Reported-by: Mark Salter Signed-off-by: Joerg Roedel diff --git a/lib/dma-debug.c b/lib/dma-debug.c index 59f4a1a..5e396ac 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -852,37 +852,22 @@ static __init int dma_debug_entries_cmdline(char *str) __setup("dma_debug=", dma_debug_cmdline); __setup("dma_debug_entries=", dma_debug_entries_cmdline); -/* Calling dma_mapping_error() from dma-debug api will result in calling - debug_dma_mapping_error() - need internal mapping error routine to - avoid debug checks */ -#ifndef DMA_ERROR_CODE -#define DMA_ERROR_CODE 0 -#endif -static inline int has_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - const struct dma_map_ops *ops = get_dma_ops(dev); - if (ops->mapping_error) - return ops->mapping_error(dev, dma_addr); - - return (dma_addr == DMA_ERROR_CODE); -} - static void check_unmap(struct dma_debug_entry *ref) { struct dma_debug_entry *entry; struct hash_bucket *bucket; unsigned long flags; - if (unlikely(has_mapping_error(ref->dev, ref->dev_addr))) { - err_printk(ref->dev, NULL, "DMA-API: device driver tries " - "to free an invalid DMA memory address\n"); - return; - } - bucket = get_hash_bucket(ref, &flags); entry = bucket_find_exact(bucket, ref); if (!entry) { + if (dma_mapping_error(ref->dev, ref->dev_addr)) { + err_printk(ref->dev, NULL, + "DMA-API: device driver tries " + "to free an invalid DMA memory address\n"); + return; + } err_printk(ref->dev, NULL, "DMA-API: device driver tries " "to free DMA memory it has not allocated " "[device address=0x%016llx] [size=%llu bytes]\n", @@ -1055,7 +1040,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, if (unlikely(global_disable)) return; - if (unlikely(has_mapping_error(dev, dma_addr))) + if (dma_mapping_error(dev, dma_addr)) return; entry = dma_entry_alloc(); -- cgit v0.10.2 From 5d346d103355a0ea1ccc40b7ac0659326cb74077 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 25 Oct 2012 18:31:42 -0600 Subject: sparc: dma-mapping: support debug_dma_mapping_error Add support for debug_dma_mapping_error() call to avoid warning from debug_dma_unmap() interface when it checks for mapping error checked status. Without this patch, device driver failed to check map error warning is generated. Signed-off-by: Shuah Khan Acked-by: David S. Miller Signed-off-by: Joerg Roedel diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 8493fd3..05fe53f 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -59,6 +59,7 @@ static inline void dma_free_attrs(struct device *dev, size_t size, static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { + debug_dma_mapping_error(dev, dma_addr); return (dma_addr == DMA_ERROR_CODE); } -- cgit v0.10.2 From 2cbba75a56ea78e6876b4e2547a882f10b3fe72b Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Mon, 5 Nov 2012 22:40:14 +0400 Subject: jffs2: hold erase_completion_lock on exit Users of jffs2_do_reserve_space() expect they still held erase_completion_lock after call to it. But there is a path where jffs2_do_reserve_space() leaves erase_completion_lock unlocked. The patch fixes it. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Cc: stable@vger.kernel.org Signed-off-by: Artem Bityutskiy diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 0c96eb5..0331072 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -417,14 +417,16 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, spin_unlock(&c->erase_completion_lock); ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); - if (ret) - return ret; + /* Just lock it again and continue. Nothing much can change because we hold c->alloc_sem anyway. In fact, it's not entirely clear why we hold c->erase_completion_lock in the majority of this function... but that's a question for another (more caffeine-rich) day. */ spin_lock(&c->erase_completion_lock); + if (ret) + return ret; + waste = jeb->free_size; jffs2_link_node_ref(c, jeb, (jeb->offset + c->sector_size - waste) | REF_OBSOLETE, -- cgit v0.10.2 From ded4c55d108e0e4e4ba221b39a782e85d77a5ca0 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 16 Nov 2012 16:08:22 +0530 Subject: mtd: s3c2410: Fix potential NULL pointer dereference error 'set' is tested for NULL. But subsequently accessed without the check. Thus making it conditional to avoid NULL pointer dereferencing. Signed-off-by: Sachin Kamat Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 295e4be..bbc49c4 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -730,11 +730,14 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *mtd, struct s3c2410_nand_set *set) { - if (set) + if (set) { mtd->mtd.name = set->name; - return mtd_device_parse_register(&mtd->mtd, NULL, NULL, + return mtd_device_parse_register(&mtd->mtd, NULL, NULL, set->partitions, set->nr_partitions); + } + + return -ENODEV; } /** -- cgit v0.10.2 From 07300164657526d8d26c626c43723c310fbf3616 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 9 Nov 2012 16:23:45 +0800 Subject: mtd: de-select the chip when it is not used When we scan several nand chips with nand_scan(), such as ....................... nand_scan(*, 2); ....................... In nand_scan_ident(), the maxchips will become 2, so the current code will select chip 1 to read the device ID. But the chip 0 is still selected in this case. To make the logic clear, we'd better de-select the chip when it is not used. This patch de-select the nand chip if it is not used any more. Signed-off-by: Huang Shijie Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 0150540..95d56ed 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3329,6 +3329,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, return PTR_ERR(type); } + chip->select_chip(mtd, -1); + /* Check for a chip array */ for (i = 1; i < maxchips; i++) { chip->select_chip(mtd, i); @@ -3338,8 +3340,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ if (nand_maf_id != chip->read_byte(mtd) || - nand_dev_id != chip->read_byte(mtd)) + nand_dev_id != chip->read_byte(mtd)) { + chip->select_chip(mtd, -1); break; + } + chip->select_chip(mtd, -1); } if (i > 1) pr_info("%d NAND chips detected\n", i); @@ -3598,9 +3603,6 @@ int nand_scan_tail(struct mtd_info *mtd) /* Initialize state */ chip->state = FL_READY; - /* De-select the device */ - chip->select_chip(mtd, -1); - /* Invalidate the pagebuffer reference */ chip->pagebuf = -1; -- cgit v0.10.2 From 064a7694b5347208febeb7aba7c90d38934ec8a1 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Fri, 9 Nov 2012 23:20:58 +0900 Subject: mtd: Fix typo mtd/tests Correct spelling typo in printk within drivers/mtd/tests. Signed-off-by: Masanari Iida Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 95d56ed..6eef7fb 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -160,7 +160,7 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) } /** - * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip * @mtd: MTD device structure * diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c index e86bb29..e827fa8 100644 --- a/drivers/mtd/tests/mtd_oobtest.c +++ b/drivers/mtd/tests/mtd_oobtest.c @@ -366,8 +366,8 @@ static int __init mtd_oobtest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - pr_info("Please specify a valid mtd-device via module paramter\n"); - pr_crit(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + pr_info("Please specify a valid mtd-device via module parameter\n"); + pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c index 3ba2a77..f93a76f 100644 --- a/drivers/mtd/tests/mtd_pagetest.c +++ b/drivers/mtd/tests/mtd_pagetest.c @@ -499,7 +499,7 @@ static int __init mtd_pagetest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_info("Please specify a valid mtd-device via module parameter\n"); pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c index ec3efb5..31f505c 100644 --- a/drivers/mtd/tests/mtd_readtest.c +++ b/drivers/mtd/tests/mtd_readtest.c @@ -171,7 +171,7 @@ static int __init mtd_readtest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_info("Please specify a valid mtd-device via module parameter\n"); return -EINVAL; } diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 8a5803b..596cbea 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -351,7 +351,7 @@ static int __init mtd_speedtest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_info("Please specify a valid mtd-device via module parameter\n"); pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c index fea1dd7..3729f67 100644 --- a/drivers/mtd/tests/mtd_stresstest.c +++ b/drivers/mtd/tests/mtd_stresstest.c @@ -231,7 +231,7 @@ static int __init mtd_stresstest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_info("Please specify a valid mtd-device via module parameter\n"); pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c index 8813b0e..c880c22 100644 --- a/drivers/mtd/tests/mtd_subpagetest.c +++ b/drivers/mtd/tests/mtd_subpagetest.c @@ -377,7 +377,7 @@ static int __init mtd_subpagetest_init(void) printk(KERN_INFO "=================================================\n"); if (dev < 0) { - pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_info("Please specify a valid mtd-device via module parameter\n"); pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c index 98d2a82..c4cde1e 100644 --- a/drivers/mtd/tests/mtd_torturetest.c +++ b/drivers/mtd/tests/mtd_torturetest.c @@ -216,7 +216,7 @@ static int __init tort_init(void) "flash, stop it if this is not wanted.\n"); if (dev < 0) { - pr_info("Please specify a valid mtd-device via module paramter\n"); + pr_info("Please specify a valid mtd-device via module parameter\n"); pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } -- cgit v0.10.2 From 0857ba3c24c308f42a242fe8a1894772750230ce Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 18 Nov 2012 18:36:19 +0200 Subject: i2c: i2c-cbus-gpio: introduce driver Add i2c driver to enable access to devices behind CBUS on Nokia Internet Tablets. The patch also adds CBUS I2C configuration for N8x0 which is one of the users of this driver. Acked-by: Felipe Balbi Acked-by: Tony Lindgren Signed-off-by: Aaro Koskinen Signed-off-by: Wolfram Sang diff --git a/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt new file mode 100644 index 0000000..8ce9cd2 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt @@ -0,0 +1,27 @@ +Device tree bindings for i2c-cbus-gpio driver + +Required properties: + - compatible = "i2c-cbus-gpio"; + - gpios: clk, dat, sel + - #address-cells = <1>; + - #size-cells = <0>; + +Optional properties: + - child nodes conforming to i2c bus binding + +Example: + +i2c@0 { + compatible = "i2c-cbus-gpio"; + gpios = <&gpio 66 0 /* clk */ + &gpio 65 0 /* dat */ + &gpio 64 0 /* sel */ + >; + #address-cells = <1>; + #size-cells = <0>; + + retu-mfd: retu@1 { + compatible = "retu-mfd"; + reg = <0x1>; + }; +}; diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index d95f727..bbfd742 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -16,10 +16,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -39,6 +41,45 @@ #define TUSB6010_GPIO_ENABLE 0 #define TUSB6010_DMACHAN 0x3f +#if defined(CONFIG_I2C_CBUS_GPIO) || defined(CONFIG_I2C_CBUS_GPIO_MODULE) +static struct i2c_cbus_platform_data n8x0_cbus_data = { + .clk_gpio = 66, + .dat_gpio = 65, + .sel_gpio = 64, +}; + +static struct platform_device n8x0_cbus_device = { + .name = "i2c-cbus-gpio", + .id = 3, + .dev = { + .platform_data = &n8x0_cbus_data, + }, +}; + +static struct i2c_board_info n8x0_i2c_board_info_3[] __initdata = { + { + I2C_BOARD_INFO("retu-mfd", 0x01), + }, +}; + +static void __init n8x0_cbus_init(void) +{ + const int retu_irq_gpio = 108; + + if (gpio_request_one(retu_irq_gpio, GPIOF_IN, "Retu IRQ")) + return; + irq_set_irq_type(gpio_to_irq(retu_irq_gpio), IRQ_TYPE_EDGE_RISING); + n8x0_i2c_board_info_3[0].irq = gpio_to_irq(retu_irq_gpio); + i2c_register_board_info(3, n8x0_i2c_board_info_3, + ARRAY_SIZE(n8x0_i2c_board_info_3)); + platform_device_register(&n8x0_cbus_device); +} +#else /* CONFIG_I2C_CBUS_GPIO */ +static void __init n8x0_cbus_init(void) +{ +} +#endif /* CONFIG_I2C_CBUS_GPIO */ + #if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE) /* * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and @@ -677,6 +718,7 @@ static void __init n8x0_init_machine(void) gpmc_onenand_init(board_onenand_data); n8x0_mmc_init(); n8x0_usb_init(); + n8x0_cbus_init(); } MACHINE_START(NOKIA_N800, "Nokia N800") diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e9df461..e949edf 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -337,6 +337,16 @@ config I2C_BLACKFIN_TWI_CLK_KHZ help The unit of the TWI clock is kHz. +config I2C_CBUS_GPIO + tristate "CBUS I2C driver" + depends on GENERIC_GPIO + help + Support for CBUS access using I2C API. Mostly relevant for Nokia + Internet Tablets (770, N800 and N810). + + This driver can also be built as a module. If so, the module + will be called i2c-cbus-gpio. + config I2C_CPM tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)" depends on (CPM1 || CPM2) && OF_I2C diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 395b516..f9e3e0b 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o +obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o diff --git a/drivers/i2c/busses/i2c-cbus-gpio.c b/drivers/i2c/busses/i2c-cbus-gpio.c new file mode 100644 index 0000000..98386d6 --- /dev/null +++ b/drivers/i2c/busses/i2c-cbus-gpio.c @@ -0,0 +1,300 @@ +/* + * CBUS I2C driver for Nokia Internet Tablets. + * + * Copyright (C) 2004-2010 Nokia Corporation + * + * Based on code written by Juha Yrjölä, David Weinehall, Mikko Ylinen and + * Felipe Balbi. Converted to I2C driver by Aaro Koskinen. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Bit counts are derived from Nokia implementation. These should be checked + * if other CBUS implementations appear. + */ +#define CBUS_ADDR_BITS 3 +#define CBUS_REG_BITS 5 + +struct cbus_host { + spinlock_t lock; /* host lock */ + struct device *dev; + int clk_gpio; + int dat_gpio; + int sel_gpio; +}; + +/** + * cbus_send_bit - sends one bit over the bus + * @host: the host we're using + * @bit: one bit of information to send + */ +static void cbus_send_bit(struct cbus_host *host, unsigned bit) +{ + gpio_set_value(host->dat_gpio, bit ? 1 : 0); + gpio_set_value(host->clk_gpio, 1); + gpio_set_value(host->clk_gpio, 0); +} + +/** + * cbus_send_data - sends @len amount of data over the bus + * @host: the host we're using + * @data: the data to send + * @len: size of the transfer + */ +static void cbus_send_data(struct cbus_host *host, unsigned data, unsigned len) +{ + int i; + + for (i = len; i > 0; i--) + cbus_send_bit(host, data & (1 << (i - 1))); +} + +/** + * cbus_receive_bit - receives one bit from the bus + * @host: the host we're using + */ +static int cbus_receive_bit(struct cbus_host *host) +{ + int ret; + + gpio_set_value(host->clk_gpio, 1); + ret = gpio_get_value(host->dat_gpio); + gpio_set_value(host->clk_gpio, 0); + return ret; +} + +/** + * cbus_receive_word - receives 16-bit word from the bus + * @host: the host we're using + */ +static int cbus_receive_word(struct cbus_host *host) +{ + int ret = 0; + int i; + + for (i = 16; i > 0; i--) { + int bit = cbus_receive_bit(host); + + if (bit < 0) + return bit; + + if (bit) + ret |= 1 << (i - 1); + } + return ret; +} + +/** + * cbus_transfer - transfers data over the bus + * @host: the host we're using + * @rw: read/write flag + * @dev: device address + * @reg: register address + * @data: if @rw == I2C_SBUS_WRITE data to send otherwise 0 + */ +static int cbus_transfer(struct cbus_host *host, char rw, unsigned dev, + unsigned reg, unsigned data) +{ + unsigned long flags; + int ret; + + /* We don't want interrupts disturbing our transfer */ + spin_lock_irqsave(&host->lock, flags); + + /* Reset state and start of transfer, SEL stays down during transfer */ + gpio_set_value(host->sel_gpio, 0); + + /* Set the DAT pin to output */ + gpio_direction_output(host->dat_gpio, 1); + + /* Send the device address */ + cbus_send_data(host, dev, CBUS_ADDR_BITS); + + /* Send the rw flag */ + cbus_send_bit(host, rw == I2C_SMBUS_READ); + + /* Send the register address */ + cbus_send_data(host, reg, CBUS_REG_BITS); + + if (rw == I2C_SMBUS_WRITE) { + cbus_send_data(host, data, 16); + ret = 0; + } else { + ret = gpio_direction_input(host->dat_gpio); + if (ret) { + dev_dbg(host->dev, "failed setting direction\n"); + goto out; + } + gpio_set_value(host->clk_gpio, 1); + + ret = cbus_receive_word(host); + if (ret < 0) { + dev_dbg(host->dev, "failed receiving data\n"); + goto out; + } + } + + /* Indicate end of transfer, SEL goes up until next transfer */ + gpio_set_value(host->sel_gpio, 1); + gpio_set_value(host->clk_gpio, 1); + gpio_set_value(host->clk_gpio, 0); + +out: + spin_unlock_irqrestore(&host->lock, flags); + + return ret; +} + +static int cbus_i2c_smbus_xfer(struct i2c_adapter *adapter, + u16 addr, + unsigned short flags, + char read_write, + u8 command, + int size, + union i2c_smbus_data *data) +{ + struct cbus_host *chost = i2c_get_adapdata(adapter); + int ret; + + if (size != I2C_SMBUS_WORD_DATA) + return -EINVAL; + + ret = cbus_transfer(chost, read_write == I2C_SMBUS_READ, addr, + command, data->word); + if (ret < 0) + return ret; + + if (read_write == I2C_SMBUS_READ) + data->word = ret; + + return 0; +} + +static u32 cbus_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; +} + +static const struct i2c_algorithm cbus_i2c_algo = { + .smbus_xfer = cbus_i2c_smbus_xfer, + .functionality = cbus_i2c_func, +}; + +static int cbus_i2c_remove(struct platform_device *pdev) +{ + struct i2c_adapter *adapter = platform_get_drvdata(pdev); + + return i2c_del_adapter(adapter); +} + +static int cbus_i2c_probe(struct platform_device *pdev) +{ + struct i2c_adapter *adapter; + struct cbus_host *chost; + int ret; + + adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter), + GFP_KERNEL); + if (!adapter) + return -ENOMEM; + + chost = devm_kzalloc(&pdev->dev, sizeof(*chost), GFP_KERNEL); + if (!chost) + return -ENOMEM; + + if (pdev->dev.of_node) { + struct device_node *dnode = pdev->dev.of_node; + if (of_gpio_count(dnode) != 3) + return -ENODEV; + chost->clk_gpio = of_get_gpio(dnode, 0); + chost->dat_gpio = of_get_gpio(dnode, 1); + chost->sel_gpio = of_get_gpio(dnode, 2); + } else if (pdev->dev.platform_data) { + struct i2c_cbus_platform_data *pdata = pdev->dev.platform_data; + chost->clk_gpio = pdata->clk_gpio; + chost->dat_gpio = pdata->dat_gpio; + chost->sel_gpio = pdata->sel_gpio; + } else { + return -ENODEV; + } + + adapter->owner = THIS_MODULE; + adapter->class = I2C_CLASS_HWMON; + adapter->dev.parent = &pdev->dev; + adapter->nr = pdev->id; + adapter->timeout = HZ; + adapter->algo = &cbus_i2c_algo; + strlcpy(adapter->name, "CBUS I2C adapter", sizeof(adapter->name)); + + spin_lock_init(&chost->lock); + chost->dev = &pdev->dev; + + ret = devm_gpio_request_one(&pdev->dev, chost->clk_gpio, + GPIOF_OUT_INIT_LOW, "CBUS clk"); + if (ret) + return ret; + + ret = devm_gpio_request_one(&pdev->dev, chost->dat_gpio, GPIOF_IN, + "CBUS data"); + if (ret) + return ret; + + ret = devm_gpio_request_one(&pdev->dev, chost->sel_gpio, + GPIOF_OUT_INIT_HIGH, "CBUS sel"); + if (ret) + return ret; + + i2c_set_adapdata(adapter, chost); + platform_set_drvdata(pdev, adapter); + + return i2c_add_numbered_adapter(adapter); +} + +#if defined(CONFIG_OF) +static const struct of_device_id i2c_cbus_dt_ids[] = { + { .compatible = "i2c-cbus-gpio", }, + { } +}; +MODULE_DEVICE_TABLE(of, i2c_cbus_dt_ids); +#endif + +static struct platform_driver cbus_i2c_driver = { + .probe = cbus_i2c_probe, + .remove = cbus_i2c_remove, + .driver = { + .owner = THIS_MODULE, + .name = "i2c-cbus-gpio", + }, +}; +module_platform_driver(cbus_i2c_driver); + +MODULE_ALIAS("platform:i2c-cbus-gpio"); +MODULE_DESCRIPTION("CBUS I2C driver"); +MODULE_AUTHOR("Juha Yrjölä"); +MODULE_AUTHOR("David Weinehall"); +MODULE_AUTHOR("Mikko Ylinen"); +MODULE_AUTHOR("Felipe Balbi"); +MODULE_AUTHOR("Aaro Koskinen "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/i2c-cbus-gpio.h b/include/linux/platform_data/i2c-cbus-gpio.h new file mode 100644 index 0000000..6faa992 --- /dev/null +++ b/include/linux/platform_data/i2c-cbus-gpio.h @@ -0,0 +1,27 @@ +/* + * i2c-cbus-gpio.h - CBUS I2C platform_data definition + * + * Copyright (C) 2004-2009 Nokia Corporation + * + * Written by Felipe Balbi and Aaro Koskinen. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __INCLUDE_LINUX_I2C_CBUS_GPIO_H +#define __INCLUDE_LINUX_I2C_CBUS_GPIO_H + +struct i2c_cbus_platform_data { + int dat_gpio; + int clk_gpio; + int sel_gpio; +}; + +#endif /* __INCLUDE_LINUX_I2C_CBUS_GPIO_H */ -- cgit v0.10.2 From 3b2f3ceb3c7f4a8c2d11aa7652842e5ce1b0dcc3 Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Mon, 19 Nov 2012 15:48:46 +0530 Subject: i2c: s3c2410: Fix code to free gpios Store the requested gpios so that they can be freed on error/removal. Signed-off-by: Abhilash Kesavan Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 081e261..16592e5 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -856,6 +856,7 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio); goto free_gpio; } + i2c->gpios[idx] = gpio; ret = gpio_request(gpio, "i2c-bus"); if (ret) { -- cgit v0.10.2 From 658122fe5e3a72940631ceda3efcb841054d91dc Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Mon, 19 Nov 2012 15:47:17 +0530 Subject: i2c: s3c2410: Add fix for i2c suspend/resume The I2C driver makes a gpio_request during initialization. This request happens again on resume and fails due to the earlier successful request. Re-factor the code to only initialize the gpios during probe. Errors on resume without this: [ 16.020000] s3c-i2c s3c2440-i2c.0: gpio [42] request failed [ 16.020000] s3c-i2c s3c2440-i2c.1: gpio [44] request failed [ 16.020000] s3c-i2c s3c2440-i2c.2: gpio [6] request failed Signed-off-by: Abhilash Kesavan Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 16592e5..d784c76 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -908,13 +908,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) pdata = i2c->pdata; - /* inititalise the gpio */ - - if (pdata->cfg_gpio) - pdata->cfg_gpio(to_platform_device(i2c->dev)); - else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) - return -EINVAL; - /* write slave address */ writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD); @@ -1055,6 +1048,15 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev); + /* inititalise the i2c gpio lines */ + + if (i2c->pdata->cfg_gpio) { + i2c->pdata->cfg_gpio(to_platform_device(i2c->dev)); + } else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) { + ret = -EINVAL; + goto err_clk; + } + /* initialise the i2c controller */ ret = s3c24xx_i2c_init(i2c); -- cgit v0.10.2 From 717a9ef7f355480686cdbac3f32d6075437a923e Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 18 Jul 2012 11:56:01 -0700 Subject: tracing: Remove unneeded checks from the stack tracer It seems that 'ftrace_enabled' flag should not be used inside the tracer functions. The ftrace core is using this flag for internal purposes, and the flag wasn't meant to be used in tracers' runtime checks. stack tracer is the only tracer that abusing the flag. So stop it from serving as a bad example. Also, there is a local 'stack_trace_disabled' flag in the stack tracer, which is never updated; so it can be removed as well. Link: http://lkml.kernel.org/r/1342637761-9655-1-git-send-email-anton.vorontsov@linaro.org Signed-off-by: Anton Vorontsov Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 0c1b1657..42ca822 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -33,7 +33,6 @@ static unsigned long max_stack_size; static arch_spinlock_t max_stack_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; -static int stack_trace_disabled __read_mostly; static DEFINE_PER_CPU(int, trace_active); static DEFINE_MUTEX(stack_sysctl_mutex); @@ -116,9 +115,6 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip, { int cpu; - if (unlikely(!ftrace_enabled || stack_trace_disabled)) - return; - preempt_disable_notrace(); cpu = raw_smp_processor_id(); -- cgit v0.10.2 From bf3071f5a054db9e5bab873355d27a7330ce5187 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 25 Jul 2012 11:39:08 -0400 Subject: tracing: Remove unnecessary WARN_ONCE's from tracing_buffers_splice_read WARN shouldn't be used as a means of communicating failure to a userspace programmer. Link: http://lkml.kernel.org/r/20120725153908.GA25203@redhat.com Signed-off-by: Dave Jones Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 64ad9bc..5bc3590 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4275,13 +4275,11 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, return -ENOMEM; if (*ppos & (PAGE_SIZE - 1)) { - WARN_ONCE(1, "Ftrace: previous read must page-align\n"); ret = -EINVAL; goto out; } if (len & (PAGE_SIZE - 1)) { - WARN_ONCE(1, "Ftrace: splice_read should page-align\n"); if (len < PAGE_SIZE) { ret = -EINVAL; goto out; -- cgit v0.10.2 From 16f890988114a1b2d7abb30dafb708d4513801da Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 15 Oct 2012 13:49:12 +0100 Subject: kbuild: Remove reference to uninitialised variable Verbose output variable is unnecessary because the command's echo is already surpressed. Additionally because the block defines skip-makefile the variable Q is not defined within the makefile, which can cause problems if Q is defined in the users environment. Signed-off-by: Charles Keepax Signed-off-by: Michal Marek diff --git a/Makefile b/Makefile index 5be2ee8..6744909 100644 --- a/Makefile +++ b/Makefile @@ -124,7 +124,7 @@ $(if $(KBUILD_OUTPUT),, \ PHONY += $(MAKECMDGOALS) sub-make $(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make - $(Q)@: + @: sub-make: FORCE $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \ -- cgit v0.10.2 From fc96b211bc6fa917bfb07a8db4cd898663e5f2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Bie=C3=9Fmann?= Date: Thu, 18 Oct 2012 11:08:49 +0200 Subject: scripts/pnmtologo: fix for plain PBM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PBM generated with current tools do not have a whitespace between the digits. Therefore the pnmtologo tool fails to gernerate the required C-Array for these images. This patch fixes that behaviour and can handle both 'old style' and 'new style' PBM files. Signed-off-by: Andreas Bießmann Signed-off-by: Michal Marek diff --git a/scripts/pnmtologo.c b/scripts/pnmtologo.c index 5c11312..68bb4ef 100644 --- a/scripts/pnmtologo.c +++ b/scripts/pnmtologo.c @@ -74,6 +74,7 @@ static unsigned int logo_height; static struct color **logo_data; static struct color logo_clut[MAX_LINUX_LOGO_COLORS]; static unsigned int logo_clutsize; +static int is_plain_pbm = 0; static void die(const char *fmt, ...) __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2))); @@ -103,6 +104,11 @@ static unsigned int get_number(FILE *fp) val = 0; while (isdigit(c)) { val = 10*val+c-'0'; + /* some PBM are 'broken'; GiMP for example exports a PBM without space + * between the digits. This is Ok cause we know a PBM can only have a '1' + * or a '0' for the digit. */ + if (is_plain_pbm) + break; c = fgetc(fp); if (c == EOF) die("%s: end of file\n", filename); @@ -167,6 +173,7 @@ static void read_image(void) switch (magic) { case '1': /* Plain PBM */ + is_plain_pbm = 1; for (i = 0; i < logo_height; i++) for (j = 0; j < logo_width; j++) logo_data[i][j].red = logo_data[i][j].green = -- cgit v0.10.2 From 6bdb5f213c4344324f600dde885f25768fbd14db Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Mon, 12 Nov 2012 16:55:38 -0500 Subject: NFS: Add sequence_priviliged_ops for nfs4_proc_sequence() If I mount an NFS v4.1 server to a single client multiple times and then run xfstests over each mountpoint I usually get the client into a state where recovery deadlocks. The server informs the client of a cb_path_down sequence error, the client then does a bind_connection_to_session and checks the status of the lease. I found that bind_connection_to_session sets the NFS4_SESSION_DRAINING flag on the client, but this flag is never unset before nfs4_check_lease() reaches nfs4_proc_sequence(). This causes the client to deadlock, halting all NFS activity to the server. nfs4_proc_sequence() is only called by the state manager, so I can change it to run in privileged mode to bypass the NFS4_SESSION_DRAINING check and avoid the deadlock. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust Cc: stable@vger.kernel.org diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6300cdd..a32d953 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -6136,13 +6136,26 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data) rpc_call_start(task); } +static void nfs41_sequence_prepare_privileged(struct rpc_task *task, void *data) +{ + rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); + nfs41_sequence_prepare(task, data); +} + static const struct rpc_call_ops nfs41_sequence_ops = { .rpc_call_done = nfs41_sequence_call_done, .rpc_call_prepare = nfs41_sequence_prepare, .rpc_release = nfs41_sequence_release, }; -static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) +static const struct rpc_call_ops nfs41_sequence_privileged_ops = { + .rpc_call_done = nfs41_sequence_call_done, + .rpc_call_prepare = nfs41_sequence_prepare_privileged, + .rpc_release = nfs41_sequence_release, +}; + +static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred, + const struct rpc_call_ops *seq_ops) { struct nfs4_sequence_data *calldata; struct rpc_message msg = { @@ -6152,7 +6165,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_ struct rpc_task_setup task_setup_data = { .rpc_client = clp->cl_rpcclient, .rpc_message = &msg, - .callback_ops = &nfs41_sequence_ops, + .callback_ops = seq_ops, .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT, }; @@ -6179,7 +6192,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0) return 0; - task = _nfs41_proc_sequence(clp, cred); + task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_ops); if (IS_ERR(task)) ret = PTR_ERR(task); else @@ -6193,7 +6206,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) struct rpc_task *task; int ret; - task = _nfs41_proc_sequence(clp, cred); + task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_privileged_ops); if (IS_ERR(task)) { ret = PTR_ERR(task); goto out; -- cgit v0.10.2 From 4a83eecff65bd327bf5cb3b400b96fa975c73308 Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Tue, 20 Nov 2012 22:49:31 -0800 Subject: Input: matrix-keypad - add device tree support Also the driver was modifued to take advantage of recent improvements in matrix_keypad_build_keymap() implementation, which automatically allocates memory for keymap. The driver was tested on AM335x EVM. Signed-off-by: AnilKumar Ch Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov diff --git a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt new file mode 100644 index 0000000..ead641c --- /dev/null +++ b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt @@ -0,0 +1,46 @@ +* GPIO driven matrix keypad device tree bindings + +GPIO driven matrix keypad is used to interface a SoC with a matrix keypad. +The matrix keypad supports multiple row and column lines, a key can be +placed at each intersection of a unique row and a unique column. The matrix +keypad can sense a key-press and key-release by means of GPIO lines and +report the event using GPIO interrupts to the cpu. + +Required Properties: +- compatible: Should be "gpio-matrix-keypad" +- row-gpios: List of gpios used as row lines. The gpio specifier + for this property depends on the gpio controller to + which these row lines are connected. +- col-gpios: List of gpios used as column lines. The gpio specifier + for this property depends on the gpio controller to + which these column lines are connected. +- linux,keymap: The definition can be found at + bindings/input/matrix-keymap.txt + +Optional Properties: +- linux,no-autorepeat: do no enable autorepeat feature. +- linux,wakeup: use any event on keypad as wakeup event. +- debounce-delay-ms: debounce interval in milliseconds +- col-scan-delay-us: delay, measured in microseconds, that is needed + before we can scan keypad after activating column gpio + +Example: + matrix-keypad { + compatible = "gpio-matrix-keypad"; + debounce-delay-ms = <5>; + col-scan-delay-us = <2>; + + row-gpios = <&gpio2 25 0 + &gpio2 26 0 + &gpio2 27 0>; + + col-gpios = <&gpio2 21 0 + &gpio2 22 0>; + + linux,keymap = <0x0000008B + 0x0100009E + 0x02000069 + 0x0001006A + 0x0101001C + 0x0201006C>; + }; diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 18b7237..05d3a96 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include struct matrix_keypad { const struct matrix_keypad_platform_data *pdata; @@ -37,8 +40,6 @@ struct matrix_keypad { bool scan_pending; bool stopped; bool gpio_all_disabled; - - unsigned short keycodes[]; }; /* @@ -118,6 +119,7 @@ static void matrix_keypad_scan(struct work_struct *work) struct matrix_keypad *keypad = container_of(work, struct matrix_keypad, work.work); struct input_dev *input_dev = keypad->input_dev; + const unsigned short *keycodes = input_dev->keycode; const struct matrix_keypad_platform_data *pdata = keypad->pdata; uint32_t new_state[MATRIX_MAX_COLS]; int row, col, code; @@ -153,7 +155,7 @@ static void matrix_keypad_scan(struct work_struct *work) code = MATRIX_SCAN_CODE(row, col, keypad->row_shift); input_event(input_dev, EV_MSC, MSC_SCAN, code); input_report_key(input_dev, - keypad->keycodes[code], + keycodes[code], new_state[col] & (1 << row)); } } @@ -394,33 +396,95 @@ static void matrix_keypad_free_gpio(struct matrix_keypad *keypad) gpio_free(pdata->col_gpios[i]); } +#ifdef CONFIG_OF +static struct matrix_keypad_platform_data * __devinit +matrix_keypad_parse_dt(struct device *dev) +{ + struct matrix_keypad_platform_data *pdata; + struct device_node *np = dev->of_node; + unsigned int *gpios; + int i; + + if (!np) { + dev_err(dev, "device lacks DT data\n"); + return ERR_PTR(-ENODEV); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "could not allocate memory for platform data\n"); + return ERR_PTR(-ENOMEM); + } + + pdata->num_row_gpios = of_gpio_named_count(np, "row-gpios"); + pdata->num_col_gpios = of_gpio_named_count(np, "col-gpios"); + if (!pdata->num_row_gpios || !pdata->num_col_gpios) { + dev_err(dev, "number of keypad rows/columns not specified\n"); + return ERR_PTR(-EINVAL); + } + + if (of_get_property(np, "linux,no-autorepeat", NULL)) + pdata->no_autorepeat = true; + if (of_get_property(np, "linux,wakeup", NULL)) + pdata->wakeup = true; + if (of_get_property(np, "gpio-activelow", NULL)) + pdata->active_low = true; + + of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms); + of_property_read_u32(np, "col-scan-delay-us", + &pdata->col_scan_delay_us); + + gpios = devm_kzalloc(dev, + sizeof(unsigned int) * + (pdata->num_row_gpios + pdata->num_col_gpios), + GFP_KERNEL); + if (!gpios) { + dev_err(dev, "could not allocate memory for gpios\n"); + return ERR_PTR(-ENOMEM); + } + + for (i = 0; i < pdata->num_row_gpios; i++) + gpios[i] = of_get_named_gpio(np, "row-gpios", i); + + for (i = 0; i < pdata->num_col_gpios; i++) + gpios[pdata->num_row_gpios + i] = + of_get_named_gpio(np, "col-gpios", i); + + pdata->row_gpios = gpios; + pdata->col_gpios = &gpios[pdata->num_row_gpios]; + + return pdata; +} +#else +static inline struct matrix_keypad_platform_data * +matrix_keypad_parse_dt(struct device *dev) +{ + dev_err(dev, "no platform data defined\n"); + + return ERR_PTR(-EINVAL); +} +#endif + static int __devinit matrix_keypad_probe(struct platform_device *pdev) { const struct matrix_keypad_platform_data *pdata; - const struct matrix_keymap_data *keymap_data; struct matrix_keypad *keypad; struct input_dev *input_dev; - unsigned int row_shift; - size_t keymap_size; int err; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -EINVAL; - } - - keymap_data = pdata->keymap_data; - if (!keymap_data) { + pdata = matrix_keypad_parse_dt(&pdev->dev); + if (IS_ERR(pdata)) { + dev_err(&pdev->dev, "no platform data defined\n"); + return PTR_ERR(pdata); + } + } else if (!pdata->keymap_data) { dev_err(&pdev->dev, "no keymap data defined\n"); return -EINVAL; } - row_shift = get_count_order(pdata->num_col_gpios); - keymap_size = (pdata->num_row_gpios << row_shift) * - sizeof(keypad->keycodes[0]); - keypad = kzalloc(sizeof(struct matrix_keypad) + keymap_size, - GFP_KERNEL); + keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL); input_dev = input_allocate_device(); if (!keypad || !input_dev) { err = -ENOMEM; @@ -429,7 +493,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) keypad->input_dev = input_dev; keypad->pdata = pdata; - keypad->row_shift = row_shift; + keypad->row_shift = get_count_order(pdata->num_col_gpios); keypad->stopped = true; INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan); spin_lock_init(&keypad->lock); @@ -440,12 +504,14 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) input_dev->open = matrix_keypad_start; input_dev->close = matrix_keypad_stop; - err = matrix_keypad_build_keymap(keymap_data, NULL, + err = matrix_keypad_build_keymap(pdata->keymap_data, NULL, pdata->num_row_gpios, pdata->num_col_gpios, - keypad->keycodes, input_dev); - if (err) + NULL, input_dev); + if (err) { + dev_err(&pdev->dev, "failed to build keymap\n"); goto err_free_mem; + } if (!pdata->no_autorepeat) __set_bit(EV_REP, input_dev->evbit); @@ -488,6 +554,14 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id matrix_keypad_dt_match[] = { + { .compatible = "gpio-matrix-keypad" }, + { } +}; +MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match); +#endif + static struct platform_driver matrix_keypad_driver = { .probe = matrix_keypad_probe, .remove = __devexit_p(matrix_keypad_remove), @@ -495,6 +569,7 @@ static struct platform_driver matrix_keypad_driver = { .name = "matrix-keypad", .owner = THIS_MODULE, .pm = &matrix_keypad_pm_ops, + .of_match_table = of_match_ptr(matrix_keypad_dt_match), }, }; module_platform_driver(matrix_keypad_driver); -- cgit v0.10.2 From 5df904aeb0d9baad90e78fc730dfe1afa4996005 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 21 Nov 2012 09:22:14 -0500 Subject: NFSv4.1: Handle session reset and bind_conn_to_session before lease check We can't send a SEQUENCE op unless the session is OK, so it is pointless to handle the CHECK_LEASE state before we've dealt with SESSION_RESET and BIND_CONN_TO_SESSION. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index e0a28df..f3d1bc4 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -2114,15 +2114,6 @@ static void nfs4_state_manager(struct nfs_client *clp) continue; } - if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { - section = "check lease"; - status = nfs4_check_lease(clp); - if (status < 0) - goto out_error; - if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) - continue; - } - /* Initialize or reset the session */ if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) { section = "reset session"; @@ -2143,6 +2134,14 @@ static void nfs4_state_manager(struct nfs_client *clp) continue; } + if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { + section = "check lease"; + status = nfs4_check_lease(clp); + if (status < 0) + goto out_error; + continue; + } + /* Recall session slots */ if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)) { section = "recall slot"; -- cgit v0.10.2 From ae72ae676045274c82f3c25159a9dd7cfcf5ffae Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 11:02:55 -0500 Subject: NFSv4.1: Don't confuse CREATE_SESSION arguments and results Don't store the target request and response sizes in the same variables used to store the server's replies to those targets. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a32d953..3e572dc 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5807,8 +5807,8 @@ void nfs4_destroy_session(struct nfs4_session *session) static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) { struct nfs4_session *session = args->client->cl_session; - unsigned int mxrqst_sz = session->fc_attrs.max_rqst_sz, - mxresp_sz = session->fc_attrs.max_resp_sz; + unsigned int mxrqst_sz = session->fc_target_max_rqst_sz, + mxresp_sz = session->fc_target_max_resp_sz; if (mxrqst_sz == 0) mxrqst_sz = NFS_MAX_FILE_IO_SIZE; @@ -6015,24 +6015,28 @@ int nfs4_init_session(struct nfs_server *server) { struct nfs_client *clp = server->nfs_client; struct nfs4_session *session; - unsigned int rsize, wsize; + unsigned int target_max_rqst_sz = NFS_MAX_FILE_IO_SIZE; + unsigned int target_max_resp_sz = NFS_MAX_FILE_IO_SIZE; if (!nfs4_has_session(clp)) return 0; + if (server->rsize != 0) + target_max_resp_sz = server->rsize; + target_max_resp_sz += nfs41_maxread_overhead; + + if (server->wsize != 0) + target_max_rqst_sz = server->wsize; + target_max_rqst_sz += nfs41_maxwrite_overhead; + session = clp->cl_session; spin_lock(&clp->cl_lock); if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) { - - rsize = server->rsize; - if (rsize == 0) - rsize = NFS_MAX_FILE_IO_SIZE; - wsize = server->wsize; - if (wsize == 0) - wsize = NFS_MAX_FILE_IO_SIZE; - - session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead; - session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead; + /* Initialise targets and channel attributes */ + session->fc_target_max_rqst_sz = target_max_rqst_sz; + session->fc_attrs.max_rqst_sz = target_max_rqst_sz; + session->fc_target_max_resp_sz = target_max_resp_sz; + session->fc_attrs.max_resp_sz = target_max_resp_sz; } spin_unlock(&clp->cl_lock); diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index a9e76ee..97c8f91 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -242,6 +242,9 @@ struct nfs4_session { struct nfs4_channel_attrs bc_attrs; struct nfs4_slot_table bc_slot_table; struct nfs_client *clp; + /* Create session arguments */ + unsigned int fc_target_max_rqst_sz; + unsigned int fc_target_max_resp_sz; }; #endif /* CONFIG_NFS_V4 */ -- cgit v0.10.2 From 688a9024e2bc8d07cdc62e287dfb048722cf96df Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 10:53:39 -0500 Subject: NFSv4.1: Adjust CREATE_SESSION arguments when mounting a new filesystem If we're mounting a new filesystem, ensure that the session has negotiated large enough request and reply sizes to match the wsize and rsize mount arguments. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3e572dc..ee82cdd 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -6037,9 +6037,22 @@ int nfs4_init_session(struct nfs_server *server) session->fc_attrs.max_rqst_sz = target_max_rqst_sz; session->fc_target_max_resp_sz = target_max_resp_sz; session->fc_attrs.max_resp_sz = target_max_resp_sz; + } else { + /* Just adjust the targets */ + if (target_max_rqst_sz > session->fc_target_max_rqst_sz) { + session->fc_target_max_rqst_sz = target_max_rqst_sz; + set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); + } + if (target_max_resp_sz > session->fc_target_max_resp_sz) { + session->fc_target_max_resp_sz = target_max_resp_sz; + set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); + } } spin_unlock(&clp->cl_lock); + if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) + nfs4_schedule_lease_recovery(clp); + return nfs41_check_session_ready(clp); } -- cgit v0.10.2 From 43095d397219aa1898db23937b03c1215ef16a37 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 11:13:12 -0500 Subject: NFSv4.1: We must bump the clientid sequence number after CREATE_SESSION We must always bump the clientid sequence number after a successful call to CREATE_SESSION on the server. The result of nfs4_verify_channel_attrs() is irrelevant to that requirement. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ee82cdd..1ac339b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5917,10 +5917,9 @@ static int _nfs4_proc_create_session(struct nfs_client *clp, status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); - if (!status) + if (!status) { /* Verify the session's negotiated channel_attrs values */ status = nfs4_verify_channel_attrs(&args, session); - if (!status) { /* Increment the clientid slot sequence id */ clp->cl_seqid++; } -- cgit v0.10.2 From 2d473d378eb571ad77f9563653639aa35e22d39c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 19 Nov 2012 18:03:22 -0500 Subject: NFSv4.1: nfs4_alloc_slots doesn't need zeroing All that memory is going to be initialised to non-zero by nfs4_add_and_init_slots anyway. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1ac339b..0402ebb 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5658,7 +5658,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) static struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags) { - return kcalloc(max_slots, sizeof(struct nfs4_slot), gfp_flags); + return kmalloc_array(max_slots, sizeof(struct nfs4_slot), gfp_flags); } static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, -- cgit v0.10.2 From 9216106a847a53e6d0fe6d11dfd9175f2ca7fccf Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 19 Nov 2012 19:50:45 -0500 Subject: NFSv4.1: clean up nfs4_recall_slot to use nfs4_alloc_slots Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index a525fde..36880b9 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -258,6 +258,8 @@ extern int nfs4_proc_get_lease_time(struct nfs_client *clp, extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync); +extern struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags); + static inline bool is_ds_only_client(struct nfs_client *clp) { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0402ebb..5e5cc5a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5656,7 +5656,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) return status; } -static struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags) +struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags) { return kmalloc_array(max_slots, sizeof(struct nfs4_slot), gfp_flags); } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index f3d1bc4..96fcbb9 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -2033,8 +2033,7 @@ static int nfs4_recall_slot(struct nfs_client *clp) return 0; nfs4_begin_drain_session(clp); fc_tbl = &clp->cl_session->fc_slot_table; - new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot), - GFP_NOFS); + new = nfs4_alloc_slots(fc_tbl->target_max_slots, GFP_NOFS); if (!new) return -ENOMEM; -- cgit v0.10.2 From 933602e368c4452260c9bff4fbb3baba35cf987a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 16 Nov 2012 12:12:38 -0500 Subject: NFSv4.1: Shrink struct nfs4_sequence_res by moving sr_renewal_time Store the renewal time inside the session slot instead. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5e5cc5a..14b3974 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -486,6 +486,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) { + struct nfs4_slot *slot; unsigned long timestamp; struct nfs_client *clp; @@ -502,12 +503,14 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * if (!RPC_WAS_SENT(task)) goto out; + slot = res->sr_slot; + /* Check the SEQUENCE operation status */ switch (res->sr_status) { case 0: /* Update the slot's sequence and clientid lease timer */ - ++res->sr_slot->seq_nr; - timestamp = res->sr_renewal_time; + ++slot->seq_nr; + timestamp = slot->renewal_time; clp = res->sr_session->clp; do_renew_lease(clp, timestamp); /* Check sequence flags */ @@ -521,12 +524,12 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * */ dprintk("%s: slot=%td seq=%d: Operation in progress\n", __func__, - res->sr_slot - res->sr_session->fc_slot_table.slots, - res->sr_slot->seq_nr); + slot - res->sr_session->fc_slot_table.slots, + slot->seq_nr); goto out_retry; default: /* Just update the slot sequence no. */ - ++res->sr_slot->seq_nr; + ++slot->seq_nr; } out: /* The session may be reset by one of the error handlers. */ @@ -637,6 +640,7 @@ int nfs41_setup_sequence(struct nfs4_session *session, rpc_task_set_priority(task, RPC_PRIORITY_NORMAL); slot = tbl->slots + slotid; + slot->renewal_time = jiffies; args->sa_session = session; args->sa_slotid = slotid; @@ -644,7 +648,6 @@ int nfs41_setup_sequence(struct nfs4_session *session, res->sr_session = session; res->sr_slot = slot; - res->sr_renewal_time = jiffies; res->sr_status_flags = 0; /* * sr_status is only set in decode_sequence, and so will remain diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index a73ea89..9cb1c63 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -187,6 +187,7 @@ struct nfs4_channel_attrs { /* nfs41 sessions slot seqid */ struct nfs4_slot { + unsigned long renewal_time; u32 seq_nr; }; @@ -200,7 +201,6 @@ struct nfs4_sequence_res { struct nfs4_session *sr_session; struct nfs4_slot *sr_slot; /* slot used to send request */ int sr_status; /* sequence operation status */ - unsigned long sr_renewal_time; u32 sr_status_flags; }; -- cgit v0.10.2 From 9329c5eb5b087d6e6af905bd7e4f7eee13f9f7e5 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 9 Nov 2012 12:36:35 -0300 Subject: mtd: mtd_blkdev: Use a different name for block_device_operations variable struct mtd_blktrans_ops is a type, and mtd_blktrans_ops is a variable. To improve code clarity it's better to not use the same names, so we just change the latter. Signed-off-by: Ezequiel Garcia Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index f1f0671..26ef2a7 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -325,7 +325,7 @@ unlock: return ret; } -static const struct block_device_operations mtd_blktrans_ops = { +static const struct block_device_operations mtd_block_ops = { .owner = THIS_MODULE, .open = blktrans_open, .release = blktrans_release, @@ -401,7 +401,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) gd->private_data = new; gd->major = tr->major; gd->first_minor = (new->devnum) << tr->part_bits; - gd->fops = &mtd_blktrans_ops; + gd->fops = &mtd_block_ops; if (tr->part_bits) if (new->devnum < 26) -- cgit v0.10.2 From 22a8578fca5a47e643bb4f70c232d0ec84db9e4e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Sat, 10 Nov 2012 13:08:20 -0300 Subject: mtd: mtd_blkdevs: Replace request handler kthread with a workqueue By replacing a kthread with a workqueue, the code is now a bit clearer. There's also a slight reduction of code size (numbers apply for x86): Before: text data bss dec hex filename 3248 36 0 3284 cd4 drivers/mtd/mtd_blkdevs.o After: text data bss dec hex filename 3150 36 0 3186 c72 drivers/mtd/mtd_blkdevs.o Due to lack of real hardware, tests have been performed on an emulated environment with mtdswap and mtdblock over nandsim devices. Some real testing should be done, before merging this patch. Signed-off-by: Ezequiel Garcia Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 26ef2a7..5ad39bb 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include "mtdcore.h" @@ -121,16 +120,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev) { - if (kthread_should_stop()) - return 1; - return dev->bg_stop; } EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background); -static int mtd_blktrans_thread(void *arg) +static void mtd_blktrans_work(struct work_struct *work) { - struct mtd_blktrans_dev *dev = arg; + struct mtd_blktrans_dev *dev = + container_of(work, struct mtd_blktrans_dev, work); struct mtd_blktrans_ops *tr = dev->tr; struct request_queue *rq = dev->rq; struct request *req = NULL; @@ -138,7 +135,7 @@ static int mtd_blktrans_thread(void *arg) spin_lock_irq(rq->queue_lock); - while (!kthread_should_stop()) { + while (1) { int res; dev->bg_stop = false; @@ -156,15 +153,7 @@ static int mtd_blktrans_thread(void *arg) background_done = !dev->bg_stop; continue; } - set_current_state(TASK_INTERRUPTIBLE); - - if (kthread_should_stop()) - set_current_state(TASK_RUNNING); - - spin_unlock_irq(rq->queue_lock); - schedule(); - spin_lock_irq(rq->queue_lock); - continue; + break; } spin_unlock_irq(rq->queue_lock); @@ -185,8 +174,6 @@ static int mtd_blktrans_thread(void *arg) __blk_end_request_all(req, -EIO); spin_unlock_irq(rq->queue_lock); - - return 0; } static void mtd_blktrans_request(struct request_queue *rq) @@ -199,10 +186,8 @@ static void mtd_blktrans_request(struct request_queue *rq) if (!dev) while ((req = blk_fetch_request(rq)) != NULL) __blk_end_request_all(req, -ENODEV); - else { - dev->bg_stop = true; - wake_up_process(dev->thread); - } + else + queue_work(dev->wq, &dev->work); } static int blktrans_open(struct block_device *bdev, fmode_t mode) @@ -437,14 +422,13 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) gd->queue = new->rq; - /* Create processing thread */ - /* TODO: workqueue ? */ - new->thread = kthread_run(mtd_blktrans_thread, new, - "%s%d", tr->name, new->mtd->index); - if (IS_ERR(new->thread)) { - ret = PTR_ERR(new->thread); + /* Create processing workqueue */ + new->wq = alloc_workqueue("%s%d", 0, 0, + tr->name, new->mtd->index); + if (!new->wq) goto error4; - } + INIT_WORK(&new->work, mtd_blktrans_work); + gd->driverfs_dev = &new->mtd->dev; if (new->readonly) @@ -484,9 +468,8 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) /* Stop new requests to arrive */ del_gendisk(old->disk); - - /* Stop the thread */ - kthread_stop(old->thread); + /* Stop workqueue. This will perform any pending request. */ + destroy_workqueue(old->wq); /* Kill current requests */ spin_lock_irqsave(&old->queue_lock, flags); diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h index ed270bd..4eb0a50 100644 --- a/include/linux/mtd/blktrans.h +++ b/include/linux/mtd/blktrans.h @@ -23,6 +23,7 @@ #include #include #include +#include struct hd_geometry; struct mtd_info; @@ -43,7 +44,8 @@ struct mtd_blktrans_dev { struct kref ref; struct gendisk *disk; struct attribute_group *disk_attributes; - struct task_struct *thread; + struct workqueue_struct *wq; + struct work_struct work; struct request_queue *rq; spinlock_t queue_lock; void *priv; -- cgit v0.10.2 From 9ff407385441744ea4618f109535014c4b651f8a Mon Sep 17 00:00:00 2001 From: Luka Perkov Date: Sun, 11 Nov 2012 20:32:15 +0100 Subject: mtd: use SQUASHFS_MAGIC from uapi/linux/magic.h Signed-off-by: Luka Perkov Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c index 9453931..7c057a0 100644 --- a/drivers/mtd/ar7part.c +++ b/drivers/mtd/ar7part.c @@ -26,19 +26,16 @@ #include #include #include -#include #include +#include + #define AR7_PARTS 4 #define ROOT_OFFSET 0xe0000 #define LOADER_MAGIC1 le32_to_cpu(0xfeedfa42) #define LOADER_MAGIC2 le32_to_cpu(0xfeed1281) -#ifndef SQUASHFS_MAGIC -#define SQUASHFS_MAGIC 0x73717368 -#endif - struct ar7_bin_rec { unsigned int checksum; unsigned int length; -- cgit v0.10.2 From fafc3d6880b28fe55af935fd43b23a29d61c537d Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Mon, 12 Nov 2012 10:52:47 +0100 Subject: mtd: bcm63xxpart: remove unused variable namelen is never used, so drop it. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index 63d2a64..1eb1416 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -79,7 +79,6 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, unsigned int rootfsaddr, kerneladdr, spareaddr; unsigned int rootfslen, kernellen, sparelen, totallen; unsigned int cfelen, nvramlen; - int namelen = 0; int i; u32 computed_crc; bool rootfs_first = false; @@ -143,15 +142,11 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, } /* Determine number of partitions */ - namelen = 8; - if (rootfslen > 0) { + if (rootfslen > 0) nrparts++; - namelen += 6; - } - if (kernellen > 0) { + + if (kernellen > 0) nrparts++; - namelen += 6; - } /* Ask kernel for more memory */ parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); -- cgit v0.10.2 From e190401ba1ca20d76f22c1f0aada0abd5bdc1afe Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Mon, 12 Nov 2012 10:52:48 +0100 Subject: mtd: bcm63xxpart: merge sparelen calculation The length of the spare part is calculated the same way in both branches so move to a common place. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index 1eb1416..ba7eeb8 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -120,7 +120,6 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE; rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE; spareaddr = roundup(totallen, master->erasesize) + cfelen; - sparelen = master->size - spareaddr - nvramlen; if (rootfsaddr < kerneladdr) { /* default Broadcom layout */ @@ -138,8 +137,8 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, rootfslen = 0; rootfsaddr = 0; spareaddr = cfelen; - sparelen = master->size - cfelen - nvramlen; } + sparelen = master->size - spareaddr - nvramlen; /* Determine number of partitions */ if (rootfslen > 0) -- cgit v0.10.2 From 4e4fb63955650e39ccfbd376733fa258adfb1e5d Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Mon, 12 Nov 2012 10:52:49 +0100 Subject: mtd: bcm63xxpart: make fixed part length calculation more generic The CFE does not use 4K sectors even if the flash supports it, so for the fixed partitions like CFE itself or NVRAM the erase block size is always 64k or bigger. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index ba7eeb8..b3db8e3 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -37,8 +37,7 @@ #define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */ -#define BCM63XX_MIN_CFE_SIZE 0x10000 /* always at least 64KiB */ -#define BCM63XX_MIN_NVRAM_SIZE 0x10000 /* always at least 64KiB */ +#define BCM63XX_CFE_BLOCK_SIZE 0x10000 /* always at least 64KiB */ #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0 @@ -79,6 +78,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, unsigned int rootfsaddr, kerneladdr, spareaddr; unsigned int rootfslen, kernellen, sparelen, totallen; unsigned int cfelen, nvramlen; + unsigned int cfe_erasesize; int i; u32 computed_crc; bool rootfs_first = false; @@ -86,8 +86,11 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, if (bcm63xx_detect_cfe(master)) return -EINVAL; - cfelen = max_t(uint32_t, master->erasesize, BCM63XX_MIN_CFE_SIZE); - nvramlen = max_t(uint32_t, master->erasesize, BCM63XX_MIN_NVRAM_SIZE); + cfe_erasesize = max_t(uint32_t, master->erasesize, + BCM63XX_CFE_BLOCK_SIZE); + + cfelen = cfe_erasesize; + nvramlen = cfe_erasesize; /* Allocate memory for buffer */ buf = vmalloc(sizeof(struct bcm_tag)); -- cgit v0.10.2 From f3f9a5dac79880af9a27f520fbeff11314ef9dde Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Mon, 12 Nov 2012 10:52:50 +0100 Subject: mtd: bcm63xxpart: move the last curpart++ to its correct place The line belongs above the comment, not below it. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index b3db8e3..44cba4e 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -190,9 +190,9 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, parts[curpart].name = "nvram"; parts[curpart].offset = master->size - nvramlen; parts[curpart].size = nvramlen; + curpart++; /* Global partition "linux" to make easy firmware upgrade */ - curpart++; parts[curpart].name = "linux"; parts[curpart].offset = cfelen; parts[curpart].size = master->size - cfelen - nvramlen; -- cgit v0.10.2 From 60768368b76b2794b088bb66fbd07557a10fa77e Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Mon, 12 Nov 2012 10:52:51 +0100 Subject: mtd: bcm63xxpart: use correct printk format for partitions Use ll to be able to remove the casts. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index 44cba4e..6eeb84c 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -198,9 +198,8 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, parts[curpart].size = master->size - cfelen - nvramlen; for (i = 0; i < nrparts; i++) - pr_info("Partition %d is %s offset %lx and length %lx\n", i, - parts[i].name, (long unsigned int)(parts[i].offset), - (long unsigned int)(parts[i].size)); + pr_info("Partition %d is %s offset %llx and length %llx\n", i, + parts[i].name, parts[i].offset, parts[i].size); pr_info("Spare partition is offset %x and length %x\n", spareaddr, sparelen); -- cgit v0.10.2 From ea2447f700cab264019b52e2b417d689e052dcfd Mon Sep 17 00:00:00 2001 From: Tom Mingarelli Date: Tue, 20 Nov 2012 19:43:17 +0000 Subject: intel-iommu: Prevent devices with RMRRs from being placed into SI Domain This patch is to prevent non-USB devices that have RMRRs associated with them from being placed into the SI Domain during init. This fixes the issue where the RMRR info for devices being placed in and out of the SI Domain gets lost. Signed-off-by: Thomas Mingarelli Tested-by: Shuah Khan Reviewed-by: Donald Dutile Reviewed-by: Alex Williamson Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index d4a4cd4..ca3ee46 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2320,8 +2320,39 @@ static int domain_add_dev_info(struct dmar_domain *domain, return 0; } +static bool device_has_rmrr(struct pci_dev *dev) +{ + struct dmar_rmrr_unit *rmrr; + int i; + + for_each_rmrr_units(rmrr) { + for (i = 0; i < rmrr->devices_cnt; i++) { + /* + * Return TRUE if this RMRR contains the device that + * is passed in. + */ + if (rmrr->devices[i] == dev) + return true; + } + } + return false; +} + static int iommu_should_identity_map(struct pci_dev *pdev, int startup) { + + /* + * We want to prevent any device associated with an RMRR from + * getting placed into the SI Domain. This is done because + * problems exist when devices are moved in and out of domains + * and their respective RMRR info is lost. We exempt USB devices + * from this process due to their usage of RMRRs that are known + * to not be needed after BIOS hand-off to OS. + */ + if (device_has_rmrr(pdev) && + (pdev->class >> 8) != PCI_CLASS_SERIAL_USB) + return 0; + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return 1; -- cgit v0.10.2 From 506ee557b75d4e77f4876ca4189cb855397d617b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 20 Nov 2012 00:26:17 -0800 Subject: OMAP: nokia770: remove custom implementation of ads7846_get_pendown_state The default implementation matches exactly our custom one so we can switch to using the default one. As a bonus the driver will take care of setting GPIO line for us. Tested-by: Aaro Koskinen Acked-by: Tony Lindgren Signed-off-by: Dmitry Torokhov diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index 7d5c06d..be6490b 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -112,17 +112,6 @@ static void __init mipid_dev_init(void) omapfb_set_lcd_config(&nokia770_lcd_config); } -static void __init ads7846_dev_init(void) -{ - if (gpio_request(ADS7846_PENDOWN_GPIO, "ADS7846 pendown") < 0) - printk(KERN_ERR "can't get ads7846 pen down GPIO\n"); -} - -static int ads7846_get_pendown_state(void) -{ - return !gpio_get_value(ADS7846_PENDOWN_GPIO); -} - static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata = { .x_max = 0x0fff, .y_max = 0x0fff, @@ -131,7 +120,7 @@ static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata = .debounce_max = 10, .debounce_tol = 3, .debounce_rep = 1, - .get_pendown_state = ads7846_get_pendown_state, + .gpio_pendown = ADS7846_PENDOWN_GPIO, }; static struct spi_board_info nokia770_spi_board_info[] __initdata = { @@ -241,7 +230,6 @@ static void __init omap_nokia770_init(void) omap_serial_init(); omap_register_i2c_bus(1, 100, NULL, 0); hwa742_dev_init(); - ads7846_dev_init(); mipid_dev_init(); omap1_usb_init(&nokia770_usb_config); nokia770_mmc_init(); -- cgit v0.10.2 From 2ad5169c762e56e4c7a76f517256ce853eb53ad0 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Wed, 21 Nov 2012 13:12:16 -0800 Subject: Input: wacom - simplify type check for newer V5 devices The updated type enum enables this implementation. Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 7554a04..a257212 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -467,9 +467,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom) /* general pen packet */ if ((data[1] & 0xb8) == 0xa0) { t = (data[6] << 2) | ((data[7] >> 6) & 3); - if ((features->type >= INTUOS4S && features->type <= INTUOS4L) || - (features->type >= INTUOS5S && features->type <= INTUOS5L) || - (features->type >= WACOM_21UX2 && features->type <= WACOM_24HD)) { + if (features->type >= INTUOS4S && features->type <= WACOM_24HD) { t = (t << 1) | (data[1] & 1); } input_report_abs(input, ABS_PRESSURE, t); -- cgit v0.10.2 From edbe265d245b0fe05c43e96e52554dacae5dcc70 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Wed, 21 Nov 2012 13:12:50 -0800 Subject: Input: wacom - add support for a new MT device (0x4001) It supports 10 fingers. Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index a257212..c0f3e91 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -2029,6 +2029,9 @@ static const struct wacom_features wacom_features_0x100 = static const struct wacom_features wacom_features_0x101 = { "Wacom ISDv4 101", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, 0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x4001 = + { "Wacom ISDv4 4001", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, + 0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x47 = { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -2207,6 +2210,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xEF) }, { USB_DEVICE_WACOM(0x100) }, { USB_DEVICE_WACOM(0x101) }, + { USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x47) }, { USB_DEVICE_WACOM(0xF4) }, { USB_DEVICE_WACOM(0xF8) }, -- cgit v0.10.2 From fe20d7d5eefb218b82033ba5c13cbcbd2a3d874c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 21 Nov 2012 22:49:36 -0500 Subject: NFSv4: Fix a compile time warning when #undef CONFIG_NFS_V4_1 The function nfs4_get_machine_cred_locked is used by NFSv4.0 routines too. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index a525fde..ea4e362 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -321,13 +321,13 @@ extern void nfs4_renew_state(struct work_struct *); /* nfs4state.c */ struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp); +struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp); struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); int nfs4_discover_server_trunking(struct nfs_client *clp, struct nfs_client **); int nfs40_discover_server_trunking(struct nfs_client *clp, struct nfs_client **, struct rpc_cred *); #if defined(CONFIG_NFS_V4_1) -struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp); struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp); int nfs41_discover_server_trunking(struct nfs_client *clp, struct nfs_client **, struct rpc_cred *); -- cgit v0.10.2 From d751f748b359534d78e2b2e52b59d39f0e0540aa Mon Sep 17 00:00:00 2001 From: Jim Rees Date: Fri, 16 Nov 2012 18:12:06 -0500 Subject: NFS: Reduce stack use in encode_exchange_id() encode_exchange_id() uses more stack space than necessary, giving a compile time warning. Reduce the size of the static buffer for implementation name. Signed-off-by: Jim Rees Reviewed-by: "Adamson, Dros" Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 40836ee..142aacb 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -270,6 +270,8 @@ static int nfs4_stat_to_errno(int); #if defined(CONFIG_NFS_V4_1) #define NFS4_MAX_MACHINE_NAME_LEN (64) +#define IMPL_NAME_LIMIT (sizeof(utsname()->sysname) + sizeof(utsname()->release) + \ + sizeof(utsname()->version) + sizeof(utsname()->machine) + 8) #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \ encode_verifier_maxsz + \ @@ -282,7 +284,7 @@ static int nfs4_stat_to_errno(int); 1 /* nii_domain */ + \ XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \ 1 /* nii_name */ + \ - XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \ + XDR_QUADLEN(IMPL_NAME_LIMIT) + \ 3 /* nii_date */) #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \ 2 /* eir_clientid */ + \ @@ -1713,7 +1715,7 @@ static void encode_exchange_id(struct xdr_stream *xdr, struct compound_hdr *hdr) { __be32 *p; - char impl_name[NFS4_OPAQUE_LIMIT]; + char impl_name[IMPL_NAME_LIMIT]; int len = 0; encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr); @@ -1728,7 +1730,7 @@ static void encode_exchange_id(struct xdr_stream *xdr, if (send_implementation_id && sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 && sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) - <= NFS4_OPAQUE_LIMIT + 1) + <= sizeof(impl_name) + 1) len = snprintf(impl_name, sizeof(impl_name), "%s %s %s %s", utsname()->sysname, utsname()->release, utsname()->version, utsname()->machine); -- cgit v0.10.2 From 8d4b9e3182634d8b5afb5a144a8c6c24b187bcc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 12 Nov 2012 13:03:20 +0100 Subject: bcma: export PLL reading function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is required by NAND flash driver for initializing wait counters. Signed-off-by: Rafał Miłecki Signed-off-by: Artem Bityutskiy diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index 201faf1..657f235 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -13,12 +13,13 @@ #include #include -static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset) +u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset) { bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA); } +EXPORT_SYMBOL_GPL(bcma_chipco_pll_read); void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value) { diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 4180eb7..4fb6bd7 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -345,6 +345,7 @@ extern void bcma_core_set_clockmode(struct bcma_device *core, enum bcma_clkmode clkmode); extern void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on); +extern u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset); #define BCMA_DMA_TRANSLATION_MASK 0xC0000000 #define BCMA_DMA_TRANSLATION_NONE 0x00000000 #define BCMA_DMA_TRANSLATION_DMA32_CMT 0x40000000 /* Client Mode Translation for 32-bit DMA */ -- cgit v0.10.2 From a5401370c520d573e9d62b3f8f34940c3b798a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 12 Nov 2012 13:03:21 +0100 Subject: mtd: prepare place for BCMA NAND flash driver(s) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCMA bus can contain NAND flash memory, it's registered in system as platform device. This adds required hooks and place for controler specific drivers. Signed-off-by: Rafał Miłecki Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index a803d9b..3314e92 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -460,6 +460,15 @@ config MTD_NAND_GPMI_NAND block, such as SD card. So pay attention to it when you enable the GPMI. +config MTD_NAND_BCM47XXNFLASH + tristate "R/O support for NAND flash on BCMA bus" + depends on BCMA_NFLASH + help + BCMA bus can have various flash memories attached, they are + registered by bcma as platform devices. This enables driver for + NAND flash memories. For now only read mode for BCM4706 is + implemented. + config MTD_NAND_PLATFORM tristate "Support for generic platform NAND driver" depends on HAS_IOMEM diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 44fca05..3c3f215 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -54,5 +54,6 @@ obj-$(CONFIG_MTD_NAND_RICOH) += r852.o obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o +obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/bcm47xxnflash/Makefile new file mode 100644 index 0000000..1d0693a --- /dev/null +++ b/drivers/mtd/nand/bcm47xxnflash/Makefile @@ -0,0 +1,3 @@ +bcm47xxnflash-y += main.o + +obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash.o diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h new file mode 100644 index 0000000..2e8864a --- /dev/null +++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h @@ -0,0 +1,14 @@ +#ifndef __BCM47XXNFLASH_H +#define __BCM47XXNFLASH_H + +#include +#include + +struct bcm47xxnflash { + struct bcma_drv_cc *cc; + + struct nand_chip nand_chip; + struct mtd_info mtd; +}; + +#endif /* BCM47XXNFLASH */ diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c new file mode 100644 index 0000000..fc9139d --- /dev/null +++ b/drivers/mtd/nand/bcm47xxnflash/main.c @@ -0,0 +1,108 @@ +/* + * BCM47XX NAND flash driver + * + * Copyright (C) 2012 Rafał Miłecki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include + +#include "bcm47xxnflash.h" + +MODULE_DESCRIPTION("NAND flash driver for BCMA bus"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rafał Miłecki"); + +static const char *probes[] = { "bcm47xxpart", NULL }; + +static int bcm47xxnflash_probe(struct platform_device *pdev) +{ + struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev); + struct bcm47xxnflash *b47n; + int err = 0; + + b47n = kzalloc(sizeof(*b47n), GFP_KERNEL); + if (!b47n) { + err = -ENOMEM; + goto out; + } + + b47n->nand_chip.priv = b47n; + b47n->mtd.owner = THIS_MODULE; + b47n->mtd.priv = &b47n->nand_chip; /* Required */ + b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash); + + if (0) { + /* TODO: init device */ + } else { + pr_err("Device not supported\n"); + err = -ENOTSUPP; + } + if (err) { + pr_err("Initialization failed: %d\n", err); + goto err_init; + } + + err = mtd_device_parse_register(&b47n->mtd, probes, NULL, NULL, 0); + if (err) { + pr_err("Failed to register MTD device: %d\n", err); + goto err_dev_reg; + } + + return 0; + +err_dev_reg: +err_init: + kfree(b47n); +out: + return err; +} + +static int __devexit bcm47xxnflash_remove(struct platform_device *pdev) +{ + struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev); + + if (nflash->mtd) + mtd_device_unregister(nflash->mtd); + + return 0; +} + +static struct platform_driver bcm47xxnflash_driver = { + .remove = __devexit_p(bcm47xxnflash_remove), + .driver = { + .name = "bcma_nflash", + .owner = THIS_MODULE, + }, +}; + +static int __init bcm47xxnflash_init(void) +{ + int err; + + /* + * Platform device "bcma_nflash" exists on SoCs and is registered very + * early, it won't be added during runtime (use platform_driver_probe). + */ + err = platform_driver_probe(&bcm47xxnflash_driver, bcm47xxnflash_probe); + if (err) + pr_err("Failed to register serial flash driver: %d\n", err); + + return err; +} + +static void __exit bcm47xxnflash_exit(void) +{ + platform_driver_unregister(&bcm47xxnflash_driver); +} + +module_init(bcm47xxnflash_init); +module_exit(bcm47xxnflash_exit); -- cgit v0.10.2 From 19c0921c842e0aa9ce8c540c9134fd358acc9b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 12 Nov 2012 13:03:22 +0100 Subject: mtd: bcm47xxnflash: init NAND on BCM4706 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/bcm47xxnflash/Makefile index 1d0693a..4f688f9 100644 --- a/drivers/mtd/nand/bcm47xxnflash/Makefile +++ b/drivers/mtd/nand/bcm47xxnflash/Makefile @@ -1,3 +1,4 @@ bcm47xxnflash-y += main.o +bcm47xxnflash- += ops_bcm4706.o obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash.o diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c new file mode 100644 index 0000000..ae8a793 --- /dev/null +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -0,0 +1,109 @@ +/* + * BCM47XX NAND flash driver + * + * Copyright (C) 2012 Rafał Miłecki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include + +#include "bcm47xxnflash.h" + +/************************************************** + * Various helpers + **************************************************/ + +static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock) +{ + return ((ns * 1000 * clock) / 1000000) + 1; +} + +/************************************************** + * NAND chip ops + **************************************************/ + +/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */ +static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, + int chip) +{ + return; +} + +/************************************************** + * Init + **************************************************/ + +int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) +{ + int err; + u32 freq; + u16 clock; + u8 w0, w1, w2, w3, w4; + + unsigned long chipsize; /* MiB */ + u8 tbits, col_bits, col_size, row_bits, row_bsize; + u32 val; + + b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; + b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ + + /* Enable NAND flash access */ + bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG, + BCMA_CC_4706_FLASHSCFG_NF1); + + /* Configure wait counters */ + if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) { + freq = 100000000; + } else { + freq = bcma_chipco_pll_read(b47n->cc, 4); + freq = (freq * 0xFFF) >> 3; + freq = (freq * 25000000) >> 3; + } + clock = freq / 1000000; + w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock); + w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock); + w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock); + w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock); + w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock); + bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0, + (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0)); + + /* Scan NAND */ + err = nand_scan(&b47n->mtd, 1); + if (err) { + pr_err("Could not scan NAND flash: %d\n", err); + goto exit; + } + + /* Configure FLASH */ + chipsize = b47n->nand_chip.chipsize >> 20; + tbits = ffs(chipsize); /* find first bit set */ + if (!tbits || tbits != fls(chipsize)) { + pr_err("Invalid flash size: 0x%lX\n", chipsize); + err = -ENOTSUPP; + goto exit; + } + tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */ + + col_bits = b47n->nand_chip.page_shift + 1; + col_size = (col_bits + 7) / 8; + + row_bits = tbits - col_bits + 1; + row_bsize = (row_bits + 7) / 8; + + val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2; + bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val); + +exit: + if (err) + bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG, + ~BCMA_CC_4706_FLASHSCFG_NF1); + return err; +} -- cgit v0.10.2 From 0fbc5991551fa2024de7db79421e9a16ca9fe542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 12 Nov 2012 13:03:23 +0100 Subject: mtd: bcm47xxnflash: support for NAND_CMD_READID command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h index 2e8864a..cc71400 100644 --- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h +++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h @@ -9,6 +9,11 @@ struct bcm47xxnflash { struct nand_chip nand_chip; struct mtd_info mtd; + + unsigned curr_command; + int curr_column; + + u8 id_data[8]; }; #endif /* BCM47XXNFLASH */ diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index ae8a793..7de190e 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -16,6 +16,10 @@ #include "bcm47xxnflash.h" +/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has + * shown 164 retries as maxiumum. */ +#define NFLASH_READY_RETRIES 1000 + /************************************************** * Various helpers **************************************************/ @@ -25,6 +29,24 @@ static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock) return ((ns * 1000 * clock) / 1000000) + 1; } +static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code) +{ + int i = 0; + + bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, 0x80000000 | code); + for (i = 0; i < NFLASH_READY_RETRIES; i++) { + if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & 0x80000000)) { + i = 0; + break; + } + } + if (i) { + pr_err("NFLASH control command not ready!\n"); + return -EBUSY; + } + return 0; +} + /************************************************** * NAND chip ops **************************************************/ @@ -36,6 +58,83 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, return; } +/* + * Default nand_command and nand_command_lp don't match BCM4706 hardware layout. + * For example, reading chip id is performed in a non-standard way. + * Setting column and page is also handled differently, we use a special + * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert + * standard commands would be much more complicated. + */ +static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, + unsigned command, int column, + int page_addr) +{ + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + u32 ctlcode; + int i; + + if (column != -1) + b47n->curr_column = column; + + switch (command) { + case NAND_CMD_RESET: + pr_warn("Chip reset not implemented yet\n"); + break; + case NAND_CMD_READID: + ctlcode = 0x40000000 | 0x01000000 | 0x00080000 | 0x00010000; + ctlcode |= NAND_CMD_READID; + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) { + pr_err("READID error\n"); + break; + } + + /* + * Reading is specific, last one has to go without 0x40000000 + * bit. We don't know how many reads NAND subsystem is going + * to perform, so cache everything. + */ + for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) { + ctlcode = 0x40000000 | 0x00100000; + if (i == ARRAY_SIZE(b47n->id_data) - 1) + ctlcode &= ~0x40000000; + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, + ctlcode)) { + pr_err("READID error\n"); + break; + } + b47n->id_data[i] = + bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA) + & 0xFF; + } + + break; + default: + pr_err("Command 0x%X unsupported\n", command); + break; + } + b47n->curr_command = command; +} + +static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + + switch (b47n->curr_command) { + case NAND_CMD_READID: + if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) { + pr_err("Requested invalid id_data: %d\n", + b47n->curr_column); + return 0; + } + return b47n->id_data[b47n->curr_column++]; + } + + pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command); + return 0; +} + /************************************************** * Init **************************************************/ @@ -52,6 +151,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) u32 val; b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; + b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; + b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ /* Enable NAND flash access */ -- cgit v0.10.2 From 3c01d4cb7576ff79e13ba7d7fb884e63e6f07bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 12 Nov 2012 13:03:24 +0100 Subject: mtd: bcm47xxnflash: implement reading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h index cc71400..264aec4 100644 --- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h +++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h @@ -11,6 +11,7 @@ struct bcm47xxnflash { struct mtd_info mtd; unsigned curr_command; + int curr_page_addr; int curr_column; u8 id_data[8]; diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index 7de190e..e42e182 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -20,6 +20,8 @@ * shown 164 retries as maxiumum. */ #define NFLASH_READY_RETRIES 1000 +#define NFLASH_SECTOR_SIZE 512 + /************************************************** * Various helpers **************************************************/ @@ -47,6 +49,80 @@ static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code) return 0; } +static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc) +{ + int i; + + for (i = 0; i < NFLASH_READY_RETRIES; i++) { + if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & 0x04000000) { + if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & + BCMA_CC_NFLASH_CTL_ERR) { + pr_err("Error on polling\n"); + return -EBUSY; + } else { + return 0; + } + } + } + + pr_err("Polling timeout!\n"); + return -EBUSY; +} + +/************************************************** + * R/W + **************************************************/ + +static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, + int len) +{ + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + + u32 ctlcode; + u32 *dest = (u32 *)buf; + int i; + int toread; + + BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask); + /* Don't validate column using nand_chip->page_shift, it may be bigger + * when accessing OOB */ + + while (len) { + /* We can read maximum of 0x200 bytes at once */ + toread = min(len, 0x200); + + /* Set page and column */ + bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR, + b47n->curr_column); + bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR, + b47n->curr_page_addr); + + /* Prepare to read */ + ctlcode = 0x40000000 | 0x00080000 | 0x00040000 | 0x00020000 | + 0x00010000; + ctlcode |= NAND_CMD_READSTART << 8; + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) + return; + if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc)) + return; + + /* Eventually read some data :) */ + for (i = 0; i < toread; i += 4, dest++) { + ctlcode = 0x40000000 | 0x30000000 | 0x00100000; + if (i == toread - 4) /* Last read goes without that */ + ctlcode &= ~0x40000000; + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, + ctlcode)) + return; + *dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA); + } + + b47n->curr_column += toread; + len -= toread; + } +} + /************************************************** * NAND chip ops **************************************************/ @@ -76,6 +152,8 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, if (column != -1) b47n->curr_column = column; + if (page_addr != -1) + b47n->curr_page_addr = page_addr; switch (command) { case NAND_CMD_RESET: @@ -109,6 +187,12 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, } break; + case NAND_CMD_READ0: + break; + case NAND_CMD_READOOB: + if (page_addr != -1) + b47n->curr_column += mtd->writesize; + break; default: pr_err("Command 0x%X unsupported\n", command); break; @@ -120,6 +204,7 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) { struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + u32 tmp = 0; switch (b47n->curr_command) { case NAND_CMD_READID: @@ -129,12 +214,31 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) return 0; } return b47n->id_data[b47n->curr_column++]; + case NAND_CMD_READOOB: + bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4); + return tmp & 0xFF; } pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command); return 0; } +static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd, + uint8_t *buf, int len) +{ + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + + switch (b47n->curr_command) { + case NAND_CMD_READ0: + case NAND_CMD_READOOB: + bcm47xxnflash_ops_bcm4706_read(mtd, buf, len); + return; + } + + pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command); +} + /************************************************** * Init **************************************************/ @@ -153,6 +257,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; + b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; + b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ /* Enable NAND flash access */ -- cgit v0.10.2 From 00940a23475f31870cb777d5017b6f160542f3fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 12 Nov 2012 13:03:25 +0100 Subject: mtd: bcm47xxnflash: enable BCM4706 driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/bcm47xxnflash/Makefile index 4f688f9..f05b119 100644 --- a/drivers/mtd/nand/bcm47xxnflash/Makefile +++ b/drivers/mtd/nand/bcm47xxnflash/Makefile @@ -1,4 +1,4 @@ bcm47xxnflash-y += main.o -bcm47xxnflash- += ops_bcm4706.o +bcm47xxnflash-y += ops_bcm4706.o obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash.o diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h index 264aec4..0bdb2ce 100644 --- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h +++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h @@ -17,4 +17,6 @@ struct bcm47xxnflash { u8 id_data[8]; }; +int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n); + #endif /* BCM47XXNFLASH */ diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c index fc9139d..2b8b05b 100644 --- a/drivers/mtd/nand/bcm47xxnflash/main.c +++ b/drivers/mtd/nand/bcm47xxnflash/main.c @@ -40,8 +40,8 @@ static int bcm47xxnflash_probe(struct platform_device *pdev) b47n->mtd.priv = &b47n->nand_chip; /* Required */ b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash); - if (0) { - /* TODO: init device */ + if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { + err = bcm47xxnflash_ops_bcm4706_init(b47n); } else { pr_err("Device not supported\n"); err = -ENOTSUPP; -- cgit v0.10.2 From 9b7ef60ce15c5f668c0da30a39ed9b315d3d7ff0 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 12 Nov 2012 12:58:28 -0700 Subject: mtd: m25p80: add support for the Winbond w25q80bl chip Signed-off-by: Stephen Warren Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 7e2d8f9..1518324 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -742,6 +742,7 @@ static const struct spi_device_id m25p_ids[] = { { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) }, /* Catalyst / On Semiconductor -- non-JEDEC */ -- cgit v0.10.2 From ab0b00bc6ebcfbff42dedb3bf53f0ece79b27e88 Mon Sep 17 00:00:00 2001 From: Josh Radel Date: Wed, 14 Nov 2012 14:11:32 -0800 Subject: mtd: ofpart: Replicate mtd cmdline "lk" option with device tree "lock" property The mtd partition command line parser already supports a "lk" option to mask MTD_POWERUP_LOCK. This extends that same functionality to device tree partition specifications. Signed-off-by: Josh Radel Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index d9127e2..dbd3aa5 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -71,7 +71,10 @@ static int parse_ofpart_partitions(struct mtd_info *master, (*pparts)[i].name = (char *)partname; if (of_get_property(pp, "read-only", &len)) - (*pparts)[i].mask_flags = MTD_WRITEABLE; + (*pparts)[i].mask_flags |= MTD_WRITEABLE; + + if (of_get_property(pp, "lock", &len)) + (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK; i++; } -- cgit v0.10.2 From 8ea9eee903f3acf5aa6bdfb831461aec063b128b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 18 Nov 2012 14:43:43 +0400 Subject: mtd: Drop FORTUNET support The kernel has never contained the symbol SA1100_FORTUNET so the driver never compiled and can be removed safely. Signed-off-by: Alexander Shiyan Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 2e47c2e..a183070 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -365,13 +365,6 @@ config MTD_IXP2000 IXP2000 based board and would like to use the flash chips on it, say 'Y'. -config MTD_FORTUNET - tristate "CFI Flash device mapped on the FortuNet board" - depends on MTD_CFI && SA1100_FORTUNET - help - This enables access to the Flash on the FortuNet board. If you - have such a board, say 'Y'. - config MTD_AUTCPU12 bool "NV-RAM mapping AUTCPU12 board" depends on ARCH_AUTCPU12 diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index deb43e9..4bd6d0d 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -40,7 +40,6 @@ obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o obj-$(CONFIG_MTD_IMPA7) += impa7.o -obj-$(CONFIG_MTD_FORTUNET) += fortunet.o obj-$(CONFIG_MTD_UCLINUX) += uclinux.o obj-$(CONFIG_MTD_NETtel) += nettel.o obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c deleted file mode 100644 index 956e2e4..0000000 --- a/drivers/mtd/maps/fortunet.c +++ /dev/null @@ -1,277 +0,0 @@ -/* fortunet.c memory map - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#define MAX_NUM_REGIONS 4 -#define MAX_NUM_PARTITIONS 8 - -#define DEF_WINDOW_ADDR_PHY 0x00000000 -#define DEF_WINDOW_SIZE 0x00800000 // 8 Mega Bytes - -#define MTD_FORTUNET_PK "MTD FortuNet: " - -#define MAX_NAME_SIZE 128 - -struct map_region -{ - int window_addr_physical; - int altbankwidth; - struct map_info map_info; - struct mtd_info *mymtd; - struct mtd_partition parts[MAX_NUM_PARTITIONS]; - char map_name[MAX_NAME_SIZE]; - char parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE]; -}; - -static struct map_region map_regions[MAX_NUM_REGIONS]; -static int map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0}; -static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0}; - - - -struct map_info default_map = { - .size = DEF_WINDOW_SIZE, - .bankwidth = 4, -}; - -static char * __init get_string_option(char *dest,int dest_size,char *sor) -{ - if(!dest_size) - return sor; - dest_size--; - while(*sor) - { - if(*sor==',') - { - sor++; - break; - } - else if(*sor=='\"') - { - sor++; - while(*sor) - { - if(*sor=='\"') - { - sor++; - break; - } - *dest = *sor; - dest++; - sor++; - dest_size--; - if(!dest_size) - { - *dest = 0; - return sor; - } - } - } - else - { - *dest = *sor; - dest++; - sor++; - dest_size--; - if(!dest_size) - { - *dest = 0; - return sor; - } - } - } - *dest = 0; - return sor; -} - -static int __init MTD_New_Region(char *line) -{ - char string[MAX_NAME_SIZE]; - int params[6]; - get_options (get_string_option(string,sizeof(string),line),6,params); - if(params[0]<1) - { - printk(MTD_FORTUNET_PK "Bad parameters for MTD Region " - " name,region-number[,base,size,bankwidth,altbankwidth]\n"); - return 1; - } - if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS)) - { - printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n", - params[1],MAX_NUM_REGIONS-1); - return 1; - } - memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]])); - memcpy(&map_regions[params[1]].map_info, - &default_map,sizeof(map_regions[params[1]].map_info)); - map_regions_set[params[1]] = 1; - map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY; - map_regions[params[1]].altbankwidth = 2; - map_regions[params[1]].mymtd = NULL; - map_regions[params[1]].map_info.name = map_regions[params[1]].map_name; - strcpy(map_regions[params[1]].map_info.name,string); - if(params[0]>1) - { - map_regions[params[1]].window_addr_physical = params[2]; - } - if(params[0]>2) - { - map_regions[params[1]].map_info.size = params[3]; - } - if(params[0]>3) - { - map_regions[params[1]].map_info.bankwidth = params[4]; - } - if(params[0]>4) - { - map_regions[params[1]].altbankwidth = params[5]; - } - return 1; -} - -static int __init MTD_New_Partition(char *line) -{ - char string[MAX_NAME_SIZE]; - int params[4]; - get_options (get_string_option(string,sizeof(string),line),4,params); - if(params[0]<3) - { - printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition " - " name,region-number,size,offset\n"); - return 1; - } - if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS)) - { - printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n", - params[1],MAX_NUM_REGIONS-1); - return 1; - } - if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS) - { - printk(MTD_FORTUNET_PK "Out of space for partition in this region\n"); - return 1; - } - map_regions[params[1]].parts[map_regions_parts[params[1]]].name = - map_regions[params[1]]. parts_name[map_regions_parts[params[1]]]; - strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string); - map_regions[params[1]].parts[map_regions_parts[params[1]]].size = - params[2]; - map_regions[params[1]].parts[map_regions_parts[params[1]]].offset = - params[3]; - map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0; - map_regions_parts[params[1]]++; - return 1; -} - -__setup("MTD_Region=", MTD_New_Region); -__setup("MTD_Partition=", MTD_New_Partition); - -/* Backwards-spelling-compatibility */ -__setup("MTD_Partion=", MTD_New_Partition); - -static int __init init_fortunet(void) -{ - int ix,iy; - for(iy=ix=0;ixowner = THIS_MODULE; - mtd_device_register(map_regions[ix].mymtd, - map_regions[ix].parts, - map_regions_parts[ix]); - } - } - if(iy) - return 0; - return -ENXIO; -} - -static void __exit cleanup_fortunet(void) -{ - int ix; - for(ix=0;ix Date: Mon, 19 Nov 2012 13:21:24 -0500 Subject: mtd: remove use of __devexit_p CONFIG_HOTPLUG is going away as an option so __devexit_p is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index 2dc5a6f..113aced 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c @@ -77,7 +77,7 @@ static int __devexit bcm47xxsflash_remove(struct platform_device *pdev) } static struct platform_driver bcma_sflash_driver = { - .remove = __devexit_p(bcm47xxsflash_remove), + .remove = bcm47xxsflash_remove, .driver = { .name = "bcma_sflash", .owner = THIS_MODULE, diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 1518324..bd2d912 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -994,7 +994,7 @@ static struct spi_driver m25p80_driver = { }, .id_table = m25p_ids, .probe = m25p_probe, - .remove = __devexit_p(m25p_remove), + .remove = m25p_remove, /* REVISIT: many of these chips have deep power-down modes, which * should clearly be entered on suspend() to minimize power use. diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 928fb0e..23ccc36 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -920,7 +920,7 @@ static struct spi_driver dataflash_driver = { }, .probe = dataflash_probe, - .remove = __devexit_p(dataflash_remove), + .remove = dataflash_remove, /* FIXME: investigate suspend and resume... */ }; diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index 39e9567..e27737c 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -1092,7 +1092,7 @@ static struct platform_driver spear_smi_driver = { #endif }, .probe = spear_smi_probe, - .remove = __devexit_p(spear_smi_remove), + .remove = spear_smi_remove, }; module_platform_driver(spear_smi_driver); diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index ab8a2f4..9ebf86d 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -428,7 +428,7 @@ static struct spi_driver sst25l_driver = { .owner = THIS_MODULE, }, .probe = sst25l_probe, - .remove = __devexit_p(sst25l_remove), + .remove = sst25l_remove, }; module_spi_driver(sst25l_driver); diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c index 76fb594..ca0313d 100644 --- a/drivers/mtd/maps/autcpu12-nvram.c +++ b/drivers/mtd/maps/autcpu12-nvram.c @@ -121,7 +121,7 @@ static struct platform_driver autcpu12_nvram_driver = { .owner = THIS_MODULE, }, .probe = autcpu12_nvram_probe, - .remove = __devexit_p(autcpu12_nvram_remove), + .remove = autcpu12_nvram_remove, }; module_platform_driver(autcpu12_nvram_driver); diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index ef5cde8..340e8a2 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -184,7 +184,7 @@ static int __devexit bfin_flash_remove(struct platform_device *pdev) static struct platform_driver bfin_flash_driver = { .probe = bfin_flash_probe, - .remove = __devexit_p(bfin_flash_remove), + .remove = bfin_flash_remove, .driver = { .name = DRIVER_NAME, }, diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index e4de96b..670af9a 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -273,7 +273,7 @@ static int __devexit gpio_flash_remove(struct platform_device *pdev) static struct platform_driver gpio_flash_driver = { .probe = gpio_flash_probe, - .remove = __devexit_p(gpio_flash_remove), + .remove = gpio_flash_remove, .driver = { .name = DRIVER_NAME, }, diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index 93f0317..f6185d4 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -256,7 +256,7 @@ vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) static struct pci_driver vr_nor_pci_driver = { .name = DRV_NAME, .probe = vr_nor_pci_probe, - .remove = __devexit_p(vr_nor_pci_remove), + .remove = vr_nor_pci_remove, .id_table = vr_nor_pci_ids, }; diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index c03456f..4c032f1 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -209,7 +209,7 @@ MODULE_DEVICE_TABLE(of, ltq_mtd_match); static struct platform_driver ltq_mtd_driver = { .probe = ltq_mtd_probe, - .remove = __devexit_p(ltq_mtd_remove), + .remove = ltq_mtd_remove, .driver = { .name = "ltq-nor", .owner = THIS_MODULE, diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c index 3c7ad17..962a76a 100644 --- a/drivers/mtd/maps/latch-addr-flash.c +++ b/drivers/mtd/maps/latch-addr-flash.c @@ -218,7 +218,7 @@ done: static struct platform_driver latch_addr_flash_driver = { .probe = latch_addr_flash_probe, - .remove = __devexit_p(latch_addr_flash_remove), + .remove = latch_addr_flash_remove, .driver = { .name = DRIVER_NAME, }, diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index 1c30c1a..ddc8c0c 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -326,7 +326,7 @@ mtd_pci_remove(struct pci_dev *dev) static struct pci_driver mtd_pci_driver = { .name = "MTD PCI", .probe = mtd_pci_probe, - .remove = __devexit_p(mtd_pci_remove), + .remove = mtd_pci_remove, .id_table = mtd_pci_ids, }; diff --git a/drivers/mtd/maps/pismo.c b/drivers/mtd/maps/pismo.c index 65bd1cd..9f4e594 100644 --- a/drivers/mtd/maps/pismo.c +++ b/drivers/mtd/maps/pismo.c @@ -267,7 +267,7 @@ static struct i2c_driver pismo_driver = { .owner = THIS_MODULE, }, .probe = pismo_probe, - .remove = __devexit_p(pismo_remove), + .remove = pismo_remove, .id_table = pismo_id, }; diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 81884c2..f913a1c 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -139,7 +139,7 @@ static struct platform_driver pxa2xx_flash_driver = { .owner = THIS_MODULE, }, .probe = pxa2xx_flash_probe, - .remove = __devexit_p(pxa2xx_flash_remove), + .remove = pxa2xx_flash_remove, .shutdown = pxa2xx_flash_shutdown, }; diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index 9dcbc68..d527608 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c @@ -231,7 +231,7 @@ static struct pci_driver scb2_flash_driver = { .name = "Intel SCB2 BIOS Flash", .id_table = scb2_flash_pci_ids, .probe = scb2_flash_probe, - .remove = __devexit_p(scb2_flash_remove), + .remove = scb2_flash_remove, }; module_pci_driver(scb2_flash_driver); diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 175e537..1c03ca7 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -155,7 +155,7 @@ static struct platform_driver uflash_driver = { .of_match_table = uflash_match, }, .probe = uflash_probe, - .remove = __devexit_p(uflash_remove), + .remove = uflash_remove, }; module_platform_driver(uflash_driver); diff --git a/drivers/mtd/maps/vmu-flash.c b/drivers/mtd/maps/vmu-flash.c index 2e2b094..5a83a26 100644 --- a/drivers/mtd/maps/vmu-flash.c +++ b/drivers/mtd/maps/vmu-flash.c @@ -802,7 +802,7 @@ static struct maple_driver vmu_flash_driver = { .drv = { .name = "Dreamcast_visual_memory", .probe = probe_maple_vmu, - .remove = __devexit_p(remove_maple_vmu), + .remove = remove_maple_vmu, }, }; diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 9e7723a..51dba43 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -289,7 +289,7 @@ static int __devexit ams_delta_cleanup(struct platform_device *pdev) static struct platform_driver ams_delta_nand_driver = { .probe = ams_delta_init, - .remove = __devexit_p(ams_delta_cleanup), + .remove = ams_delta_cleanup, .driver = { .name = "ams-delta-nand", .owner = THIS_MODULE, diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 5c47b20..d84af46 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -509,7 +509,7 @@ static struct platform_driver au1550nd_driver = { .owner = THIS_MODULE, }, .probe = au1550nd_probe, - .remove = __devexit_p(au1550nd_remove), + .remove = au1550nd_remove, }; module_platform_driver(au1550nd_driver); diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index ab0caa7..0afd4ac 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -865,7 +865,7 @@ static int bf5xx_nand_resume(struct platform_device *dev) /* driver device registration */ static struct platform_driver bf5xx_nand_driver = { .probe = bf5xx_nand_probe, - .remove = __devexit_p(bf5xx_nand_remove), + .remove = bf5xx_nand_remove, .suspend = bf5xx_nand_suspend, .resume = bf5xx_nand_resume, .driver = { diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 2bb7170..1b62f04 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -887,7 +887,7 @@ static struct pci_driver cafe_nand_pci_driver = { .name = "CAFÉ NAND", .id_table = cafe_nand_tbl, .probe = cafe_nand_probe, - .remove = __devexit_p(cafe_nand_remove), + .remove = cafe_nand_remove, .resume = cafe_nand_resume, }; diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index fbabbaa..445de7c 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -142,7 +142,7 @@ static int __devexit denali_dt_remove(struct platform_device *ofdev) static struct platform_driver denali_dt_driver = { .probe = denali_dt_probe, - .remove = __devexit_p(denali_dt_remove), + .remove = denali_dt_remove, .driver = { .name = "denali-nand-dt", .owner = THIS_MODULE, diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 45df542..b40661d 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -350,7 +350,7 @@ static struct platform_driver of_fun_driver = { .of_match_table = of_fun_match, }, .probe = fun_probe, - .remove = __devexit_p(fun_remove), + .remove = fun_remove, }; module_platform_driver(of_fun_driver); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index d376198..7ce6d01 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1692,7 +1692,7 @@ static struct platform_driver gpmi_nand_driver = { .of_match_table = gpmi_nand_id_table, }, .probe = gpmi_nand_probe, - .remove = __devexit_p(gpmi_nand_remove), + .remove = gpmi_nand_remove, .id_table = gpmi_ids, }; module_platform_driver(gpmi_nand_driver); diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 100b677..2552fe2 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -573,7 +573,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev) static struct platform_driver jz_nand_driver = { .probe = jz_nand_probe, - .remove = __devexit_p(jz_nand_remove), + .remove = jz_nand_remove, .driver = { .name = "jz4740-nand", .owner = THIS_MODULE, diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index c29b7ac..3115642 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -907,7 +907,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); static struct platform_driver lpc32xx_nand_driver = { .probe = lpc32xx_nand_probe, - .remove = __devexit_p(lpc32xx_nand_remove), + .remove = lpc32xx_nand_remove, .resume = lpc32xx_nand_resume, .suspend = lpc32xx_nand_suspend, .driver = { diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 32409c4..9e291b7 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -1021,7 +1021,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); static struct platform_driver lpc32xx_nand_driver = { .probe = lpc32xx_nand_probe, - .remove = __devexit_p(lpc32xx_nand_remove), + .remove = lpc32xx_nand_remove, .resume = lpc32xx_nand_resume, .suspend = lpc32xx_nand_suspend, .driver = { diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index f776c85..17fe0c9 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -848,7 +848,7 @@ static struct of_device_id mpc5121_nfc_match[] __devinitdata = { static struct platform_driver mpc5121_nfc_driver = { .probe = mpc5121_nfc_probe, - .remove = __devexit_p(mpc5121_nfc_remove), + .remove = mpc5121_nfc_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 72e31d8..a4caf64 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1556,7 +1556,7 @@ static struct platform_driver mxcnd_driver = { .of_match_table = of_match_ptr(mxcnd_dt_ids), }, .probe = mxcnd_probe, - .remove = __devexit_p(mxcnd_remove), + .remove = mxcnd_remove, }; module_platform_driver(mxcnd_driver); diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 5fd3f01..32e6bef 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -279,7 +279,7 @@ static struct platform_driver ndfc_driver = { .of_match_table = ndfc_match, }, .probe = ndfc_probe, - .remove = __devexit_p(ndfc_remove), + .remove = ndfc_remove, }; module_platform_driver(ndfc_driver); diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 94dc46b..eed134c 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -340,7 +340,7 @@ static int __devexit nuc900_nand_remove(struct platform_device *pdev) static struct platform_driver nuc900_nand_driver = { .probe = nuc900_nand_probe, - .remove = __devexit_p(nuc900_nand_remove), + .remove = nuc900_nand_remove, .driver = { .name = "nuc900-fmi", .owner = THIS_MODULE, diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index aefaf8c..e6b296d 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -223,7 +223,7 @@ static struct of_device_id orion_nand_of_match_table[] = { #endif static struct platform_driver orion_nand_driver = { - .remove = __devexit_p(orion_nand_remove), + .remove = orion_nand_remove, .driver = { .name = "orion_nand", .owner = THIS_MODULE, diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index a47ee68..95a1dba 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -160,7 +160,7 @@ MODULE_DEVICE_TABLE(of, plat_nand_match); static struct platform_driver plat_nand_driver = { .probe = plat_nand_probe, - .remove = __devexit_p(plat_nand_remove), + .remove = plat_nand_remove, .driver = { .name = "gen_nand", .owner = THIS_MODULE, diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 3421e37..541fd51 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -228,7 +228,7 @@ static struct platform_driver sharpsl_nand_driver = { .owner = THIS_MODULE, }, .probe = sharpsl_nand_probe, - .remove = __devexit_p(sharpsl_nand_remove), + .remove = sharpsl_nand_remove, }; module_platform_driver(sharpsl_nand_driver); diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index f3f28fa..78b1a04 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -251,7 +251,7 @@ static struct platform_driver socrates_nand_driver = { .of_match_table = socrates_nand_match, }, .probe = socrates_nand_probe, - .remove = __devexit_p(socrates_nand_remove), + .remove = socrates_nand_remove, }; module_platform_driver(socrates_nand_driver); diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 1c4f97c..27aa44a 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -112,7 +112,7 @@ static struct platform_driver generic_onenand_driver = { .owner = THIS_MODULE, }, .probe = generic_onenand_probe, - .remove = __devexit_p(generic_onenand_remove), + .remove = generic_onenand_remove, }; module_platform_driver(generic_onenand_driver); diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 1961be9..73dac4c 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -811,7 +811,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) static struct platform_driver omap2_onenand_driver = { .probe = omap2_onenand_probe, - .remove = __devexit_p(omap2_onenand_remove), + .remove = omap2_onenand_remove, .shutdown = omap2_onenand_shutdown, .driver = { .name = DRIVER_NAME, diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 8e4b3f2..3d462cb 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -1130,7 +1130,7 @@ static struct platform_driver s3c_onenand_driver = { }, .id_table = s3c_onenand_driver_ids, .probe = s3c_onenand_probe, - .remove = __devexit_p(s3c_onenand_remove), + .remove = s3c_onenand_remove, }; module_platform_driver(s3c_onenand_driver); -- cgit v0.10.2 From 06f25510692385ed4dadd23f7d3d064d1ab11c2d Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:23:07 -0500 Subject: mtd: remove use of __devinit CONFIG_HOTPLUG is going away as an option so __devinit is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index bd2d912..ae43b01 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -755,7 +755,7 @@ static const struct spi_device_id m25p_ids[] = { }; MODULE_DEVICE_TABLE(spi, m25p_ids); -static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi) +static const struct spi_device_id *jedec_probe(struct spi_device *spi) { int tmp; u8 code = OPCODE_RDID; @@ -800,7 +800,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi) * matches what the READ command supports, at least until this driver * understands FAST_READ (for clocks over 25 MHz). */ -static int __devinit m25p_probe(struct spi_device *spi) +static int m25p_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); struct flash_platform_data *data; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 23ccc36..080cb1c 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -618,7 +618,7 @@ static char *otp_setup(struct mtd_info *device, char revision) /* * Register DataFlash device with MTD subsystem. */ -static int __devinit +static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages, int pagesize, int pageoffset, char revision) { @@ -679,7 +679,7 @@ add_dataflash_otp(struct spi_device *spi, char *name, return err; } -static inline int __devinit +static inline int add_dataflash(struct spi_device *spi, char *name, int nr_pages, int pagesize, int pageoffset) { @@ -740,7 +740,7 @@ static struct flash_info __devinitdata dataflash_data [] = { { "at45db642d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS}, }; -static struct flash_info *__devinit jedec_probe(struct spi_device *spi) +static struct flash_info *jedec_probe(struct spi_device *spi) { int tmp; uint8_t code = OP_READ_ID; @@ -823,7 +823,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) * AT45DB0642 64Mbit (8M) xx111xxx (0x3c) 8192 1056 11 * AT45DB1282 128Mbit (16M) xx0100xx (0x10) 16384 1056 11 */ -static int __devinit dataflash_probe(struct spi_device *spi) +static int dataflash_probe(struct spi_device *spi) { int status; struct flash_info *info; diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index e27737c..a30cd27 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -756,7 +756,7 @@ err_probe: #ifdef CONFIG_OF -static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev, +static int spear_smi_probe_config_dt(struct platform_device *pdev, struct device_node *np) { struct spear_smi_plat_data *pdata = dev_get_platdata(&pdev->dev); @@ -799,7 +799,7 @@ static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev, return 0; } #else -static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev, +static int spear_smi_probe_config_dt(struct platform_device *pdev, struct device_node *np) { return -ENOSYS; @@ -901,7 +901,7 @@ static int spear_smi_setup_banks(struct platform_device *pdev, * and do proper init for any found one. * Returns 0 on success, non zero otherwise */ -static int __devinit spear_smi_probe(struct platform_device *pdev) +static int spear_smi_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct spear_smi_plat_data *pdata = NULL; diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 9ebf86d..ab4154d 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -313,7 +313,7 @@ out: return ret; } -static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi) +static struct flash_info *sst25l_match_device(struct spi_device *spi) { struct flash_info *flash_info = NULL; struct spi_message m; @@ -353,7 +353,7 @@ static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi) return flash_info; } -static int __devinit sst25l_probe(struct spi_device *spi) +static int sst25l_probe(struct spi_device *spi) { struct flash_info *flash_info; struct sst25l_flash *flash; diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index e2875d6..1a4f671 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -100,7 +100,7 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window) } -static int __devinit amd76xrom_init_one (struct pci_dev *pdev, +static int amd76xrom_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c index ca0313d..b8c8589 100644 --- a/drivers/mtd/maps/autcpu12-nvram.c +++ b/drivers/mtd/maps/autcpu12-nvram.c @@ -33,7 +33,7 @@ struct autcpu12_nvram_priv { struct map_info map; }; -static int __devinit autcpu12_nvram_probe(struct platform_device *pdev) +static int autcpu12_nvram_probe(struct platform_device *pdev) { map_word tmp, save0, save1; struct resource *res; diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 340e8a2..658a7d0 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -123,7 +123,7 @@ static void bfin_flash_copy_to(struct map_info *map, unsigned long to, const voi static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; -static int __devinit bfin_flash_probe(struct platform_device *pdev) +static int bfin_flash_probe(struct platform_device *pdev) { int ret; struct physmap_flash_data *pdata = pdev->dev.platform_data; diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 3d0e762..65fedb9 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -112,7 +112,7 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window) } -static int __devinit ck804xrom_init_one (struct pci_dev *pdev, +static int ck804xrom_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index 08322b1..3797825 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -144,7 +144,7 @@ static void esb2rom_cleanup(struct esb2rom_window *window) pci_dev_put(window->pdev); } -static int __devinit esb2rom_init_one(struct pci_dev *pdev, +static int esb2rom_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 670af9a..9a6a3e1 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -185,7 +185,7 @@ static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; * ... * }; */ -static int __devinit gpio_flash_probe(struct platform_device *pdev) +static int gpio_flash_probe(struct platform_device *pdev) { size_t i, arr_size; struct physmap_flash_data *pdata; diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index 6689dcb..a9bab67 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -84,7 +84,7 @@ static void ichxrom_cleanup(struct ichxrom_window *window) } -static int __devinit ichxrom_init_one (struct pci_dev *pdev, +static int ichxrom_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index f6185d4..1694c03 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -68,7 +68,7 @@ static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p) mtd_device_unregister(p->info); } -static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p) +static int vr_nor_init_partitions(struct vr_nor_mtd *p) { /* register the flash bank */ /* partition the flash bank */ @@ -80,7 +80,7 @@ static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) map_destroy(p->info); } -static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p) +static int vr_nor_mtd_setup(struct vr_nor_mtd *p) { static const char *probe_types[] = { "cfi_probe", "jedec_probe", NULL }; @@ -116,7 +116,7 @@ static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p) * Initialize the map_info structure and map the flash. * Returns 0 on success, nonzero otherwise. */ -static int __devinit vr_nor_init_maps(struct vr_nor_mtd *p) +static int vr_nor_init_maps(struct vr_nor_mtd *p) { unsigned long csr_phys, csr_len; unsigned long win_phys, win_len; @@ -189,7 +189,7 @@ static void __devexit vr_nor_pci_remove(struct pci_dev *dev) pci_disable_device(dev); } -static int __devinit +static int vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct vr_nor_mtd *p = NULL; diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 4c032f1..58d1f61 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -109,7 +109,7 @@ ltq_copy_to(struct map_info *map, unsigned long to, spin_unlock_irqrestore(&ebu_lock, flags); } -static int __devinit +static int ltq_mtd_probe(struct platform_device *pdev) { struct mtd_part_parser_data ppdata; diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c index 962a76a..ab0fead 100644 --- a/drivers/mtd/maps/latch-addr-flash.c +++ b/drivers/mtd/maps/latch-addr-flash.c @@ -125,7 +125,7 @@ static int latch_addr_flash_remove(struct platform_device *dev) return 0; } -static int __devinit latch_addr_flash_probe(struct platform_device *dev) +static int latch_addr_flash_probe(struct platform_device *dev) { struct latch_addr_flash_data *latch_addr_data; struct latch_addr_flash_info *info; diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index ddc8c0c..81a8caf 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -253,7 +253,7 @@ static struct pci_device_id mtd_pci_ids[] = { * Generic code follows. */ -static int __devinit +static int mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data; diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index d7f19bc..cde8bf9 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -77,7 +77,7 @@ static int of_flash_remove(struct platform_device *dev) /* Helper function to handle probing of the obsolete "direct-mapped" * compatible binding, which has an extra "probe-type" property * describing the type of flash probe necessary. */ -static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev, +static struct mtd_info *obsolete_probe(struct platform_device *dev, struct map_info *map) { struct device_node *dp = dev->dev.of_node; @@ -116,7 +116,7 @@ static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev, information. */ static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL }; -static const char ** __devinit of_get_probes(struct device_node *dp) +static const char **of_get_probes(struct device_node *dp) { const char *cp; int cplen; @@ -145,14 +145,14 @@ static const char ** __devinit of_get_probes(struct device_node *dp) return res; } -static void __devinit of_free_probes(const char **probes) +static void of_free_probes(const char **probes) { if (probes != part_probe_types_def) kfree(probes); } static struct of_device_id of_flash_match[]; -static int __devinit of_flash_probe(struct platform_device *dev) +static int of_flash_probe(struct platform_device *dev) { const char **part_probe_types; const struct of_device_id *match; diff --git a/drivers/mtd/maps/pismo.c b/drivers/mtd/maps/pismo.c index 9f4e594..01db0d0 100644 --- a/drivers/mtd/maps/pismo.c +++ b/drivers/mtd/maps/pismo.c @@ -58,7 +58,7 @@ static void pismo_set_vpp(struct platform_device *pdev, int on) pismo->vpp(pismo->vpp_data, on); } -static unsigned int __devinit pismo_width_to_bytes(unsigned int width) +static unsigned int pismo_width_to_bytes(unsigned int width) { width &= 15; if (width > 2) @@ -66,7 +66,7 @@ static unsigned int __devinit pismo_width_to_bytes(unsigned int width) return 1 << width; } -static int __devinit pismo_eeprom_read(struct i2c_client *client, void *buf, +static int pismo_eeprom_read(struct i2c_client *client, void *buf, u8 addr, size_t size) { int ret; @@ -88,7 +88,7 @@ static int __devinit pismo_eeprom_read(struct i2c_client *client, void *buf, return ret == ARRAY_SIZE(msg) ? size : -EIO; } -static int __devinit pismo_add_device(struct pismo_data *pismo, int i, +static int pismo_add_device(struct pismo_data *pismo, int i, struct pismo_mem *region, const char *name, void *pdata, size_t psize) { struct platform_device *dev; @@ -129,7 +129,7 @@ static int __devinit pismo_add_device(struct pismo_data *pismo, int i, return ret; } -static int __devinit pismo_add_nor(struct pismo_data *pismo, int i, +static int pismo_add_nor(struct pismo_data *pismo, int i, struct pismo_mem *region) { struct physmap_flash_data data = { @@ -143,7 +143,7 @@ static int __devinit pismo_add_nor(struct pismo_data *pismo, int i, &data, sizeof(data)); } -static int __devinit pismo_add_sram(struct pismo_data *pismo, int i, +static int pismo_add_sram(struct pismo_data *pismo, int i, struct pismo_mem *region) { struct platdata_mtd_ram data = { @@ -154,7 +154,7 @@ static int __devinit pismo_add_sram(struct pismo_data *pismo, int i, &data, sizeof(data)); } -static void __devinit pismo_add_one(struct pismo_data *pismo, int i, +static void pismo_add_one(struct pismo_data *pismo, int i, const struct pismo_cs_block *cs, phys_addr_t base) { struct device *dev = &pismo->client->dev; @@ -210,7 +210,7 @@ static int __devexit pismo_remove(struct i2c_client *client) return 0; } -static int __devinit pismo_probe(struct i2c_client *client, +static int pismo_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index f913a1c..b5120f9 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -49,7 +49,7 @@ struct pxa2xx_flash_info { static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; -static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) +static int pxa2xx_flash_probe(struct platform_device *pdev) { struct flash_platform_data *flash = pdev->dev.platform_data; struct pxa2xx_flash_info *info; diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index a675bdb..7aebc82 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -149,8 +149,7 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla plat->exit(); } -static struct sa_info *__devinit -sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) +static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) { struct sa_info *info; int nr, size, i, ret = 0; @@ -246,7 +245,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; -static int __devinit sa1100_mtd_probe(struct platform_device *pdev) +static int sa1100_mtd_probe(struct platform_device *pdev) { struct flash_platform_data *plat = pdev->dev.platform_data; struct sa_info *info; diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index d527608..bb1857f 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c @@ -69,7 +69,7 @@ static struct map_info scb2_map = { }; static int region_fail; -static int __devinit +static int scb2_fixup_mtd(struct mtd_info *mtd) { int i; @@ -133,7 +133,7 @@ scb2_fixup_mtd(struct mtd_info *mtd) /* CSB5's 'Function Control Register' has bits for decoding @ >= 0xffc00000 */ #define CSB5_FCR 0x41 #define CSB5_FCR_DECODE_ALL 0x0e -static int __devinit +static int scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent) { u8 reg; diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 1c03ca7..2618e4d 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -108,7 +108,7 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp) return 0; } -static int __devinit uflash_probe(struct platform_device *op) +static int uflash_probe(struct platform_device *op) { struct device_node *dp = op->dev.of_node; diff --git a/drivers/mtd/maps/vmu-flash.c b/drivers/mtd/maps/vmu-flash.c index 5a83a26..84c3f5a 100644 --- a/drivers/mtd/maps/vmu-flash.c +++ b/drivers/mtd/maps/vmu-flash.c @@ -596,7 +596,7 @@ fail_name: } /* Handles very basic info about the flash, queries for details */ -static int __devinit vmu_connect(struct maple_device *mdev) +static int vmu_connect(struct maple_device *mdev) { unsigned long test_flash_data, basic_flash_data; int c, error; @@ -772,7 +772,7 @@ static void vmu_file_error(struct maple_device *mdev, void *recvbuf) } -static int __devinit probe_maple_vmu(struct device *dev) +static int probe_maple_vmu(struct device *dev) { int error; struct maple_device *mdev = to_maple_dev(dev); diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 51dba43..703e373 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -173,7 +173,7 @@ static const struct gpio _mandatory_gpio[] = { /* * Main initialization routine */ -static int __devinit ams_delta_init(struct platform_device *pdev) +static int ams_delta_init(struct platform_device *pdev) { struct nand_chip *this; struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 9144557..c918386 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -330,13 +330,13 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) * 12-bits 20-bytes 21-bytes * 24-bits 39-bytes 42-bytes */ -static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size) +static int pmecc_get_ecc_bytes(int cap, int sector_size) { int m = 12 + sector_size / 512; return (m * cap + 7) / 8; } -static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout, +static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, int oobsize, int ecc_len) { int i; @@ -352,7 +352,7 @@ static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout, oobsize - ecc_len - layout->oobfree[0].offset; } -static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) +static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) { int table_size; @@ -374,7 +374,7 @@ static void pmecc_data_free(struct atmel_nand_host *host) kfree(host->pmecc_delta); } -static int __devinit pmecc_data_alloc(struct atmel_nand_host *host) +static int pmecc_data_alloc(struct atmel_nand_host *host) { const int cap = host->pmecc_corr_cap; @@ -1205,7 +1205,7 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) } #if defined(CONFIG_OF) -static int __devinit atmel_of_init_port(struct atmel_nand_host *host, +static int atmel_of_init_port(struct atmel_nand_host *host, struct device_node *np) { u32 val, table_offset; @@ -1292,7 +1292,7 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host, return 0; } #else -static int __devinit atmel_of_init_port(struct atmel_nand_host *host, +static int atmel_of_init_port(struct atmel_nand_host *host, struct device_node *np) { return -EINVAL; diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index d84af46..73d6423 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -382,7 +382,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i while(!this->dev_ready(mtd)); } -static int __devinit find_nand_cs(unsigned long nand_base) +static int find_nand_cs(unsigned long nand_base) { void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR); @@ -403,7 +403,7 @@ static int __devinit find_nand_cs(unsigned long nand_base) return -ENODEV; } -static int __devinit au1550nd_probe(struct platform_device *pdev) +static int au1550nd_probe(struct platform_device *pdev) { struct au1550nd_platdata *pd; struct au1550nd_ctx *ctx; diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 0afd4ac..56de9b6 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -658,7 +658,7 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info) /* * Device management interface */ -static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info) +static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info) { struct mtd_info *mtd = &info->mtd; struct mtd_partition *parts = info->platform->partitions; @@ -725,7 +725,7 @@ static int bf5xx_nand_scan(struct mtd_info *mtd) * it can allocate all necessary resources then calls the * nand layer to look for devices */ -static int __devinit bf5xx_nand_probe(struct platform_device *pdev) +static int bf5xx_nand_probe(struct platform_device *pdev) { struct bf5xx_nand_platform *plat = to_nand_plat(pdev); struct bf5xx_nand_info *info = NULL; diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 1b62f04..480834a 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -585,7 +585,7 @@ static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) } /* F_2[X]/(X**6+X+1) */ -static unsigned short __devinit gf64_mul(u8 a, u8 b) +static unsigned short gf64_mul(u8 a, u8 b) { u8 c; unsigned int i; @@ -604,7 +604,7 @@ static unsigned short __devinit gf64_mul(u8 a, u8 b) } /* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X] */ -static u16 __devinit gf4096_mul(u16 a, u16 b) +static u16 gf4096_mul(u16 a, u16 b) { u8 ah, al, bh, bl, ch, cl; @@ -619,14 +619,14 @@ static u16 __devinit gf4096_mul(u16 a, u16 b) return (ch << 6) ^ cl; } -static int __devinit cafe_mul(int x) +static int cafe_mul(int x) { if (x == 0) return 1; return gf4096_mul(x, 0xe01); } -static int __devinit cafe_nand_probe(struct pci_dev *pdev, +static int cafe_nand_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct mtd_info *mtd; diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 445de7c..f9b593c 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -57,7 +57,7 @@ MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); static u64 denali_dma_mask; -static int __devinit denali_dt_probe(struct platform_device *ofdev) +static int denali_dt_probe(struct platform_device *ofdev) { struct resource *denali_reg, *nand_data; struct denali_dt *dt; diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index ea074e6..f1f8f89 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -130,7 +130,7 @@ static struct pci_driver denali_pci_driver = { .remove = denali_pci_remove, }; -static int __devinit denali_init_pci(void) +static int denali_init_pci(void) { pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__); return pci_register_driver(&denali_pci_driver); diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4c4d3e5..2065720 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -799,7 +799,7 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) static DEFINE_MUTEX(fsl_elbc_nand_mutex); -static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) +static int fsl_elbc_nand_probe(struct platform_device *pdev) { struct fsl_lbc_regs __iomem *lbc; struct fsl_elbc_mtd *priv; diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 5315231..ad62226 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -922,7 +922,7 @@ static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank, static DEFINE_MUTEX(fsl_ifc_nand_mutex); -static int __devinit fsl_ifc_nand_probe(struct platform_device *dev) +static int fsl_ifc_nand_probe(struct platform_device *dev) { struct fsl_ifc_regs __iomem *ifc; struct fsl_ifc_mtd *priv; diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index b40661d..a564325 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -152,7 +152,7 @@ static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) fun_wait_rnb(fun); } -static int __devinit fun_chip_init(struct fsl_upm_nand *fun, +static int fun_chip_init(struct fsl_upm_nand *fun, const struct device_node *upm_np, const struct resource *io_res) { @@ -201,7 +201,7 @@ err: return ret; } -static int __devinit fun_probe(struct platform_device *ofdev) +static int fun_probe(struct platform_device *ofdev) { struct fsl_upm_nand *fun; struct resource io_res; diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 6b59223..1d74464 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -864,7 +864,7 @@ static bool filter(struct dma_chan *chan, void *slave) } #ifdef CONFIG_OF -static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, +static int fsmc_nand_probe_config_dt(struct platform_device *pdev, struct device_node *np) { struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -886,7 +886,7 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, return 0; } #else -static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, +static int fsmc_nand_probe_config_dt(struct platform_device *pdev, struct device_node *np) { return -ENOSYS; diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 0b3c815..45f1a24 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -282,7 +282,7 @@ static void __iomem *request_and_remap(struct resource *res, size_t size, return ptr; } -static int __devinit gpio_nand_probe(struct platform_device *dev) +static int gpio_nand_probe(struct platform_device *dev) { struct gpiomtd *gpiomtd; struct nand_chip *this; diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 7ce6d01..2a251c9 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -319,7 +319,7 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, return 0; } -static int __devinit +static int acquire_register_block(struct gpmi_nand_data *this, const char *res_name) { struct platform_device *pdev = this->pdev; @@ -360,7 +360,7 @@ static void release_register_block(struct gpmi_nand_data *this) res->bch_regs = NULL; } -static int __devinit +static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) { struct platform_device *pdev = this->pdev; @@ -427,7 +427,7 @@ static void release_dma_channels(struct gpmi_nand_data *this) } } -static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) +static int acquire_dma_channels(struct gpmi_nand_data *this) { struct platform_device *pdev = this->pdev; struct resource *r_dma; @@ -492,7 +492,7 @@ static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = { "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch", }; -static int __devinit gpmi_get_clks(struct gpmi_nand_data *this) +static int gpmi_get_clks(struct gpmi_nand_data *this) { struct resources *r = &this->resources; char **extra_clks = NULL; @@ -538,7 +538,7 @@ err_clock: return -ENOMEM; } -static int __devinit acquire_resources(struct gpmi_nand_data *this) +static int acquire_resources(struct gpmi_nand_data *this) { struct pinctrl *pinctrl; int ret; @@ -588,7 +588,7 @@ static void release_resources(struct gpmi_nand_data *this) release_dma_channels(this); } -static int __devinit init_hardware(struct gpmi_nand_data *this) +static int init_hardware(struct gpmi_nand_data *this) { int ret; @@ -1542,7 +1542,7 @@ static void gpmi_nfc_exit(struct gpmi_nand_data *this) gpmi_free_dma_buffer(this); } -static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) +static int gpmi_nfc_init(struct gpmi_nand_data *this) { struct mtd_info *mtd = &this->mtd; struct nand_chip *chip = &this->nand; @@ -1625,7 +1625,7 @@ static const struct of_device_id gpmi_nand_id_table[] = { }; MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); -static int __devinit gpmi_nand_probe(struct platform_device *pdev) +static int gpmi_nand_probe(struct platform_device *pdev) { struct gpmi_nand_data *this; const struct of_device_id *of_id; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 2552fe2..5396b6c 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -322,7 +322,7 @@ static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem * release_mem_region(res->start, resource_size(res)); } -static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) { +static int jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) { int ret; int gpio; char gpio_name[9]; @@ -400,7 +400,7 @@ notfound_gpio: return ret; } -static int __devinit jz_nand_probe(struct platform_device *pdev) +static int jz_nand_probe(struct platform_device *pdev) { int ret; struct jz_nand *nand; diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 3115642..bb83daf 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -655,7 +655,7 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) /* * Probe for NAND controller */ -static int __devinit lpc32xx_nand_probe(struct platform_device *pdev) +static int lpc32xx_nand_probe(struct platform_device *pdev) { struct lpc32xx_nand_host *host; struct mtd_info *mtd; diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 9e291b7..17267f2 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -755,7 +755,7 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) /* * Probe for NAND controller */ -static int __devinit lpc32xx_nand_probe(struct platform_device *pdev) +static int lpc32xx_nand_probe(struct platform_device *pdev) { struct lpc32xx_nand_host *host; struct mtd_info *mtd; diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 17fe0c9..f779e6a 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -626,7 +626,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd) iounmap(prv->csreg); } -static int __devinit mpc5121_nfc_probe(struct platform_device *op) +static int mpc5121_nfc_probe(struct platform_device *op) { struct device_node *rootnode, *dn = op->dev.of_node; struct device *dev = &op->dev; diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a4caf64..77a03cf 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1363,7 +1363,7 @@ static int __init mxcnd_probe_pdata(struct mxc_nand_host *host) return 0; } -static int __devinit mxcnd_probe(struct platform_device *pdev) +static int mxcnd_probe(struct platform_device *pdev) { struct nand_chip *this; struct mtd_info *mtd; diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 32e6bef..6fa4588 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -197,7 +197,7 @@ err: return ret; } -static int __devinit ndfc_probe(struct platform_device *ofdev) +static int ndfc_probe(struct platform_device *ofdev) { struct ndfc_controller *ndfc; const __be32 *reg; diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index eed134c..00766df 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -246,7 +246,7 @@ static void nuc900_nand_enable(struct nuc900_nand *nand) spin_unlock(&nand->lock); } -static int __devinit nuc900_nand_probe(struct platform_device *pdev) +static int nuc900_nand_probe(struct platform_device *pdev) { struct nuc900_nand *nuc900_nand; struct nand_chip *chip; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 5b31386..b00ccb2 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1239,7 +1239,7 @@ static void omap3_free_bch(struct mtd_info *mtd) } #endif /* CONFIG_MTD_NAND_OMAP_BCH */ -static int __devinit omap_nand_probe(struct platform_device *pdev) +static int omap_nand_probe(struct platform_device *pdev) { struct omap_nand_info *info; struct omap_nand_platform_data *pdata; diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 1440e51..2e477cb 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -89,7 +89,7 @@ int pasemi_device_ready(struct mtd_info *mtd) return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR); } -static int __devinit pasemi_nand_probe(struct platform_device *ofdev) +static int pasemi_nand_probe(struct platform_device *ofdev) { struct pci_dev *pdev; struct device_node *np = ofdev->dev.of_node; diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 95a1dba..32e2996 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -28,7 +28,7 @@ static const char *part_probe_types[] = { "cmdlinepart", NULL }; /* * Probe for the NAND device. */ -static int __devinit plat_nand_probe(struct platform_device *pdev) +static int plat_nand_probe(struct platform_device *pdev) { struct platform_nand_data *pdata = pdev->dev.platform_data; struct mtd_part_parser_data ppdata; diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index d51e3c1..e45d6bd 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -1086,7 +1086,7 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) } #endif /* CONFIG_OF */ -static int __devinit flctl_probe(struct platform_device *pdev) +static int flctl_probe(struct platform_device *pdev) { struct resource *res; struct sh_flctl *flctl; diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 541fd51..870f0ff 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -106,7 +106,7 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, /* * Main initialization routine */ -static int __devinit sharpsl_nand_probe(struct platform_device *pdev) +static int sharpsl_nand_probe(struct platform_device *pdev) { struct nand_chip *this; struct resource *r; diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index 78b1a04..c9791fd 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -140,7 +140,7 @@ static int socrates_nand_device_ready(struct mtd_info *mtd) /* * Probe for the NAND device. */ -static int __devinit socrates_nand_probe(struct platform_device *ofdev) +static int socrates_nand_probe(struct platform_device *ofdev) { struct socrates_nand_host *host; struct mtd_info *mtd; diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 27aa44a..03e6af3 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -35,7 +35,7 @@ struct onenand_info { struct onenand_chip onenand; }; -static int __devinit generic_onenand_probe(struct platform_device *pdev) +static int generic_onenand_probe(struct platform_device *pdev) { struct onenand_info *info; struct onenand_platform_data *pdata = pdev->dev.platform_data; diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 73dac4c..8c10a2f 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -619,7 +619,7 @@ static int omap2_onenand_disable(struct mtd_info *mtd) return ret; } -static int __devinit omap2_onenand_probe(struct platform_device *pdev) +static int omap2_onenand_probe(struct platform_device *pdev) { struct omap_onenand_platform_data *pdata; struct omap2_onenand *c; -- cgit v0.10.2 From 042a190944675bc54790bcf45b8b2c86e68f003b Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:24:23 -0500 Subject: mtd: remove use of __devinitdata CONFIG_HOTPLUG is going away as an option so __devinitdata is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 080cb1c..0b3f173 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -705,7 +705,7 @@ struct flash_info { #define IS_POW2PS 0x0001 /* uses 2^N byte pages */ }; -static struct flash_info __devinitdata dataflash_data [] = { +static struct flash_info dataflash_data [] = { /* * NOTE: chips with SUP_POW2PS (rev D and up) need two entries, diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index ab4154d..e4f2339 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -64,7 +64,7 @@ struct flash_info { #define to_sst25l_flash(x) container_of(x, struct sst25l_flash, mtd) -static struct flash_info __devinitdata sst25l_flash_info[] = { +static struct flash_info sst25l_flash_info[] = { {"sst25lf020a", 0xbf43, 256, 1024, 4096}, {"sst25lf040a", 0xbf44, 256, 2048, 4096}, }; diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index 3797825..664303f 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -384,7 +384,7 @@ static void __devexit esb2rom_remove_one (struct pci_dev *pdev) esb2rom_cleanup(window); } -static struct pci_device_id esb2rom_pci_tbl[] __devinitdata = { +static struct pci_device_id esb2rom_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index a9bab67..9673601 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -321,7 +321,7 @@ static void __devexit ichxrom_remove_one (struct pci_dev *pdev) ichxrom_cleanup(window); } -static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = { +static struct pci_device_id ichxrom_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index f779e6a..09f75a5 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -841,7 +841,7 @@ static int __devexit mpc5121_nfc_remove(struct platform_device *op) return 0; } -static struct of_device_id mpc5121_nfc_match[] __devinitdata = { +static struct of_device_id mpc5121_nfc_match[] = { { .compatible = "fsl,mpc5121-nfc", }, {}, }; -- cgit v0.10.2 From 5e75e86e6d1561d5ae8e38412f93609475f19ed1 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:25:12 -0500 Subject: mtd: remove use of __devinitconst CONFIG_HOTPLUG is going away as an option so __devinitconst is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 658a7d0..6057c64 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -30,7 +30,7 @@ #include #include -#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); }) +#define pr_devinit(fmt, args...) ({ static const char __fmt[] = fmt; printk(__fmt, ## args); }) #define DRIVER_NAME "bfin-async-flash" diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 9a6a3e1..4babe04 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -26,7 +26,7 @@ #include #include -#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); }) +#define pr_devinit(fmt, args...) ({ static const char __fmt[] = fmt; printk(__fmt, ## args); }) #define DRIVER_NAME "gpio-addr-flash" #define PFX DRIVER_NAME ": " diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 58d1f61..0cf6c73 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -45,7 +45,7 @@ struct ltq_mtd { }; static const char ltq_map_name[] = "ltq_nor"; -static const char *ltq_probe_types[] __devinitconst = { +static const char *ltq_probe_types[] = { "cmdlinepart", "ofpart", NULL }; static map_word -- cgit v0.10.2 From 810b7e060c14110d8f580daaf77fab3a7d950483 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:26:04 -0500 Subject: mtd: remove use of __devexit CONFIG_HOTPLUG is going away as an option so __devexit is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index 113aced..4714584 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c @@ -66,7 +66,7 @@ out: return err; } -static int __devexit bcm47xxsflash_remove(struct platform_device *pdev) +static int bcm47xxsflash_remove(struct platform_device *pdev) { struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 681e2ee..8debac9 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -433,7 +433,7 @@ static int __init block2mtd_init(void) } -static void __devexit block2mtd_exit(void) +static void block2mtd_exit(void) { struct list_head *pos, *next; diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index ae43b01..f402b67 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -972,7 +972,7 @@ static int m25p_probe(struct spi_device *spi) } -static int __devexit m25p_remove(struct spi_device *spi) +static int m25p_remove(struct spi_device *spi) { struct m25p *flash = dev_get_drvdata(&spi->dev); int status; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 0b3f173..0caefb4 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -897,7 +897,7 @@ static int dataflash_probe(struct spi_device *spi) return status; } -static int __devexit dataflash_remove(struct spi_device *spi) +static int dataflash_remove(struct spi_device *spi) { struct dataflash *flash = dev_get_drvdata(&spi->dev); int status; diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index a30cd27..2d2c2a5 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -1016,7 +1016,7 @@ err: * * free all allocations and delete the partitions. */ -static int __devexit spear_smi_remove(struct platform_device *pdev) +static int spear_smi_remove(struct platform_device *pdev) { struct spear_smi *dev; struct spear_snor_flash *flash; diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index e4f2339..8091b01 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -411,7 +411,7 @@ static int sst25l_probe(struct spi_device *spi) return 0; } -static int __devexit sst25l_remove(struct spi_device *spi) +static int sst25l_remove(struct spi_device *spi) { struct sst25l_flash *flash = dev_get_drvdata(&spi->dev); int ret; diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 1a4f671..31ee5c8 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -289,7 +289,7 @@ static int amd76xrom_init_one (struct pci_dev *pdev, } -static void __devexit amd76xrom_remove_one (struct pci_dev *pdev) +static void amd76xrom_remove_one (struct pci_dev *pdev) { struct amd76xrom_window *window = &amd76xrom_window; diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c index b8c8589..a2dc2ae 100644 --- a/drivers/mtd/maps/autcpu12-nvram.c +++ b/drivers/mtd/maps/autcpu12-nvram.c @@ -105,7 +105,7 @@ static int autcpu12_nvram_probe(struct platform_device *pdev) return -ENOMEM; } -static int __devexit autcpu12_nvram_remove(struct platform_device *pdev) +static int autcpu12_nvram_remove(struct platform_device *pdev) { struct autcpu12_nvram_priv *priv = platform_get_drvdata(pdev); diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 6057c64..7d484de 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -172,7 +172,7 @@ static int bfin_flash_probe(struct platform_device *pdev) return 0; } -static int __devexit bfin_flash_remove(struct platform_device *pdev) +static int bfin_flash_remove(struct platform_device *pdev) { struct async_state *state = platform_get_drvdata(pdev); gpio_free(state->enet_flash_pin); diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 65fedb9..0ac41f2 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -320,7 +320,7 @@ static int ck804xrom_init_one (struct pci_dev *pdev, } -static void __devexit ck804xrom_remove_one (struct pci_dev *pdev) +static void ck804xrom_remove_one (struct pci_dev *pdev) { struct ck804xrom_window *window = &ck804xrom_window; diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index 664303f..6d6cb88 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -378,7 +378,7 @@ static int esb2rom_init_one(struct pci_dev *pdev, return 0; } -static void __devexit esb2rom_remove_one (struct pci_dev *pdev) +static void esb2rom_remove_one (struct pci_dev *pdev) { struct esb2rom_window *window = &esb2rom_window; esb2rom_cleanup(window); diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 4babe04..41aa8db 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -258,7 +258,7 @@ static int gpio_flash_probe(struct platform_device *pdev) return 0; } -static int __devexit gpio_flash_remove(struct platform_device *pdev) +static int gpio_flash_remove(struct platform_device *pdev) { struct async_state *state = platform_get_drvdata(pdev); size_t i = 0; diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index 9673601..03d60ef 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -315,7 +315,7 @@ static int ichxrom_init_one (struct pci_dev *pdev, } -static void __devexit ichxrom_remove_one (struct pci_dev *pdev) +static void ichxrom_remove_one (struct pci_dev *pdev) { struct ichxrom_window *window = &ichxrom_window; ichxrom_cleanup(window); diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index 1694c03..3ee2ad1 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -63,7 +63,7 @@ struct vr_nor_mtd { #define TIMING_BYTE_EN (1 << 0) /* 8-bit vs 16-bit bus */ #define TIMING_MASK 0x3FFF0000 -static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p) +static void vr_nor_destroy_partitions(struct vr_nor_mtd *p) { mtd_device_unregister(p->info); } @@ -75,7 +75,7 @@ static int vr_nor_init_partitions(struct vr_nor_mtd *p) return mtd_device_parse_register(p->info, NULL, NULL, NULL, 0); } -static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) +static void vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) { map_destroy(p->info); } @@ -96,7 +96,7 @@ static int vr_nor_mtd_setup(struct vr_nor_mtd *p) return 0; } -static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p) +static void vr_nor_destroy_maps(struct vr_nor_mtd *p) { unsigned int exp_timing_cs0; @@ -176,7 +176,7 @@ static struct pci_device_id vr_nor_pci_ids[] = { {0,} }; -static void __devexit vr_nor_pci_remove(struct pci_dev *dev) +static void vr_nor_pci_remove(struct pci_dev *dev) { struct vr_nor_mtd *p = pci_get_drvdata(dev); diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 0cf6c73..3c3c791 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -185,7 +185,7 @@ err_out: return err; } -static int __devexit +static int ltq_mtd_remove(struct platform_device *pdev) { struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index 81a8caf..ed82914 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -308,7 +308,7 @@ out: return err; } -static void __devexit +static void mtd_pci_remove(struct pci_dev *dev) { struct mtd_info *mtd = pci_get_drvdata(dev); diff --git a/drivers/mtd/maps/pismo.c b/drivers/mtd/maps/pismo.c index 01db0d0..afea93b 100644 --- a/drivers/mtd/maps/pismo.c +++ b/drivers/mtd/maps/pismo.c @@ -197,7 +197,7 @@ static void pismo_add_one(struct pismo_data *pismo, int i, } } -static int __devexit pismo_remove(struct i2c_client *client) +static int pismo_remove(struct i2c_client *client) { struct pismo_data *pismo = i2c_get_clientdata(client); int i; diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index b5120f9..43e3dbb 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -105,7 +105,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev) return 0; } -static int __devexit pxa2xx_flash_remove(struct platform_device *dev) +static int pxa2xx_flash_remove(struct platform_device *dev) { struct pxa2xx_flash_info *info = platform_get_drvdata(dev); diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index bb1857f..71796137 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c @@ -197,7 +197,7 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent) return 0; } -static void __devexit +static void scb2_flash_remove(struct pci_dev *dev) { if (!scb2_mtd) diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 2618e4d..d467f3b 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -121,7 +121,7 @@ static int uflash_probe(struct platform_device *op) return uflash_devinit(op, dp); } -static int __devexit uflash_remove(struct platform_device *op) +static int uflash_remove(struct platform_device *op) { struct uflash_dev *up = dev_get_drvdata(&op->dev); diff --git a/drivers/mtd/maps/vmu-flash.c b/drivers/mtd/maps/vmu-flash.c index 84c3f5a..6b223cf 100644 --- a/drivers/mtd/maps/vmu-flash.c +++ b/drivers/mtd/maps/vmu-flash.c @@ -690,7 +690,7 @@ fail_nomem: return error; } -static void __devexit vmu_disconnect(struct maple_device *mdev) +static void vmu_disconnect(struct maple_device *mdev) { struct memcard *card; struct mdev_part *mpart; @@ -789,7 +789,7 @@ static int probe_maple_vmu(struct device *dev) return 0; } -static int __devexit remove_maple_vmu(struct device *dev) +static int remove_maple_vmu(struct device *dev) { struct maple_device *mdev = to_maple_dev(dev); diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 703e373..f1d71cd 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -270,7 +270,7 @@ out_free: /* * Clean up routine */ -static int __devexit ams_delta_cleanup(struct platform_device *pdev) +static int ams_delta_cleanup(struct platform_device *pdev) { void __iomem *io_base = platform_get_drvdata(pdev); diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 73d6423..217459d 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -491,7 +491,7 @@ out1: return ret; } -static int __devexit au1550nd_remove(struct platform_device *pdev) +static int au1550nd_remove(struct platform_device *pdev) { struct au1550nd_ctx *ctx = platform_get_drvdata(pdev); struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 56de9b6..4271e94 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -667,7 +667,7 @@ static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info) return mtd_device_register(mtd, parts, nr); } -static int __devexit bf5xx_nand_remove(struct platform_device *pdev) +static int bf5xx_nand_remove(struct platform_device *pdev) { struct bf5xx_nand_info *info = to_nand_info(pdev); diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 480834a..010d612 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -821,7 +821,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, return err; } -static void __devexit cafe_nand_remove(struct pci_dev *pdev) +static void cafe_nand_remove(struct pci_dev *pdev) { struct mtd_info *mtd = pci_get_drvdata(pdev); struct cafe_priv *cafe = mtd->priv; diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index f9b593c..546f8cb 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -129,7 +129,7 @@ out_disable_clk: return ret; } -static int __devexit denali_dt_remove(struct platform_device *ofdev) +static int denali_dt_remove(struct platform_device *ofdev) { struct denali_dt *dt = platform_get_drvdata(ofdev); diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index f1f8f89..e3e4662 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -137,7 +137,7 @@ static int denali_init_pci(void) } module_init(denali_init_pci); -static void __devexit denali_exit_pci(void) +static void denali_exit_pci(void) { pci_unregister_driver(&denali_pci_driver); } diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index a564325..5a8f5c4 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -318,7 +318,7 @@ err1: return ret; } -static int __devexit fun_remove(struct platform_device *ofdev) +static int fun_remove(struct platform_device *ofdev) { struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); int i; diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 45f1a24..7aec569 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -231,7 +231,7 @@ gpio_nand_get_io_sync(struct platform_device *pdev) return platform_get_resource(pdev, IORESOURCE_MEM, 1); } -static int __devexit gpio_nand_remove(struct platform_device *dev) +static int gpio_nand_remove(struct platform_device *dev) { struct gpiomtd *gpiomtd = platform_get_drvdata(dev); struct resource *res; diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 2a251c9..5cd141f 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1675,7 +1675,7 @@ exit_acquire_resources: return ret; } -static int __devexit gpmi_nand_remove(struct platform_device *pdev) +static int gpmi_nand_remove(struct platform_device *pdev) { struct gpmi_nand_data *this = platform_get_drvdata(pdev); diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 5396b6c..72ac26e 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -541,7 +541,7 @@ err_free: return ret; } -static int __devexit jz_nand_remove(struct platform_device *pdev) +static int jz_nand_remove(struct platform_device *pdev) { struct jz_nand *nand = platform_get_drvdata(pdev); struct jz_nand_platform_data *pdata = pdev->dev.platform_data; diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index bb83daf..f182bef 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -845,7 +845,7 @@ err_exit1: /* * Remove NAND device */ -static int __devexit lpc32xx_nand_remove(struct platform_device *pdev) +static int lpc32xx_nand_remove(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); struct mtd_info *mtd = &host->mtd; diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 17267f2..030b78c 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -949,7 +949,7 @@ err_exit1: /* * Remove NAND device. */ -static int __devexit lpc32xx_nand_remove(struct platform_device *pdev) +static int lpc32xx_nand_remove(struct platform_device *pdev) { uint32_t tmp; struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 09f75a5..3c9cdcb 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -827,7 +827,7 @@ error: return retval; } -static int __devexit mpc5121_nfc_remove(struct platform_device *op) +static int mpc5121_nfc_remove(struct platform_device *op) { struct device *dev = &op->dev; struct mtd_info *mtd = dev_get_drvdata(dev); diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 77a03cf..4aef6a3 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1538,7 +1538,7 @@ escan: return err; } -static int __devexit mxcnd_remove(struct platform_device *pdev) +static int mxcnd_remove(struct platform_device *pdev) { struct mxc_nand_host *host = platform_get_drvdata(pdev); diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 6fa4588..8e148f1 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -256,7 +256,7 @@ static int ndfc_probe(struct platform_device *ofdev) return 0; } -static int __devexit ndfc_remove(struct platform_device *ofdev) +static int ndfc_remove(struct platform_device *ofdev) { struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 00766df..a619119 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -317,7 +317,7 @@ fail1: kfree(nuc900_nand); return retval; } -static int __devexit nuc900_nand_remove(struct platform_device *pdev) +static int nuc900_nand_remove(struct platform_device *pdev) { struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); struct resource *res; diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index e6b296d..cd72b92 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -194,7 +194,7 @@ no_res: return ret; } -static int __devexit orion_nand_remove(struct platform_device *pdev) +static int orion_nand_remove(struct platform_device *pdev) { struct mtd_info *mtd = platform_get_drvdata(pdev); struct nand_chip *nc = mtd->priv; diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 2e477cb..5a67082 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -184,7 +184,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev) return err; } -static int __devexit pasemi_nand_remove(struct platform_device *ofdev) +static int pasemi_nand_remove(struct platform_device *ofdev) { struct nand_chip *chip; diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 32e2996..c004566 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -134,7 +134,7 @@ out_free: /* * Remove a NAND device. */ -static int __devexit plat_nand_remove(struct platform_device *pdev) +static int plat_nand_remove(struct platform_device *pdev) { struct plat_nand_data *data = platform_get_drvdata(pdev); struct platform_nand_data *pdata = pdev->dev.platform_data; diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index e45d6bd..2a21596 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -1198,7 +1198,7 @@ err_iomap: return ret; } -static int __devexit flctl_remove(struct platform_device *pdev) +static int flctl_remove(struct platform_device *pdev) { struct sh_flctl *flctl = platform_get_drvdata(pdev); diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 870f0ff..127bc42 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -205,7 +205,7 @@ err_get_res: /* * Clean up routine */ -static int __devexit sharpsl_nand_remove(struct platform_device *pdev) +static int sharpsl_nand_remove(struct platform_device *pdev) { struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev); diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index c9791fd..09dde7d 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -220,7 +220,7 @@ out: /* * Remove a NAND device. */ -static int __devexit socrates_nand_remove(struct platform_device *ofdev) +static int socrates_nand_remove(struct platform_device *ofdev) { struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev); struct mtd_info *mtd = &host->mtd; diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 03e6af3..9f11562 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -88,7 +88,7 @@ out_free_info: return err; } -static int __devexit generic_onenand_remove(struct platform_device *pdev) +static int generic_onenand_remove(struct platform_device *pdev) { struct onenand_info *info = platform_get_drvdata(pdev); struct resource *res = pdev->resource; diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 8c10a2f..b364e6c 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -787,7 +787,7 @@ err_kfree: return r; } -static int __devexit omap2_onenand_remove(struct platform_device *pdev) +static int omap2_onenand_remove(struct platform_device *pdev) { struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 3d462cb..33f2a8f 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -1053,7 +1053,7 @@ onenand_fail: return err; } -static int __devexit s3c_onenand_remove(struct platform_device *pdev) +static int s3c_onenand_remove(struct platform_device *pdev) { struct mtd_info *mtd = platform_get_drvdata(pdev); -- cgit v0.10.2 From 7bf350b7245b40fe6a57b79ec4a04c85195dc648 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 22 Nov 2012 12:16:28 +0200 Subject: mtd: fix a number of checkpatch complaints While checking the "__devinit" removal patches with checkpatch.pl, I noticed several warnings related to a space between the function name and '(', as well as long lines. I fixed the warnings up in this patch. Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 0caefb4..ea7ea7b 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -705,7 +705,7 @@ struct flash_info { #define IS_POW2PS 0x0001 /* uses 2^N byte pages */ }; -static struct flash_info dataflash_data [] = { +static struct flash_info dataflash_data[] = { /* * NOTE: chips with SUP_POW2PS (rev D and up) need two entries, diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 31ee5c8..f7207b0 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -100,8 +100,8 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window) } -static int amd76xrom_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) +static int amd76xrom_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; u8 byte; @@ -289,7 +289,7 @@ static int amd76xrom_init_one (struct pci_dev *pdev, } -static void amd76xrom_remove_one (struct pci_dev *pdev) +static void amd76xrom_remove_one(struct pci_dev *pdev) { struct amd76xrom_window *window = &amd76xrom_window; @@ -347,4 +347,3 @@ module_exit(cleanup_amd76xrom); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Eric Biederman "); MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge"); - diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 7d484de..f833edf 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -30,7 +30,8 @@ #include #include -#define pr_devinit(fmt, args...) ({ static const char __fmt[] = fmt; printk(__fmt, ## args); }) +#define pr_devinit(fmt, args...) \ + ({ static const char __fmt[] = fmt; printk(__fmt, ## args); }) #define DRIVER_NAME "bfin-async-flash" diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 0ac41f2..586a1c7 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -112,8 +112,8 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window) } -static int ck804xrom_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) +static int ck804xrom_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; u8 byte; @@ -320,7 +320,7 @@ static int ck804xrom_init_one (struct pci_dev *pdev, } -static void ck804xrom_remove_one (struct pci_dev *pdev) +static void ck804xrom_remove_one(struct pci_dev *pdev) { struct ck804xrom_window *window = &ck804xrom_window; diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index 6d6cb88..ff8681a 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -378,7 +378,7 @@ static int esb2rom_init_one(struct pci_dev *pdev, return 0; } -static void esb2rom_remove_one (struct pci_dev *pdev) +static void esb2rom_remove_one(struct pci_dev *pdev) { struct esb2rom_window *window = &esb2rom_window; esb2rom_cleanup(window); diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 41aa8db..7b643de 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -26,7 +26,8 @@ #include #include -#define pr_devinit(fmt, args...) ({ static const char __fmt[] = fmt; printk(__fmt, ## args); }) +#define pr_devinit(fmt, args...) \ + ({ static const char __fmt[] = fmt; printk(__fmt, ## args); }) #define DRIVER_NAME "gpio-addr-flash" #define PFX DRIVER_NAME ": " @@ -142,7 +143,8 @@ static void gf_write(struct map_info *map, map_word d1, unsigned long ofs) * * See gf_copy_from() caveat. */ -static void gf_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +static void gf_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) { struct async_state *state = gf_map_info_to_state(map); diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index 03d60ef..c7478e1 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -84,8 +84,8 @@ static void ichxrom_cleanup(struct ichxrom_window *window) } -static int ichxrom_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) +static int ichxrom_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; struct ichxrom_window *window = &ichxrom_window; @@ -315,7 +315,7 @@ static int ichxrom_init_one (struct pci_dev *pdev, } -static void ichxrom_remove_one (struct pci_dev *pdev) +static void ichxrom_remove_one(struct pci_dev *pdev) { struct ichxrom_window *window = &ichxrom_window; ichxrom_cleanup(window); diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index 7aebc82..f694417 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -149,7 +149,8 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla plat->exit(); } -static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) +static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev, + struct flash_platform_data *plat) { struct sa_info *info; int nr, size, i, ret = 0; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 72ac26e..8d415f0 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -316,13 +316,17 @@ err: return ret; } -static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base) +static inline void jz_nand_iounmap_resource(struct resource *res, + void __iomem *base) { iounmap(base); release_mem_region(res->start, resource_size(res)); } -static int jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) { +static int jz_nand_detect_bank(struct platform_device *pdev, + struct jz_nand *nand, unsigned char bank, + size_t chipnr, uint8_t *nand_maf_id, + uint8_t *nand_dev_id) { int ret; int gpio; char gpio_name[9]; -- cgit v0.10.2 From c5d5474425c4e7e291a98e739ea65f8acd0d8d5c Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Mon, 19 Nov 2012 13:17:48 +0100 Subject: i2c: ocores: Move grlib set/get functions into #ifdef CONFIG_OF block This moves the grlib set and get functions into the #ifdef CONFIG_OF block to avoid warnings of unimplemented functions when compiling with -Wunused-function when CONFIG_OF is not defined. Signed-off-by: Andreas Larsson Acked-by: Peter Korsgaard Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 0ea8419..df69598 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -109,40 +109,6 @@ static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) return ioread32(i2c->base + (reg << i2c->reg_shift)); } -/* Read and write functions for the GRLIB port of the controller. Registers are - * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one - * register. The subsequent registers has their offset decreased accordingly. */ -static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) -{ - u32 rd; - int rreg = reg; - if (reg != OCI2C_PRELOW) - rreg--; - rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); - if (reg == OCI2C_PREHIGH) - return (u8)(rd >> 8); - else - return (u8)rd; -} - -static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) -{ - u32 curr, wr; - int rreg = reg; - if (reg != OCI2C_PRELOW) - rreg--; - if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { - curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); - if (reg == OCI2C_PRELOW) - wr = (curr & 0xff00) | value; - else - wr = (((u32)value) << 8) | (curr & 0xff); - } else { - wr = value; - } - iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); -} - static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { i2c->setreg(i2c, reg, value); @@ -303,6 +269,40 @@ static struct of_device_id ocores_i2c_match[] = { MODULE_DEVICE_TABLE(of, ocores_i2c_match); #ifdef CONFIG_OF +/* Read and write functions for the GRLIB port of the controller. Registers are + * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one + * register. The subsequent registers has their offset decreased accordingly. */ +static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) +{ + u32 rd; + int rreg = reg; + if (reg != OCI2C_PRELOW) + rreg--; + rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PREHIGH) + return (u8)(rd >> 8); + else + return (u8)rd; +} + +static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) +{ + u32 curr, wr; + int rreg = reg; + if (reg != OCI2C_PRELOW) + rreg--; + if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { + curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PRELOW) + wr = (curr & 0xff00) | value; + else + wr = (((u32)value) << 8) | (curr & 0xff); + } else { + wr = value; + } + iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); +} + static int ocores_i2c_of_probe(struct platform_device *pdev, struct ocores_i2c *i2c) { -- cgit v0.10.2 From 31f313d9bebfc17e48c787c8c36b38662b4134a1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 21 Nov 2012 13:12:11 +0900 Subject: i2c: s3c2410: Remove recently introduced performance overheads The changes in "i2c-s3c2410: use exponential back off while polling for bus idle" remove the initial busy wait for I2C transfers to complete and replace it with usleep_range() calls which will schedule. Since for older SoCs I2C transfers would usually complete within an extremely small number of CPU cycles there is a win from not having to schedule. This happens because on the older SoCs the cores run at a smaller multiple of the speeds that the I2C bus is operating at; on more modern SoCs the busy wait is less likely to be effective. Fix the issue by restoring the busy wait, reducing the number of spins from 20 to 3 which covers the overwhelming majority of I2C transfers on the SoCs where the busy wait is effective. Signed-off-by: Mark Brown Acked-by: Olof Johansson Reviewed-by: Daniel Kurtz Reviewed-by: Doug Anderson Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index d784c76..e93e7d6 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -554,6 +554,7 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c) unsigned long iicstat; ktime_t start, now; unsigned long delay; + int spins; /* ensure the stop has been through the bus */ @@ -566,12 +567,23 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c) * end of a transaction. However, really slow i2c devices can stretch * the clock, delaying STOP generation. * - * As a compromise between idle detection latency for the normal, fast - * case, and system load in the slow device case, use an exponential - * back off in the polling loop, up to 1/10th of the total timeout, - * then continue to poll at a constant rate up to the timeout. + * On slower SoCs this typically happens within a very small number of + * instructions so busy wait briefly to avoid scheduling overhead. */ + spins = 3; iicstat = readl(i2c->regs + S3C2410_IICSTAT); + while ((iicstat & S3C2410_IICSTAT_START) && --spins) { + cpu_relax(); + iicstat = readl(i2c->regs + S3C2410_IICSTAT); + } + + /* + * If we do get an appreciable delay as a compromise between idle + * detection latency for the normal, fast case, and system load in the + * slow device case, use an exponential back off in the polling loop, + * up to 1/10th of the total timeout, then continue to poll at a + * constant rate up to the timeout. + */ delay = 1; while ((iicstat & S3C2410_IICSTAT_START) && ktime_us_delta(now, start) < S3C2410_IDLE_TIMEOUT) { -- cgit v0.10.2 From ce20364bf75b0e91156698eea49f1e8586b212c1 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Thu, 25 Oct 2012 09:39:13 +0530 Subject: pwm: Add SPEAr PWM chip driver support Add support for PWM chips present on SPEAr platforms. These PWM chips support 4 channel output with programmable duty cycle and frequency. More details on these PWM chips can be obtained from relevant chapter of reference manual, present at following[1] location. 1. http://www.st.com/internet/mcu/product/251211.jsp Cc: Thierry Reding Signed-off-by: Shiraz Hashim Signed-off-by: Viresh Kumar Reviewed-by: Vipin Kumar Acked-by: Viresh Kumar Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/pwm/spear-pwm.txt b/Documentation/devicetree/bindings/pwm/spear-pwm.txt new file mode 100644 index 0000000..3ac779d --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/spear-pwm.txt @@ -0,0 +1,18 @@ +== ST SPEAr SoC PWM controller == + +Required properties: +- compatible: should be one of: + - "st,spear320-pwm" + - "st,spear1340-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: number of cells used to specify PWM which is fixed to 2 on + SPEAr. The first cell specifies the per-chip index of the PWM to use and + the second cell is the period in nanoseconds. + +Example: + + pwm: pwm@a8000000 { + compatible ="st,spear320-pwm"; + reg = <0xa8000000 0x1000>; + #pwm-cells = <2>; + }; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index ed81720..6e556c7 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -112,6 +112,17 @@ config PWM_SAMSUNG To compile this driver as a module, choose M here: the module will be called pwm-samsung. +config PWM_SPEAR + tristate "STMicroelectronics SPEAr PWM support" + depends on PLAT_SPEAR + depends on OF + help + Generic PWM framework driver for the PWM controller on ST + SPEAr SoCs. + + To compile this driver as a module, choose M here: the module + will be called pwm-spear. + config PWM_TEGRA tristate "NVIDIA Tegra PWM support" depends on ARCH_TEGRA diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index acfe482..3b3f4c9a 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o +obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c new file mode 100644 index 0000000..6a8fd9b --- /dev/null +++ b/drivers/pwm/pwm-spear.c @@ -0,0 +1,276 @@ +/* + * ST Microelectronics SPEAr Pulse Width Modulator driver + * + * Copyright (C) 2012 ST Microelectronics + * Shiraz Hashim + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NUM_PWM 4 + +/* PWM registers and bits definitions */ +#define PWMCR 0x00 /* Control Register */ +#define PWMCR_PWM_ENABLE 0x1 +#define PWMCR_PRESCALE_SHIFT 2 +#define PWMCR_MIN_PRESCALE 0x00 +#define PWMCR_MAX_PRESCALE 0x3FFF + +#define PWMDCR 0x04 /* Duty Cycle Register */ +#define PWMDCR_MIN_DUTY 0x0001 +#define PWMDCR_MAX_DUTY 0xFFFF + +#define PWMPCR 0x08 /* Period Register */ +#define PWMPCR_MIN_PERIOD 0x0001 +#define PWMPCR_MAX_PERIOD 0xFFFF + +/* Following only available on 13xx SoCs */ +#define PWMMCR 0x3C /* Master Control Register */ +#define PWMMCR_PWM_ENABLE 0x1 + +/** + * struct spear_pwm_chip - struct representing pwm chip + * + * @mmio_base: base address of pwm chip + * @clk: pointer to clk structure of pwm chip + * @chip: linux pwm chip representation + * @dev: pointer to device structure of pwm chip + */ +struct spear_pwm_chip { + void __iomem *mmio_base; + struct clk *clk; + struct pwm_chip chip; + struct device *dev; +}; + +static inline struct spear_pwm_chip *to_spear_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct spear_pwm_chip, chip); +} + +static inline u32 spear_pwm_readl(struct spear_pwm_chip *chip, unsigned int num, + unsigned long offset) +{ + return readl_relaxed(chip->mmio_base + (num << 4) + offset); +} + +static inline void spear_pwm_writel(struct spear_pwm_chip *chip, + unsigned int num, unsigned long offset, + unsigned long val) +{ + writel_relaxed(val, chip->mmio_base + (num << 4) + offset); +} + +int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, + int period_ns) +{ + struct spear_pwm_chip *pc = to_spear_pwm_chip(chip); + u64 val, div, clk_rate; + unsigned long prescale = PWMCR_MIN_PRESCALE, pv, dc; + int ret; + + /* + * Find pv, dc and prescale to suit duty_ns and period_ns. This is done + * according to formulas described below: + * + * period_ns = 10^9 * (PRESCALE + 1) * PV / PWM_CLK_RATE + * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE + * + * PV = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1)) + * DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1)) + */ + clk_rate = clk_get_rate(pc->clk); + while (1) { + div = 1000000000; + div *= 1 + prescale; + val = clk_rate * period_ns; + pv = div64_u64(val, div); + val = clk_rate * duty_ns; + dc = div64_u64(val, div); + + /* if duty_ns and period_ns are not achievable then return */ + if (pv < PWMPCR_MIN_PERIOD || dc < PWMDCR_MIN_DUTY) + return -EINVAL; + + /* + * if pv and dc have crossed their upper limit, then increase + * prescale and recalculate pv and dc. + */ + if (pv > PWMPCR_MAX_PERIOD || dc > PWMDCR_MAX_DUTY) { + if (++prescale > PWMCR_MAX_PRESCALE) + return -EINVAL; + continue; + } + break; + } + + /* + * NOTE: the clock to PWM has to be enabled first before writing to the + * registers. + */ + ret = clk_enable(pc->clk); + if (ret) + return ret; + + spear_pwm_writel(pc, pwm->hwpwm, PWMCR, + prescale << PWMCR_PRESCALE_SHIFT); + spear_pwm_writel(pc, pwm->hwpwm, PWMDCR, dc); + spear_pwm_writel(pc, pwm->hwpwm, PWMPCR, pv); + clk_disable(pc->clk); + + return 0; +} + +static int spear_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct spear_pwm_chip *pc = to_spear_pwm_chip(chip); + int rc = 0; + u32 val; + + rc = clk_enable(pc->clk); + if (!rc) + return rc; + + val = spear_pwm_readl(pc, pwm->hwpwm, PWMCR); + val |= PWMCR_PWM_ENABLE; + spear_pwm_writel(pc, pwm->hwpwm, PWMCR, val); + + return 0; +} + +static void spear_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct spear_pwm_chip *pc = to_spear_pwm_chip(chip); + u32 val; + + val = spear_pwm_readl(pc, pwm->hwpwm, PWMCR); + val &= ~PWMCR_PWM_ENABLE; + spear_pwm_writel(pc, pwm->hwpwm, PWMCR, val); + + clk_disable(pc->clk); +} + +static const struct pwm_ops spear_pwm_ops = { + .config = spear_pwm_config, + .enable = spear_pwm_enable, + .disable = spear_pwm_disable, + .owner = THIS_MODULE, +}; + +static int spear_pwm_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct spear_pwm_chip *pc; + struct resource *r; + int ret; + u32 val; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "no memory resources defined\n"); + return -ENODEV; + } + + pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); + if (!pc) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r); + if (!pc->mmio_base) + return -EADDRNOTAVAIL; + + pc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pc->clk)) + return PTR_ERR(pc->clk); + + pc->dev = &pdev->dev; + platform_set_drvdata(pdev, pc); + + pc->chip.dev = &pdev->dev; + pc->chip.ops = &spear_pwm_ops; + pc->chip.base = -1; + pc->chip.npwm = NUM_PWM; + + ret = clk_prepare(pc->clk); + if (!ret) + return ret; + + if (of_device_is_compatible(np, "st,spear1340-pwm")) { + ret = clk_enable(pc->clk); + if (!ret) { + clk_unprepare(pc->clk); + return ret; + } + /* + * Following enables PWM chip, channels would still be + * enabled individually through their control register + */ + val = readl_relaxed(pc->mmio_base + PWMMCR); + val |= PWMMCR_PWM_ENABLE; + writel_relaxed(val, pc->mmio_base + PWMMCR); + + clk_disable(pc->clk); + } + + ret = pwmchip_add(&pc->chip); + if (!ret) { + clk_unprepare(pc->clk); + dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); + } + + return ret; +} + +static int spear_pwm_remove(struct platform_device *pdev) +{ + struct spear_pwm_chip *pc = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < NUM_PWM; i++) + pwm_disable(&pc->chip.pwms[i]); + + /* clk was prepared in probe, hence unprepare it here */ + clk_unprepare(pc->clk); + return pwmchip_remove(&pc->chip); +} + +static struct of_device_id spear_pwm_of_match[] = { + { .compatible = "st,spear320-pwm" }, + { .compatible = "st,spear1340-pwm" }, + { } +}; + +MODULE_DEVICE_TABLE(of, spear_pwm_of_match); + +static struct platform_driver spear_pwm_driver = { + .driver = { + .name = "spear-pwm", + .of_match_table = spear_pwm_of_match, + }, + .probe = spear_pwm_probe, + .remove = spear_pwm_remove, +}; + +module_platform_driver(spear_pwm_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Shiraz Hashim "); +MODULE_AUTHOR("Viresh Kumar "); +MODULE_ALIAS("platform:spear-pwm"); -- cgit v0.10.2 From c9371360997ba26c7e341b3d91d530e16a6aab1b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 9 Nov 2012 19:52:22 +0800 Subject: pwm: spear: Staticize spear_pwm_config() spear_pwm_config() is not referenced outside of this file, make it static. Signed-off-by: Axel Lin Acked-by: Viresh Kumar Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c index 6a8fd9b..83b21d9 100644 --- a/drivers/pwm/pwm-spear.c +++ b/drivers/pwm/pwm-spear.c @@ -76,8 +76,8 @@ static inline void spear_pwm_writel(struct spear_pwm_chip *chip, writel_relaxed(val, chip->mmio_base + (num << 4) + offset); } -int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, - int period_ns) +static int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) { struct spear_pwm_chip *pc = to_spear_pwm_chip(chip); u64 val, div, clk_rate; -- cgit v0.10.2 From 2f9569f7ceab31242b306d040861737580e1876f Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Tue, 20 Nov 2012 06:44:45 +1300 Subject: pwm: vt8500: Fix build error A missing '{' causes a build error in pwm-vt8500.c Signed-off-by: Tony Prisk Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index 970b0c6..806f72c 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -100,7 +100,7 @@ static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) struct vt8500_chip *vt8500 = to_vt8500_chip(chip); err = clk_enable(vt8500->clk); - if (err < 0) + if (err < 0) { dev_err(chip->dev, "failed to enable clock\n"); return err; }; -- cgit v0.10.2 From 422470a8265fbb1d182c00ab2421f4b416ab2dba Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Tue, 20 Nov 2012 06:44:46 +1300 Subject: pwm: vt8500: Ensure PWM clock is enabled during pwm_config This patch corrects a bug reported by Peter Vasil. When all PWMs are disabled, PWM module may be disabled during calls to pwm_config. This patch enables/disables the clock in pwm_config to ensure the module is active before register read/ writes. Signed-off-by: Tony Prisk Tested-by: Peter Vasil Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index 806f72c..b0ba2d4 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -62,6 +62,13 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, struct vt8500_chip *vt8500 = to_vt8500_chip(chip); unsigned long long c; unsigned long period_cycles, prescale, pv, dc; + int err; + + err = clk_enable(vt8500->clk); + if (err < 0) { + dev_err(chip->dev, "failed to enable clock\n"); + return err; + } c = clk_get_rate(vt8500->clk); c = c * period_ns; @@ -75,8 +82,10 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, if (pv > 4095) pv = 4095; - if (prescale > 1023) + if (prescale > 1023) { + clk_disable(vt8500->clk); return -EINVAL; + } c = (unsigned long long)pv * duty_ns; do_div(c, period_ns); @@ -91,6 +100,7 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3)); writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4)); + clk_disable(vt8500->clk); return 0; } @@ -103,7 +113,7 @@ static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) if (err < 0) { dev_err(chip->dev, "failed to enable clock\n"); return err; - }; + } pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); writel(5, vt8500->base + (pwm->hwpwm << 4)); -- cgit v0.10.2 From 83af24027b3df1af5c5a9aa9adcdcfeb3429d3be Mon Sep 17 00:00:00 2001 From: "Philip, Avinash" Date: Wed, 21 Nov 2012 13:10:44 +0530 Subject: pwm: Device tree support for PWM polarity Add support for encoding PWM properties in bit encoded form with of_pwm_xlate_with_flags() function support. Platforms require platform specific PWM properties has to populate in 3rd cell of the pwm-specifier and PWM driver should also set .of_xlate support with this function. Currently PWM property polarity encoded in bit position 0 of the third cell in pwm-specifier. Signed-off-by: Philip, Avinash Acked-by: Grant Likely Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt b/Documentation/devicetree/bindings/pwm/pwm.txt index 73ec962..06e6724 100644 --- a/Documentation/devicetree/bindings/pwm/pwm.txt +++ b/Documentation/devicetree/bindings/pwm/pwm.txt @@ -37,10 +37,21 @@ device: pwm-names = "backlight"; }; +Note that in the example above, specifying the "pwm-names" is redundant +because the name "backlight" would be used as fallback anyway. + pwm-specifier typically encodes the chip-relative PWM number and the PWM -period in nanoseconds. Note that in the example above, specifying the -"pwm-names" is redundant because the name "backlight" would be used as -fallback anyway. +period in nanoseconds. + +Optionally, the pwm-specifier can encode a number of flags in a third cell: +- bit 0: PWM signal polarity (0: normal polarity, 1: inverse polarity) + +Example with optional PWM specifier for inverse polarity + + bl: backlight { + pwms = <&pwm 0 5000000 1>; + pwm-names = "backlight"; + }; 2) PWM controller nodes ----------------------- diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index f5acdaa..780cb6b 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -32,6 +32,9 @@ #define MAX_PWMS 1024 +/* flags in the third cell of the DT PWM specifier */ +#define PWM_SPEC_POLARITY (1 << 0) + static DEFINE_MUTEX(pwm_lookup_lock); static LIST_HEAD(pwm_lookup_list); static DEFINE_MUTEX(pwm_lock); @@ -129,6 +132,31 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) return 0; } +struct pwm_device * +of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) +{ + struct pwm_device *pwm; + + if (pc->of_pwm_n_cells < 3) + return ERR_PTR(-EINVAL); + + if (args->args[0] >= pc->npwm) + return ERR_PTR(-EINVAL); + + pwm = pwm_request_from_chip(pc, args->args[0], NULL); + if (IS_ERR(pwm)) + return pwm; + + pwm_set_period(pwm, args->args[1]); + + if (args->args[2] & PWM_SPEC_POLARITY) + pwm_set_polarity(pwm, PWM_POLARITY_INVERSED); + else + pwm_set_polarity(pwm, PWM_POLARITY_NORMAL); + + return pwm; +} + static struct pwm_device * of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) { diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 112b314..6d661f3 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -171,6 +171,9 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, unsigned int index, const char *label); +struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *pc, + const struct of_phandle_args *args); + struct pwm_device *pwm_get(struct device *dev, const char *consumer); void pwm_put(struct pwm_device *pwm); -- cgit v0.10.2 From c35d3cfdbc8d4fb4358a5bc97a334dbdb86e3d69 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 18 Nov 2012 06:25:07 +0100 Subject: i2c: mxs: Handle i2c DMA failure properly Properly terminate the DMA transfer in case the DMA PIO transfer or setup fails for any reason. Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 286ca19..0670da7 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -287,12 +287,14 @@ read_init_dma_fail: select_init_dma_fail: dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); select_init_pio_fail: + dmaengine_terminate_all(i2c->dmach); return -EINVAL; /* Write failpath. */ write_init_dma_fail: dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); write_init_pio_fail: + dmaengine_terminate_all(i2c->dmach); return -EINVAL; } -- cgit v0.10.2 From 8f414059c66f57f610b71adf66fe20d8811bff8f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 18 Nov 2012 06:25:08 +0100 Subject: i2c: mxs: Do not disable the I2C SMBus quick mode There is no reason to disable the I2C SMBus quick mode on this IP block. Enable it. This essentially fixes the problem with the "i2c-detect" command for probing the bus. Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 0670da7..6ed53da 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -359,7 +359,7 @@ static int mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], static u32 mxs_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) -- cgit v0.10.2 From 037db524a2015607031c70a7935153120601b908 Mon Sep 17 00:00:00 2001 From: Vipul Kumar Samar Date: Thu, 22 Nov 2012 23:42:12 -0800 Subject: Input: stmpe-ts - add DT support for stmpe touchscreen This patch allows the STMPE Touchscreen driver to be successfully probed and initialised when Device Tree support is enabled. Bindings are mentioned in Documentation too. Signed-off-by: Vipul Kumar Samar Signed-off-by: Viresh Kumar Signed-off-by: Dmitry Torokhov diff --git a/Documentation/devicetree/bindings/input/touchscreen/stmpe.txt b/Documentation/devicetree/bindings/input/touchscreen/stmpe.txt new file mode 100644 index 0000000..127baa3 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/stmpe.txt @@ -0,0 +1,43 @@ +STMPE Touchscreen +---------------- + +Required properties: + - compatible: "st,stmpe-ts" + +Optional properties: +- st,sample-time: ADC converstion time in number of clock. (0 -> 36 clocks, 1 -> + 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks, 4 -> 80 clocks, 5 -> 96 clocks, 6 + -> 144 clocks), recommended is 4. +- st,mod-12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC) +- st,ref-sel: ADC reference source (0 -> internal reference, 1 -> external + reference) +- st,adc-freq: ADC Clock speed (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz) +- st,ave-ctrl: Sample average control (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 + samples, 3 -> 8 samples) +- st,touch-det-delay: Touch detect interrupt delay (0 -> 10 us, 1 -> 50 us, 2 -> + 100 us, 3 -> 500 us, 4-> 1 ms, 5 -> 5 ms, 6 -> 10 ms, 7 -> 50 ms) recommended + is 3 +- st,settling: Panel driver settling time (0 -> 10 us, 1 -> 100 us, 2 -> 500 us, 3 + -> 1 ms, 4 -> 5 ms, 5 -> 10 ms, 6 for 50 ms, 7 -> 100 ms) recommended is 2 +- st,fraction-z: Length of the fractional part in z (fraction-z ([0..7]) = Count of + the fractional part) recommended is 7 +- st,i-drive: current limit value of the touchscreen drivers (0 -> 20 mA typical 35 + mA max, 1 -> 50 mA typical 80 mA max) + +Node name must be stmpe_touchscreen and should be child node of stmpe node to +which it belongs. + +Example: + + stmpe_touchscreen { + compatible = "st,stmpe-ts"; + st,sample-time = <4>; + st,mod-12b = <1>; + st,ref-sel = <0>; + st,adc-freq = <1>; + st,ave-ctrl = <1>; + st,touch-det-delay = <2>; + st,settling = <2>; + st,fraction-z = <7>; + st,i-drive = <1>; + }; diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index b3f7503..43e7967 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -262,11 +263,53 @@ static void stmpe_ts_close(struct input_dev *dev) STMPE_TSC_CTRL_TSC_EN, 0); } -static int __devinit stmpe_input_probe(struct platform_device *pdev) +static void stmpe_ts_get_platform_info(struct platform_device *pdev, + struct stmpe_touch *ts) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); - const struct stmpe_platform_data *pdata = stmpe->pdata; - const struct stmpe_ts_platform_data *ts_pdata = NULL; + struct device_node *np = pdev->dev.of_node; + struct stmpe_ts_platform_data *ts_pdata = NULL; + + ts->stmpe = stmpe; + + if (stmpe->pdata && stmpe->pdata->ts) { + ts_pdata = stmpe->pdata->ts; + + ts->sample_time = ts_pdata->sample_time; + ts->mod_12b = ts_pdata->mod_12b; + ts->ref_sel = ts_pdata->ref_sel; + ts->adc_freq = ts_pdata->adc_freq; + ts->ave_ctrl = ts_pdata->ave_ctrl; + ts->touch_det_delay = ts_pdata->touch_det_delay; + ts->settling = ts_pdata->settling; + ts->fraction_z = ts_pdata->fraction_z; + ts->i_drive = ts_pdata->i_drive; + } else if (np) { + u32 val; + + if (!of_property_read_u32(np, "st,sample-time", &val)) + ts->sample_time = val; + if (!of_property_read_u32(np, "st,mod-12b", &val)) + ts->mod_12b = val; + if (!of_property_read_u32(np, "st,ref-sel", &val)) + ts->ref_sel = val; + if (!of_property_read_u32(np, "st,adc-freq", &val)) + ts->adc_freq = val; + if (!of_property_read_u32(np, "st,ave-ctrl", &val)) + ts->ave_ctrl = val; + if (!of_property_read_u32(np, "st,touch-det-delay", &val)) + ts->touch_det_delay = val; + if (!of_property_read_u32(np, "st,settling", &val)) + ts->settling = val; + if (!of_property_read_u32(np, "st,fraction-z", &val)) + ts->fraction_z = val; + if (!of_property_read_u32(np, "st,i-drive", &val)) + ts->i_drive = val; + } +} + +static int __devinit stmpe_input_probe(struct platform_device *pdev) +{ struct stmpe_touch *ts; struct input_dev *idev; int error; @@ -285,24 +328,10 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, ts); - ts->stmpe = stmpe; ts->idev = idev; ts->dev = &pdev->dev; - if (pdata) - ts_pdata = pdata->ts; - - if (ts_pdata) { - ts->sample_time = ts_pdata->sample_time; - ts->mod_12b = ts_pdata->mod_12b; - ts->ref_sel = ts_pdata->ref_sel; - ts->adc_freq = ts_pdata->adc_freq; - ts->ave_ctrl = ts_pdata->ave_ctrl; - ts->touch_det_delay = ts_pdata->touch_det_delay; - ts->settling = ts_pdata->settling; - ts->fraction_z = ts_pdata->fraction_z; - ts->i_drive = ts_pdata->i_drive; - } + stmpe_ts_get_platform_info(pdev, ts); INIT_DELAYED_WORK(&ts->work, stmpe_work); diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index c94f521..55c7b95 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -411,6 +411,7 @@ static struct resource stmpe_ts_resources[] = { static struct mfd_cell stmpe_ts_cell = { .name = "stmpe-ts", + .of_compatible = "st,stmpe-ts", .resources = stmpe_ts_resources, .num_resources = ARRAY_SIZE(stmpe_ts_resources), }; -- cgit v0.10.2 From 9c63a650bb100e7553d60c991ba0c5db9c743239 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 31 Oct 2012 01:29:52 -0400 Subject: tools/power/x86/turbostat: share kernel MSR #defines Now that turbostat is built in the kernel tree, it can share MSR #defines with the kernel. Signed-off-by: Len Brown Cc: x86@kernel.org diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 7f0edce..2639f81 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -35,11 +35,14 @@ #define MSR_IA32_PERFCTR0 0x000000c1 #define MSR_IA32_PERFCTR1 0x000000c2 #define MSR_FSB_FREQ 0x000000cd +#define MSR_NHM_PLATFORM_INFO 0x000000ce #define MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2 #define NHM_C3_AUTO_DEMOTE (1UL << 25) #define NHM_C1_AUTO_DEMOTE (1UL << 26) #define ATM_LNC_C6_AUTO_DEMOTE (1UL << 25) +#define SNB_C1_AUTO_UNDEMOTE (1UL << 27) +#define SNB_C3_AUTO_UNDEMOTE (1UL << 28) #define MSR_MTRRcap 0x000000fe #define MSR_IA32_BBL_CR_CTL 0x00000119 @@ -55,6 +58,8 @@ #define MSR_OFFCORE_RSP_0 0x000001a6 #define MSR_OFFCORE_RSP_1 0x000001a7 +#define MSR_NHM_TURBO_RATIO_LIMIT 0x000001ad +#define MSR_IVT_TURBO_RATIO_LIMIT 0x000001ae #define MSR_LBR_SELECT 0x000001c8 #define MSR_LBR_TOS 0x000001c9 @@ -103,6 +108,15 @@ #define MSR_IA32_MC0_ADDR 0x00000402 #define MSR_IA32_MC0_MISC 0x00000403 +/* C-state Residency Counters */ +#define MSR_PKG_C3_RESIDENCY 0x000003f8 +#define MSR_PKG_C6_RESIDENCY 0x000003f9 +#define MSR_PKG_C7_RESIDENCY 0x000003fa +#define MSR_CORE_C3_RESIDENCY 0x000003fc +#define MSR_CORE_C6_RESIDENCY 0x000003fd +#define MSR_CORE_C7_RESIDENCY 0x000003fe +#define MSR_PKG_C2_RESIDENCY 0x0000060d + #define MSR_AMD64_MC0_MASK 0xc0010044 #define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x)) diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile index f856495..51880e8 100644 --- a/tools/power/x86/turbostat/Makefile +++ b/tools/power/x86/turbostat/Makefile @@ -1,5 +1,6 @@ turbostat : turbostat.c CFLAGS += -Wall +CFLAGS += -I../../../../arch/x86/include/ clean : rm -f turbostat diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index ea095ab..3c063a0 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -20,6 +20,7 @@ */ #define _GNU_SOURCE +#include #include #include #include @@ -35,19 +36,6 @@ #include #include -#define MSR_NEHALEM_PLATFORM_INFO 0xCE -#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD -#define MSR_IVT_TURBO_RATIO_LIMIT 0x1AE -#define MSR_APERF 0xE8 -#define MSR_MPERF 0xE7 -#define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */ -#define MSR_PKG_C3_RESIDENCY 0x3F8 -#define MSR_PKG_C6_RESIDENCY 0x3F9 -#define MSR_PKG_C7_RESIDENCY 0x3FA /* SNB only */ -#define MSR_CORE_C3_RESIDENCY 0x3FC -#define MSR_CORE_C6_RESIDENCY 0x3FD -#define MSR_CORE_C7_RESIDENCY 0x3FE /* SNB only */ - char *proc_stat = "/proc/stat"; unsigned int interval_sec = 5; /* set with -i interval_sec */ unsigned int verbose; /* set with -v */ @@ -674,9 +662,9 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) t->tsc = rdtsc(); /* we are running on local CPU of interest */ if (has_aperf) { - if (get_msr(cpu, MSR_APERF, &t->aperf)) + if (get_msr(cpu, MSR_IA32_APERF, &t->aperf)) return -3; - if (get_msr(cpu, MSR_MPERF, &t->mperf)) + if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf)) return -4; } @@ -742,10 +730,10 @@ void print_verbose_header(void) if (!do_nehalem_platform_info) return; - get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr); + get_msr(0, MSR_NHM_PLATFORM_INFO, &msr); if (verbose > 1) - fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr); + fprintf(stderr, "MSR_NHM_PLATFORM_INFO: 0x%llx\n", msr); ratio = (msr >> 40) & 0xFF; fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", @@ -808,10 +796,10 @@ print_nhm_turbo_ratio_limits: if (!do_nehalem_turbo_ratio_limit) return; - get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr); + get_msr(0, MSR_NHM_TURBO_RATIO_LIMIT, &msr); if (verbose > 1) - fprintf(stderr, "MSR_NEHALEM_TURBO_RATIO_LIMIT: 0x%llx\n", msr); + fprintf(stderr, "MSR_NHM_TURBO_RATIO_LIMIT: 0x%llx\n", msr); ratio = (msr >> 56) & 0xFF; if (ratio) -- cgit v0.10.2 From 3fc808aaa052dec7b155f3242c6c0eabf0c49127 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 31 Oct 2012 20:47:40 -0400 Subject: x86 power: define RAPL MSRs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Run Time Average Power Limiting interface is currently model specific, present on Sandy Bridge and Ivy Bridge processors. These #defines correspond to documentation in the latest "Intel® 64 and IA-32 Architectures Software Developer Manual", plus some typos in that document corrected. Signed-off-by: Len Brown Cc: x86@kernel.org diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 2639f81..4a4abae 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -117,6 +117,29 @@ #define MSR_CORE_C7_RESIDENCY 0x000003fe #define MSR_PKG_C2_RESIDENCY 0x0000060d +/* Run Time Average Power Limiting (RAPL) Interface */ + +#define MSR_RAPL_POWER_UNIT 0x00000606 + +#define MSR_PKG_POWER_LIMIT 0x00000610 +#define MSR_PKG_ENERGY_STATUS 0x00000611 +#define MSR_PKG_PERF_STATUS 0x00000613 +#define MSR_PKG_POWER_INFO 0x00000614 + +#define MSR_DRAM_POWER_LIMIT 0x00000618 +#define MSR_DRAM_ENERGY_STATUS 0x00000619 +#define MSR_DRAM_PERF_STATUS 0x0000061b +#define MSR_DRAM_POWER_INFO 0x0000061c + +#define MSR_PP0_POWER_LIMIT 0x00000638 +#define MSR_PP0_ENERGY_STATUS 0x00000639 +#define MSR_PP0_POLICY 0x0000063a +#define MSR_PP0_PERF_STATUS 0x0000063b + +#define MSR_PP1_POWER_LIMIT 0x00000640 +#define MSR_PP1_ENERGY_STATUS 0x00000641 +#define MSR_PP1_POLICY 0x00000642 + #define MSR_AMD64_MC0_MASK 0xc0010044 #define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x)) -- cgit v0.10.2 From 58b45d166f4c16d21f6aa059c6c5d87a9eeb1ff5 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 22 Nov 2012 23:28:57 -0800 Subject: Input: serio - remove CONFIG_HOTPLUG ifdefs Remove conditional code based on CONFIG_HOTPLUG being false. It's always on now in preparation of it going away as an option. Signed-off-by: Bill Pemberton Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index d0f7533..25fc597 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -891,8 +891,6 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv) return serio_match_port(serio_drv->id_table, serio); } -#ifdef CONFIG_HOTPLUG - #define SERIO_ADD_UEVENT_VAR(fmt, val...) \ do { \ int err = add_uevent_var(env, fmt, val); \ @@ -920,15 +918,6 @@ static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) } #undef SERIO_ADD_UEVENT_VAR -#else - -static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return -ENODEV; -} - -#endif /* CONFIG_HOTPLUG */ - #ifdef CONFIG_PM static int serio_suspend(struct device *dev) { -- cgit v0.10.2 From 1cb0aa88179b7a71c240529e9d781d7bbb43d2e8 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Fri, 23 Nov 2012 21:27:39 -0800 Subject: Input: remove use of __devexit_p CONFIG_HOTPLUG is going away as an option so __devexit_p is no longer needed. Signed-off-by: Bill Pemberton Acked-by: Russell King Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index daceafe..c300089 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -122,7 +122,7 @@ static struct pci_driver emu_driver = { .name = "Emu10k1_gameport", .id_table = emu_tbl, .probe = emu_probe, - .remove = __devexit_p(emu_remove), + .remove = emu_remove, }; module_pci_driver(emu_driver); diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 48ad382..e3ab458 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -150,7 +150,7 @@ static struct pci_driver fm801_gp_driver = { .name = "FM801_gameport", .id_table = fm801_gp_id_table, .probe = fm801_gp_probe, - .remove = __devexit_p(fm801_gp_remove), + .remove = fm801_gp_remove, }; module_pci_driver(fm801_gp_driver); diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index 9d869e2..94f3327 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -366,7 +366,7 @@ static struct i2c_driver as5011_driver = { .name = "as5011", }, .probe = as5011_probe, - .remove = __devexit_p(as5011_remove), + .remove = as5011_remove, .id_table = as5011_id, }; diff --git a/drivers/input/joystick/maplecontrol.c b/drivers/input/joystick/maplecontrol.c index 77cfde5..c843457 100644 --- a/drivers/input/joystick/maplecontrol.c +++ b/drivers/input/joystick/maplecontrol.c @@ -175,7 +175,7 @@ static struct maple_driver dc_pad_driver = { .drv = { .name = "Dreamcast_controller", .probe = probe_maple_controller, - .remove = __devexit_p(remove_maple_controller), + .remove = remove_maple_controller, }, }; diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c index e9e8674..46796b2 100644 --- a/drivers/input/keyboard/adp5520-keys.c +++ b/drivers/input/keyboard/adp5520-keys.c @@ -200,7 +200,7 @@ static struct platform_driver adp5520_keys_driver = { .owner = THIS_MODULE, }, .probe = adp5520_keys_probe, - .remove = __devexit_p(adp5520_keys_remove), + .remove = adp5520_keys_remove, }; module_platform_driver(adp5520_keys_driver); diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index b083bf1..39c2a6d 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -650,7 +650,7 @@ static struct i2c_driver adp5588_driver = { #endif }, .probe = adp5588_probe, - .remove = __devexit_p(adp5588_remove), + .remove = adp5588_remove, .id_table = adp5588_id, }; diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 74e6032..6e0c2e3 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -1104,7 +1104,7 @@ static struct i2c_driver adp5589_driver = { .pm = &adp5589_dev_pm_ops, }, .probe = adp5589_probe, - .remove = __devexit_p(adp5589_remove), + .remove = adp5589_remove, .id_table = adp5589_id, }; diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index 8eb9116..8a7909a 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c @@ -390,7 +390,7 @@ static struct platform_driver bfin_kpad_device_driver = { .owner = THIS_MODULE, }, .probe = bfin_kpad_probe, - .remove = __devexit_p(bfin_kpad_remove), + .remove = bfin_kpad_remove, .suspend = bfin_kpad_suspend, .resume = bfin_kpad_resume, }; diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c index d5bacbb..8e4b438 100644 --- a/drivers/input/keyboard/davinci_keyscan.c +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -326,7 +326,7 @@ static struct platform_driver davinci_ks_driver = { .name = "davinci_keyscan", .owner = THIS_MODULE, }, - .remove = __devexit_p(davinci_ks_remove), + .remove = davinci_ks_remove, }; static int __init davinci_ks_init(void) diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 7363402..bdf3261 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -380,7 +380,7 @@ static struct platform_driver ep93xx_keypad_driver = { .pm = &ep93xx_keypad_pm_ops, }, .probe = ep93xx_keypad_probe, - .remove = __devexit_p(ep93xx_keypad_remove), + .remove = ep93xx_keypad_remove, }; module_platform_driver(ep93xx_keypad_driver); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 6a68041..96b5ac5 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -824,7 +824,7 @@ static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume); static struct platform_driver gpio_keys_device_driver = { .probe = gpio_keys_probe, - .remove = __devexit_p(gpio_keys_remove), + .remove = gpio_keys_remove, .driver = { .name = "gpio-keys", .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index f2142de..922cbbd 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -357,7 +357,7 @@ static int __devexit gpio_keys_polled_remove(struct platform_device *pdev) static struct platform_driver gpio_keys_polled_driver = { .probe = gpio_keys_polled_probe, - .remove = __devexit_p(gpio_keys_polled_remove), + .remove = gpio_keys_polled_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index 5f72440..97d3151 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -341,7 +341,7 @@ static struct parisc_driver hil_driver = { .name = "hil", .id_table = hil_tbl, .probe = hil_probe_chip, - .remove = __devexit_p(hil_remove_chip), + .remove = hil_remove_chip, }; static int __init hil_init(void) diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index cdc2526..93c3441 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -632,7 +632,7 @@ static struct platform_driver imx_keypad_driver = { .pm = &imx_kbd_pm_ops, }, .probe = imx_keypad_probe, - .remove = __devexit_p(imx_keypad_remove), + .remove = imx_keypad_remove, }; module_platform_driver(imx_keypad_driver); diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c index 24f3ea0..bd1a9c3 100644 --- a/drivers/input/keyboard/jornada680_kbd.c +++ b/drivers/input/keyboard/jornada680_kbd.c @@ -258,7 +258,7 @@ static struct platform_driver jornada680kbd_driver = { .owner = THIS_MODULE, }, .probe = jornada680kbd_probe, - .remove = __devexit_p(jornada680kbd_remove), + .remove = jornada680kbd_remove, }; module_platform_driver(jornada680kbd_driver); diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 9d639fa..9771db1 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -173,6 +173,6 @@ static struct platform_driver jornada720_kbd_driver = { .owner = THIS_MODULE, }, .probe = jornada720_kbd_probe, - .remove = __devexit_p(jornada720_kbd_remove), + .remove = jornada720_kbd_remove, }; module_platform_driver(jornada720_kbd_driver); diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 39ac278..8743285 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -846,7 +846,7 @@ static struct i2c_driver lm8323_i2c_driver = { .pm = &lm8323_pm_ops, }, .probe = lm8323_probe, - .remove = __devexit_p(lm8323_remove), + .remove = lm8323_remove, .id_table = lm8323_id, }; MODULE_DEVICE_TABLE(i2c, lm8323_id); diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c index 081fd9e..c76e488 100644 --- a/drivers/input/keyboard/lm8333.c +++ b/drivers/input/keyboard/lm8333.c @@ -225,7 +225,7 @@ static struct i2c_driver lm8333_driver = { .owner = THIS_MODULE, }, .probe = lm8333_probe, - .remove = __devexit_p(lm8333_remove), + .remove = lm8333_remove, .id_table = lm8333_id, }; module_i2c_driver(lm8333_driver); diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index b1ab298..5f66272 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -345,7 +345,7 @@ static struct locomo_driver keyboard_driver = { }, .devid = LOCOMO_DEVID_KEYBOARD, .probe = locomokbd_probe, - .remove = __devexit_p(locomokbd_remove), + .remove = locomokbd_remove, }; static int __init locomokbd_init(void) diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index dd786c8..8872ce6 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -377,7 +377,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_kscan_match); static struct platform_driver lpc32xx_kscan_driver = { .probe = lpc32xx_kscan_probe, - .remove = __devexit_p(lpc32xx_kscan_remove), + .remove = lpc32xx_kscan_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 05d3a96..ed2bacd 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -564,7 +564,7 @@ MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match); static struct platform_driver matrix_keypad_driver = { .probe = matrix_keypad_probe, - .remove = __devexit_p(matrix_keypad_remove), + .remove = matrix_keypad_remove, .driver = { .name = "matrix-keypad", .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index 8edada8..90478d1 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -312,7 +312,7 @@ static struct i2c_driver max7359_i2c_driver = { .pm = &max7359_pm, }, .probe = max7359_probe, - .remove = __devexit_p(max7359_remove), + .remove = max7359_remove, .id_table = max7359_ids, }; diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index 0d77f6c..751b141 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -270,7 +270,7 @@ static struct i2c_driver mcs_touchkey_driver = { .pm = &mcs_touchkey_pm_ops, }, .probe = mcs_touchkey_probe, - .remove = __devexit_p(mcs_touchkey_remove), + .remove = mcs_touchkey_remove, .shutdown = mcs_touchkey_shutdown, .id_table = mcs_touchkey_id, }; diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 7613f1c..63b20d0 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -327,7 +327,7 @@ static struct i2c_driver mpr_touchkey_driver = { }, .id_table = mpr121_id, .probe = mpr_touchkey_probe, - .remove = __devexit_p(mpr_touchkey_remove), + .remove = mpr_touchkey_remove, }; module_i2c_driver(mpr_touchkey_driver); diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index a1a9375..2304a81 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -427,7 +427,7 @@ static struct platform_driver ske_keypad_driver = { .owner = THIS_MODULE, .pm = &ske_keypad_dev_pm_ops, }, - .remove = __devexit_p(ske_keypad_remove), + .remove = ske_keypad_remove, }; static int __init ske_keypad_init(void) diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 4a5fcc8..1d17d91 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -379,7 +379,7 @@ static int __devexit omap_kp_remove(struct platform_device *pdev) static struct platform_driver omap_kp_driver = { .probe = omap_kp_probe, - .remove = __devexit_p(omap_kp_remove), + .remove = omap_kp_remove, .suspend = omap_kp_suspend, .resume = omap_kp_resume, .driver = { diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index c05f98c..7145ab3 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -440,7 +440,7 @@ MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); static struct platform_driver omap4_keypad_driver = { .probe = omap4_keypad_probe, - .remove = __devexit_p(omap4_keypad_remove), + .remove = omap4_keypad_remove, .driver = { .name = "omap4-keypad", .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c index abe728c..7914ede 100644 --- a/drivers/input/keyboard/opencores-kbd.c +++ b/drivers/input/keyboard/opencores-kbd.c @@ -158,7 +158,7 @@ static int __devexit opencores_kbd_remove(struct platform_device *pdev) static struct platform_driver opencores_kbd_device_driver = { .probe = opencores_kbd_probe, - .remove = __devexit_p(opencores_kbd_remove), + .remove = opencores_kbd_remove, .driver = { .name = "opencores-kbd", }, diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 52c3465..d3623c5 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -773,7 +773,7 @@ static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops, static struct platform_driver pmic8xxx_kp_driver = { .probe = pmic8xxx_kp_probe, - .remove = __devexit_p(pmic8xxx_kp_remove), + .remove = pmic8xxx_kp_remove, .driver = { .name = PM8XXX_KEYPAD_DEV_NAME, .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index cad9d5d..a6bcd31 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -620,7 +620,7 @@ MODULE_ALIAS("platform:pxa27x-keypad"); static struct platform_driver pxa27x_keypad_driver = { .probe = pxa27x_keypad_probe, - .remove = __devexit_p(pxa27x_keypad_remove), + .remove = pxa27x_keypad_remove, .driver = { .name = "pxa27x-keypad", .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c index 41488f9..f8f89d1 100644 --- a/drivers/input/keyboard/pxa930_rotary.c +++ b/drivers/input/keyboard/pxa930_rotary.c @@ -193,7 +193,7 @@ static struct platform_driver pxa930_rotary_driver = { .owner = THIS_MODULE, }, .probe = pxa930_rotary_probe, - .remove = __devexit_p(pxa930_rotary_remove), + .remove = pxa930_rotary_remove, }; module_platform_driver(pxa930_rotary_driver); diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index ca68f29..eb46405 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -256,7 +256,7 @@ static struct i2c_driver qt1070_driver = { }, .id_table = qt1070_id, .probe = qt1070_probe, - .remove = __devexit_p(qt1070_remove), + .remove = qt1070_remove, }; module_i2c_driver(qt1070_driver); diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 031eed7..691fe92 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -366,7 +366,7 @@ static struct i2c_driver qt2160_driver = { .id_table = qt2160_idtable, .probe = qt2160_probe, - .remove = __devexit_p(qt2160_remove), + .remove = qt2160_remove, }; module_i2c_driver(qt2160_driver); diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 9d7a111..f02772a 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -685,7 +685,7 @@ MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids); static struct platform_driver samsung_keypad_driver = { .probe = samsung_keypad_probe, - .remove = __devexit_p(samsung_keypad_remove), + .remove = samsung_keypad_remove, .driver = { .name = "samsung-keypad", .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index da54ad5..07415a3 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -331,7 +331,7 @@ static SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops, static struct platform_driver sh_keysc_device_driver = { .probe = sh_keysc_probe, - .remove = __devexit_p(sh_keysc_remove), + .remove = sh_keysc_remove, .driver = { .name = "sh_keysc", .pm = &sh_keysc_dev_pm_ops, diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index da914fe..0c88623 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -381,7 +381,7 @@ MODULE_DEVICE_TABLE(of, spear_kbd_id_table); static struct platform_driver spear_kbd_driver = { .probe = spear_kbd_probe, - .remove = __devexit_p(spear_kbd_remove), + .remove = spear_kbd_remove, .driver = { .name = "keyboard", .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index d3d2eaa..286719f 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -348,7 +348,7 @@ static struct platform_driver stmpe_keypad_driver = { .driver.name = "stmpe-keypad", .driver.owner = THIS_MODULE, .probe = stmpe_keypad_probe, - .remove = __devexit_p(stmpe_keypad_remove), + .remove = stmpe_keypad_remove, }; module_platform_driver(stmpe_keypad_driver); diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 7d498e6..75fa2b9 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -448,7 +448,7 @@ static struct platform_driver tc3589x_keypad_driver = { .pm = &tc3589x_keypad_dev_pm_ops, }, .probe = tc3589x_keypad_probe, - .remove = __devexit_p(tc3589x_keypad_remove), + .remove = tc3589x_keypad_remove, }; module_platform_driver(tc3589x_keypad_driver); diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index c355cdd..f5fa75a 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -361,7 +361,7 @@ static struct i2c_driver tca6416_keypad_driver = { .pm = &tca6416_keypad_dev_pm_ops, }, .probe = tca6416_keypad_probe, - .remove = __devexit_p(tca6416_keypad_remove), + .remove = tca6416_keypad_remove, .id_table = tca6416_id, }; diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 893869b..672b5f8 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -408,7 +408,7 @@ static struct i2c_driver tca8418_keypad_driver = { .owner = THIS_MODULE, }, .probe = tca8418_keypad_probe, - .remove = __devexit_p(tca8418_keypad_remove), + .remove = tca8418_keypad_remove, .id_table = tca8418_id, }; diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 5faaf25..48ef283 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -954,7 +954,7 @@ MODULE_DEVICE_TABLE(of, tegra_kbc_of_match); static struct platform_driver tegra_kbc_driver = { .probe = tegra_kbc_probe, - .remove = __devexit_p(tegra_kbc_remove), + .remove = tegra_kbc_remove, .driver = { .name = "tegra-kbc", .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c index 4c34f21..05d923c 100644 --- a/drivers/input/keyboard/tnetv107x-keypad.c +++ b/drivers/input/keyboard/tnetv107x-keypad.c @@ -319,7 +319,7 @@ static int __devexit keypad_remove(struct platform_device *pdev) static struct platform_driver keypad_driver = { .probe = keypad_probe, - .remove = __devexit_p(keypad_remove), + .remove = keypad_remove, .driver.name = "tnetv107x-keypad", .driver.owner = THIS_MODULE, }; diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index a2c6f79..ae25909 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -452,7 +452,7 @@ static int __devexit twl4030_kp_remove(struct platform_device *pdev) static struct platform_driver twl4030_kp_driver = { .probe = twl4030_kp_probe, - .remove = __devexit_p(twl4030_kp_remove), + .remove = twl4030_kp_remove, .driver = { .name = "twl4030_keypad", .owner = THIS_MODULE, diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index e0f6cd1..a90fdfc 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -257,7 +257,7 @@ static int __devexit w90p910_keypad_remove(struct platform_device *pdev) static struct platform_driver w90p910_keypad_driver = { .probe = w90p910_keypad_probe, - .remove = __devexit_p(w90p910_keypad_remove), + .remove = w90p910_keypad_remove, .driver = { .name = "nuc900-kpi", .owner = THIS_MODULE, diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c index 7f26e7b..f775575 100644 --- a/drivers/input/misc/88pm80x_onkey.c +++ b/drivers/input/misc/88pm80x_onkey.c @@ -157,7 +157,7 @@ static struct platform_driver pm80x_onkey_driver = { .pm = &pm80x_onkey_pm_ops, }, .probe = pm80x_onkey_probe, - .remove = __devexit_p(pm80x_onkey_remove), + .remove = pm80x_onkey_remove, }; module_platform_driver(pm80x_onkey_driver); diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c index f9ce183..8391a9d 100644 --- a/drivers/input/misc/88pm860x_onkey.c +++ b/drivers/input/misc/88pm860x_onkey.c @@ -161,7 +161,7 @@ static struct platform_driver pm860x_onkey_driver = { .pm = &pm860x_onkey_pm_ops, }, .probe = pm860x_onkey_probe, - .remove = __devexit_p(pm860x_onkey_remove), + .remove = pm860x_onkey_remove, }; module_platform_driver(pm860x_onkey_driver); diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index 84ec691..ae9c205 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c @@ -146,7 +146,7 @@ static struct platform_driver ab8500_ponkey_driver = { .of_match_table = of_match_ptr(ab8500_ponkey_match), }, .probe = ab8500_ponkey_probe, - .remove = __devexit_p(ab8500_ponkey_remove), + .remove = ab8500_ponkey_remove, }; module_platform_driver(ab8500_ponkey_driver); diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index c8a7901..02e21d4 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -112,7 +112,7 @@ static struct i2c_driver ad714x_i2c_driver = { .pm = &ad714x_i2c_pm, }, .probe = ad714x_i2c_probe, - .remove = __devexit_p(ad714x_i2c_remove), + .remove = ad714x_i2c_remove, .id_table = ad714x_id, }; diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c index 75f6136..eee820b 100644 --- a/drivers/input/misc/ad714x-spi.c +++ b/drivers/input/misc/ad714x-spi.c @@ -120,7 +120,7 @@ static struct spi_driver ad714x_spi_driver = { .pm = &ad714x_spi_pm, }, .probe = ad714x_spi_probe, - .remove = __devexit_p(ad714x_spi_remove), + .remove = ad714x_spi_remove, }; module_spi_driver(ad714x_spi_driver); diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index dd1d1c1..09094ca 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -144,7 +144,7 @@ static struct i2c_driver adxl34x_driver = { .pm = &adxl34x_i2c_pm, }, .probe = adxl34x_i2c_probe, - .remove = __devexit_p(adxl34x_i2c_remove), + .remove = adxl34x_i2c_remove, .id_table = adxl34x_id, }; diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c index 820a802..756c899 100644 --- a/drivers/input/misc/adxl34x-spi.c +++ b/drivers/input/misc/adxl34x-spi.c @@ -126,7 +126,7 @@ static struct spi_driver adxl34x_driver = { .pm = &adxl34x_spi_pm, }, .probe = adxl34x_spi_probe, - .remove = __devexit_p(adxl34x_spi_remove), + .remove = adxl34x_spi_remove, }; module_spi_driver(adxl34x_driver); diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c index 1c4146f..6df3f88 100644 --- a/drivers/input/misc/bfin_rotary.c +++ b/drivers/input/misc/bfin_rotary.c @@ -255,7 +255,7 @@ static const struct dev_pm_ops bfin_rotary_pm_ops = { static struct platform_driver bfin_rotary_device_driver = { .probe = bfin_rotary_probe, - .remove = __devexit_p(bfin_rotary_remove), + .remove = bfin_rotary_remove, .driver = { .name = "bfin-rotary", .owner = THIS_MODULE, diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index e2f1e9f..0788c94 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -670,7 +670,7 @@ static struct i2c_driver bma150_driver = { .class = I2C_CLASS_HWMON, .id_table = bma150_id, .probe = bma150_probe, - .remove = __devexit_p(bma150_remove), + .remove = bma150_remove, }; module_i2c_driver(bma150_driver); diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c index fe9b85f..523b6aa 100644 --- a/drivers/input/misc/cma3000_d0x_i2c.c +++ b/drivers/input/misc/cma3000_d0x_i2c.c @@ -114,7 +114,7 @@ MODULE_DEVICE_TABLE(i2c, cma3000_i2c_id); static struct i2c_driver cma3000_i2c_driver = { .probe = cma3000_i2c_probe, - .remove = __devexit_p(cma3000_i2c_remove), + .remove = cma3000_i2c_remove, .id_table = cma3000_i2c_id, .driver = { .name = "cma3000_i2c_accl", diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c index 53e43d2..659f20d 100644 --- a/drivers/input/misc/cobalt_btns.c +++ b/drivers/input/misc/cobalt_btns.c @@ -157,7 +157,7 @@ MODULE_ALIAS("platform:Cobalt buttons"); static struct platform_driver cobalt_buttons_driver = { .probe = cobalt_buttons_probe, - .remove = __devexit_p(cobalt_buttons_remove), + .remove = cobalt_buttons_remove, .driver = { .name = "Cobalt buttons", .owner = THIS_MODULE, diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c index 3c843cd..acd07e8 100644 --- a/drivers/input/misc/da9052_onkey.c +++ b/drivers/input/misc/da9052_onkey.c @@ -156,7 +156,7 @@ static int __devexit da9052_onkey_remove(struct platform_device *pdev) static struct platform_driver da9052_onkey_driver = { .probe = da9052_onkey_probe, - .remove = __devexit_p(da9052_onkey_remove), + .remove = da9052_onkey_remove, .driver = { .name = "da9052-onkey", .owner = THIS_MODULE, diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c index 10ebf15..fe434e0 100644 --- a/drivers/input/misc/da9055_onkey.c +++ b/drivers/input/misc/da9055_onkey.c @@ -156,7 +156,7 @@ static int __devexit da9055_onkey_remove(struct platform_device *pdev) static struct platform_driver da9055_onkey_driver = { .probe = da9055_onkey_probe, - .remove = __devexit_p(da9055_onkey_remove), + .remove = da9055_onkey_remove, .driver = { .name = "da9055-onkey", .owner = THIS_MODULE, diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index c1313d8..1afb91c 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -262,7 +262,7 @@ static int __devexit dm355evm_keys_remove(struct platform_device *pdev) */ static struct platform_driver dm355evm_keys_driver = { .probe = dm355evm_keys_probe, - .remove = __devexit_p(dm355evm_keys_remove), + .remove = dm355evm_keys_remove, .driver = { .owner = THIS_MODULE, .name = "dm355evm_keys", diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c index b6664cf..99ec8d0 100644 --- a/drivers/input/misc/gp2ap002a00f.c +++ b/drivers/input/misc/gp2ap002a00f.c @@ -277,7 +277,7 @@ static struct i2c_driver gp2a_i2c_driver = { .pm = &gp2a_pm, }, .probe = gp2a_probe, - .remove = __devexit_p(gp2a_remove), + .remove = gp2a_remove, .id_table = gp2a_i2c_id, }; diff --git a/drivers/input/misc/gpio_tilt_polled.c b/drivers/input/misc/gpio_tilt_polled.c index 277a057..bf97679 100644 --- a/drivers/input/misc/gpio_tilt_polled.c +++ b/drivers/input/misc/gpio_tilt_polled.c @@ -198,7 +198,7 @@ static int __devexit gpio_tilt_polled_remove(struct platform_device *pdev) static struct platform_driver gpio_tilt_polled_driver = { .probe = gpio_tilt_polled_probe, - .remove = __devexit_p(gpio_tilt_polled_remove), + .remove = gpio_tilt_polled_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index 50e2830..18a2970 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -165,7 +165,7 @@ static struct platform_driver ixp4xx_spkr_platform_driver = { .owner = THIS_MODULE, }, .probe = ixp4xx_spkr_probe, - .remove = __devexit_p(ixp4xx_spkr_remove), + .remove = ixp4xx_spkr_remove, .shutdown = ixp4xx_spkr_shutdown, }; module_platform_driver(ixp4xx_spkr_platform_driver); diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index f46139f..8414ddb 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -663,7 +663,7 @@ static struct i2c_driver kxtj9_driver = { .pm = &kxtj9_pm_ops, }, .probe = kxtj9_probe, - .remove = __devexit_p(kxtj9_remove), + .remove = kxtj9_remove, .id_table = kxtj9_id, }; diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c index 0c64d9b..f3a3c5e 100644 --- a/drivers/input/misc/m68kspkr.c +++ b/drivers/input/misc/m68kspkr.c @@ -104,7 +104,7 @@ static struct platform_driver m68kspkr_platform_driver = { .owner = THIS_MODULE, }, .probe = m68kspkr_probe, - .remove = __devexit_p(m68kspkr_remove), + .remove = m68kspkr_remove, .shutdown = m68kspkr_shutdown, }; diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c index 0a12b74..3c3db67 100644 --- a/drivers/input/misc/max8925_onkey.c +++ b/drivers/input/misc/max8925_onkey.c @@ -195,7 +195,7 @@ static struct platform_driver max8925_onkey_driver = { .pm = &max8925_onkey_pm_ops, }, .probe = max8925_onkey_probe, - .remove = __devexit_p(max8925_onkey_remove), + .remove = max8925_onkey_remove, }; module_platform_driver(max8925_onkey_driver); diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index 05b7b8b..8db64f6 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -396,7 +396,7 @@ static struct platform_driver max8997_haptic_driver = { .pm = &max8997_haptic_pm_ops, }, .probe = max8997_haptic_probe, - .remove = __devexit_p(max8997_haptic_remove), + .remove = max8997_haptic_remove, .id_table = max8997_haptic_id, }; module_platform_driver(max8997_haptic_driver); diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c index 8428f1e..a0c35a05 100644 --- a/drivers/input/misc/mc13783-pwrbutton.c +++ b/drivers/input/misc/mc13783-pwrbutton.c @@ -257,7 +257,7 @@ static int __devexit mc13783_pwrbutton_remove(struct platform_device *pdev) static struct platform_driver mc13783_pwrbutton_driver = { .probe = mc13783_pwrbutton_probe, - .remove = __devexit_p(mc13783_pwrbutton_remove), + .remove = mc13783_pwrbutton_remove, .driver = { .name = "mc13783-pwrbutton", .owner = THIS_MODULE, diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index 873ebce..050a246 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -243,7 +243,7 @@ static struct i2c_driver mma8450_driver = { .of_match_table = mma8450_dt_ids, }, .probe = mma8450_probe, - .remove = __devexit_p(mma8450_remove), + .remove = mma8450_remove, .id_table = mma8450_id, }; diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c index 306f84c..ab11409 100644 --- a/drivers/input/misc/mpu3050.c +++ b/drivers/input/misc/mpu3050.c @@ -471,7 +471,7 @@ static struct i2c_driver mpu3050_i2c_driver = { .of_match_table = mpu3050_of_match, }, .probe = mpu3050_probe, - .remove = __devexit_p(mpu3050_remove), + .remove = mpu3050_remove, .id_table = mpu3050_ids, }; diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c index e09b4fe..afd3f5a 100644 --- a/drivers/input/misc/pcap_keys.c +++ b/drivers/input/misc/pcap_keys.c @@ -119,7 +119,7 @@ static int __devexit pcap_keys_remove(struct platform_device *pdev) static struct platform_driver pcap_keys_device_driver = { .probe = pcap_keys_probe, - .remove = __devexit_p(pcap_keys_remove), + .remove = pcap_keys_remove, .driver = { .name = "pcap-keys", .owner = THIS_MODULE, diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c index 53891de..3896b0f 100644 --- a/drivers/input/misc/pcf50633-input.c +++ b/drivers/input/misc/pcf50633-input.c @@ -111,7 +111,7 @@ static struct platform_driver pcf50633_input_driver = { .name = "pcf50633-input", }, .probe = pcf50633_input_probe, - .remove = __devexit_p(pcf50633_input_remove), + .remove = pcf50633_input_remove, }; module_platform_driver(pcf50633_input_driver); diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index 544c663..6c480bf 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -212,7 +212,7 @@ static struct i2c_driver pcf8574_kp_driver = { #endif }, .probe = pcf8574_kp_probe, - .remove = __devexit_p(pcf8574_kp_remove), + .remove = pcf8574_kp_remove, .id_table = pcf8574_kp_id, }; diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index b2484aa..17d6555f 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -131,7 +131,7 @@ static struct platform_driver pcspkr_platform_driver = { .pm = &pcspkr_pm_ops, }, .probe = pcspkr_probe, - .remove = __devexit_p(pcspkr_remove), + .remove = pcspkr_remove, .shutdown = pcspkr_shutdown, }; module_platform_driver(pcspkr_platform_driver); diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index dfbfb46..2e0a3bf 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -270,7 +270,7 @@ static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); static struct platform_driver pm8xxx_vib_driver = { .probe = pm8xxx_vib_probe, - .remove = __devexit_p(pm8xxx_vib_remove), + .remove = pm8xxx_vib_remove, .driver = { .name = "pm8xxx-vib", .owner = THIS_MODULE, diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index 0f83d0f..b2396e2 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -206,7 +206,7 @@ static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev) static struct platform_driver pmic8xxx_pwrkey_driver = { .probe = pmic8xxx_pwrkey_probe, - .remove = __devexit_p(pmic8xxx_pwrkey_remove), + .remove = pmic8xxx_pwrkey_remove, .driver = { .name = PM8XXX_PWRKEY_DEV_NAME, .owner = THIS_MODULE, diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index 502544c..d40c2f6 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -184,7 +184,7 @@ static const struct of_device_id pwm_beeper_match[] = { static struct platform_driver pwm_beeper_driver = { .probe = pwm_beeper_probe, - .remove = __devexit_p(pwm_beeper_remove), + .remove = pwm_beeper_remove, .driver = { .name = "pwm-beeper", .owner = THIS_MODULE, diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c index aeb02bc..718dd83 100644 --- a/drivers/input/misc/rb532_button.c +++ b/drivers/input/misc/rb532_button.c @@ -94,7 +94,7 @@ static int __devexit rb532_button_remove(struct platform_device *pdev) static struct platform_driver rb532_button_driver = { .probe = rb532_button_probe, - .remove = __devexit_p(rb532_button_remove), + .remove = rb532_button_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/input/misc/retu-pwrbutton.c b/drivers/input/misc/retu-pwrbutton.c index 3767f43..4500027 100644 --- a/drivers/input/misc/retu-pwrbutton.c +++ b/drivers/input/misc/retu-pwrbutton.c @@ -83,7 +83,7 @@ static int __devexit retu_pwrbutton_remove(struct platform_device *pdev) static struct platform_driver retu_pwrbutton_driver = { .probe = retu_pwrbutton_probe, - .remove = __devexit_p(retu_pwrbutton_remove), + .remove = retu_pwrbutton_remove, .driver = { .name = "retu-pwrbutton", .owner = THIS_MODULE, diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 99a49e4..b183a0e 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -325,7 +325,7 @@ static int __devexit rotary_encoder_remove(struct platform_device *pdev) static struct platform_driver rotary_encoder_driver = { .probe = rotary_encoder_probe, - .remove = __devexit_p(rotary_encoder_remove), + .remove = rotary_encoder_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/input/misc/sgi_btns.c b/drivers/input/misc/sgi_btns.c index 5d9fd55..fd731e8 100644 --- a/drivers/input/misc/sgi_btns.c +++ b/drivers/input/misc/sgi_btns.c @@ -158,7 +158,7 @@ static int __devexit sgi_buttons_remove(struct platform_device *pdev) static struct platform_driver sgi_buttons_driver = { .probe = sgi_buttons_probe, - .remove = __devexit_p(sgi_buttons_remove), + .remove = sgi_buttons_remove, .driver = { .name = "sgibtns", .owner = THIS_MODULE, diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index 0122f53..b9c8702 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -263,7 +263,7 @@ static struct platform_driver bbc_beep_driver = { .of_match_table = bbc_beep_match, }, .probe = bbc_beep_probe, - .remove = __devexit_p(bbc_remove), + .remove = bbc_remove, .shutdown = sparcspkr_shutdown, }; @@ -345,7 +345,7 @@ static struct platform_driver grover_beep_driver = { .of_match_table = grover_beep_match, }, .probe = grover_beep_probe, - .remove = __devexit_p(grover_remove), + .remove = grover_remove, .shutdown = sparcspkr_shutdown, }; diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 2194a3c..29f2207 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -283,7 +283,7 @@ static int __devexit twl4030_vibra_remove(struct platform_device *pdev) static struct platform_driver twl4030_vibra_driver = { .probe = twl4030_vibra_probe, - .remove = __devexit_p(twl4030_vibra_remove), + .remove = twl4030_vibra_remove, .driver = { .name = "twl4030-vibra", .owner = THIS_MODULE, diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index c8a288a..463e963 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -433,7 +433,7 @@ static int __devexit twl6040_vibra_remove(struct platform_device *pdev) static struct platform_driver twl6040_vibra_driver = { .probe = twl6040_vibra_probe, - .remove = __devexit_p(twl6040_vibra_remove), + .remove = twl6040_vibra_remove, .driver = { .name = "twl6040-vibra", .owner = THIS_MODULE, diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index e2bdfd4..3f9ad23 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -1334,7 +1334,7 @@ static struct platform_driver wistron_driver = { #endif }, .probe = wistron_probe, - .remove = __devexit_p(wistron_remove), + .remove = wistron_remove, }; static int __init wb_module_init(void) diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c index fa8b390..3a12951 100644 --- a/drivers/input/misc/wm831x-on.c +++ b/drivers/input/misc/wm831x-on.c @@ -138,7 +138,7 @@ static int __devexit wm831x_on_remove(struct platform_device *pdev) static struct platform_driver wm831x_on_driver = { .probe = wm831x_on_probe, - .remove = __devexit_p(wm831x_on_remove), + .remove = wm831x_on_remove, .driver = { .name = "wm831x-on", .owner = THIS_MODULE, diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c index 39fe9b7..b3a8aa9 100644 --- a/drivers/input/mouse/gpio_mouse.c +++ b/drivers/input/mouse/gpio_mouse.c @@ -172,7 +172,7 @@ static int __devexit gpio_mouse_remove(struct platform_device *pdev) static struct platform_driver gpio_mouse_device_driver = { .probe = gpio_mouse_probe, - .remove = __devexit_p(gpio_mouse_remove), + .remove = gpio_mouse_remove, .driver = { .name = "gpio_mouse", .owner = THIS_MODULE, diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c index 5f27817..03ccf02 100644 --- a/drivers/input/mouse/maplemouse.c +++ b/drivers/input/mouse/maplemouse.c @@ -132,7 +132,7 @@ static struct maple_driver dc_mouse_driver = { .drv = { .name = "Dreamcast_mouse", .probe = probe_maple_mouse, - .remove = __devexit_p(remove_maple_mouse), + .remove = remove_maple_mouse, }, }; diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c index c29ae76..ac4e077 100644 --- a/drivers/input/mouse/navpoint.c +++ b/drivers/input/mouse/navpoint.c @@ -353,7 +353,7 @@ static SIMPLE_DEV_PM_OPS(navpoint_pm_ops, navpoint_suspend, navpoint_resume); static struct platform_driver navpoint_driver = { .probe = navpoint_probe, - .remove = __devexit_p(navpoint_remove), + .remove = navpoint_remove, .driver = { .name = "navpoint", .owner = THIS_MODULE, diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c index 4fe055f..953a048 100644 --- a/drivers/input/mouse/pxa930_trkball.c +++ b/drivers/input/mouse/pxa930_trkball.c @@ -248,7 +248,7 @@ static struct platform_driver pxa930_trkball_driver = { .name = "pxa930-trkball", }, .probe = pxa930_trkball_probe, - .remove = __devexit_p(pxa930_trkball_remove), + .remove = pxa930_trkball_remove, }; module_platform_driver(pxa930_trkball_driver); diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 063a174..fa8f162 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -662,7 +662,7 @@ static struct i2c_driver synaptics_i2c_driver = { }, .probe = synaptics_i2c_probe, - .remove = __devexit_p(synaptics_i2c_remove), + .remove = synaptics_i2c_remove, .id_table = synaptics_i2c_id_table, }; diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c index cc11f4e..50da8e5 100644 --- a/drivers/input/serio/altera_ps2.c +++ b/drivers/input/serio/altera_ps2.c @@ -187,7 +187,7 @@ MODULE_DEVICE_TABLE(of, altera_ps2_match); */ static struct platform_driver altera_ps2_driver = { .probe = altera_ps2_probe, - .remove = __devexit_p(altera_ps2_remove), + .remove = altera_ps2_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 2e77246..beb0816 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -204,7 +204,7 @@ static struct amba_driver ambakmi_driver = { }, .id_table = amba_kmi_idtable, .probe = amba_kmi_probe, - .remove = __devexit_p(amba_kmi_remove), + .remove = amba_kmi_remove, .resume = amba_kmi_resume, }; diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c index 89ad763..72fda8f 100644 --- a/drivers/input/serio/arc_ps2.c +++ b/drivers/input/serio/arc_ps2.c @@ -264,7 +264,7 @@ static struct platform_driver arc_ps2_driver = { .owner = THIS_MODULE, }, .probe = arc_ps2_probe, - .remove = __devexit_p(arc_ps2_remove), + .remove = arc_ps2_remove, }; module_platform_driver(arc_ps2_driver); diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index 8528165..64bcd15 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -212,7 +212,7 @@ static struct platform_driver ct82c710_driver = { .owner = THIS_MODULE, }, .probe = ct82c710_probe, - .remove = __devexit_p(ct82c710_remove), + .remove = ct82c710_remove, }; diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 4225f5d..49cb7ca 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -444,7 +444,7 @@ static struct parisc_driver parisc_ps2_driver = { .name = "gsc_ps2", .id_table = gscps2_device_tbl, .probe = gscps2_probe, - .remove = __devexit_p(gscps2_remove), + .remove = gscps2_remove, }; static int __init gscps2_init(void) diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index 395a9af..3f6c835 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -102,7 +102,7 @@ static struct platform_driver sparc_i8042_driver = { .of_match_table = sparc_i8042_match, }, .probe = sparc_i8042_probe, - .remove = __devexit_p(sparc_i8042_remove), + .remove = sparc_i8042_remove, }; static int __init i8042_platform_init(void) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 8656441..2539195 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1455,7 +1455,7 @@ static struct platform_driver i8042_driver = { .pm = &i8042_pm_ops, #endif }, - .remove = __devexit_p(i8042_remove), + .remove = i8042_remove, .shutdown = i8042_shutdown, }; diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index 61da763..2226277 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -165,7 +165,7 @@ static struct platform_driver maceps2_driver = { .owner = THIS_MODULE, }, .probe = maceps2_probe, - .remove = __devexit_p(maceps2_remove), + .remove = maceps2_remove, }; static int __init maceps2_init(void) diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 0c42497..9809373 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -212,7 +212,7 @@ static struct pci_driver pcips2_driver = { .name = "pcips2", .id_table = pcips2_ids, .probe = pcips2_probe, - .remove = __devexit_p(pcips2_remove), + .remove = pcips2_remove, }; module_pci_driver(pcips2_driver); diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 0c0df7f..5304880 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -190,7 +190,7 @@ static struct platform_driver q40kbd_driver = { .name = "q40kbd", .owner = THIS_MODULE, }, - .remove = __devexit_p(q40kbd_remove), + .remove = q40kbd_remove, }; static int __init q40kbd_init(void) diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index 2af5df6..a5100d4 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -166,7 +166,7 @@ static int __devexit rpckbd_remove(struct platform_device *dev) static struct platform_driver rpckbd_driver = { .probe = rpckbd_probe, - .remove = __devexit_p(rpckbd_remove), + .remove = rpckbd_remove, .driver = { .name = "kart", .owner = THIS_MODULE, diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 3897667..4aacf4f 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -357,7 +357,7 @@ static struct sa1111_driver ps2_driver = { }, .devid = SA1111_DEVID_PS2, .probe = ps2_probe, - .remove = __devexit_p(ps2_remove), + .remove = ps2_remove, }; static int __init ps2_init(void) diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 1e983be..73f90dd8 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -368,7 +368,7 @@ static struct platform_driver xps2_of_driver = { .of_match_table = xps2_of_match, }, .probe = xps2_of_probe, - .remove = __devexit_p(xps2_of_remove), + .remove = xps2_of_remove, }; module_platform_driver(xps2_of_driver); diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 326218d..e609db8 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -310,7 +310,7 @@ static struct platform_driver pm860x_touch_driver = { .owner = THIS_MODULE, }, .probe = pm860x_touch_probe, - .remove = __devexit_p(pm860x_touch_remove), + .remove = pm860x_touch_remove, }; module_platform_driver(pm860x_touch_driver); diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index 2c76921..d2df6a4 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -857,7 +857,7 @@ static struct spi_driver ad7877_driver = { .pm = &ad7877_pm, }, .probe = ad7877_probe, - .remove = __devexit_p(ad7877_remove), + .remove = ad7877_remove, }; module_spi_driver(ad7877_driver); diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index 3054354..850c95d 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -98,7 +98,7 @@ static struct i2c_driver ad7879_i2c_driver = { .pm = &ad7879_pm_ops, }, .probe = ad7879_i2c_probe, - .remove = __devexit_p(ad7879_i2c_remove), + .remove = ad7879_i2c_remove, .id_table = ad7879_id, }; diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index db49abf..86b0fdb 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -154,7 +154,7 @@ static struct spi_driver ad7879_spi_driver = { .pm = &ad7879_pm_ops, }, .probe = ad7879_spi_probe, - .remove = __devexit_p(ad7879_spi_remove), + .remove = ad7879_spi_remove, }; module_spi_driver(ad7879_spi_driver); diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 78e5d9a..560484d 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -1434,7 +1434,7 @@ static struct spi_driver ads7846_driver = { .pm = &ads7846_pm, }, .probe = ads7846_probe, - .remove = __devexit_p(ads7846_remove), + .remove = ads7846_remove, }; module_spi_driver(ads7846_driver); diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 1df2396..6199303 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1270,7 +1270,7 @@ static struct i2c_driver mxt_driver = { .pm = &mxt_pm_ops, }, .probe = mxt_probe, - .remove = __devexit_p(mxt_remove), + .remove = mxt_remove, .id_table = mxt_id, }; diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 201b2d2..53712b9 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -346,7 +346,7 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev) static struct platform_driver atmel_tsadcc_driver = { .probe = atmel_tsadcc_probe, - .remove = __devexit_p(atmel_tsadcc_remove), + .remove = atmel_tsadcc_remove, .driver = { .name = "atmel_tsadcc", }, diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index c7047b6..912926d 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -631,7 +631,7 @@ static struct i2c_driver auo_pixcir_driver = { .pm = &auo_pixcir_pm_ops, }, .probe = auo_pixcir_probe, - .remove = __devexit_p(auo_pixcir_remove), + .remove = auo_pixcir_remove, .id_table = auo_pixcir_idtable, }; diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index 5c487d2..c2be1fe 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -649,7 +649,7 @@ static struct i2c_driver bu21013_driver = { #endif }, .probe = bu21013_probe, - .remove = __devexit_p(bu21013_remove), + .remove = bu21013_remove, .id_table = bu21013_id, }; diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index ad6a664..9a2044f 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -357,7 +357,7 @@ static struct i2c_driver cy8ctmg110_driver = { }, .id_table = cy8ctmg110_idtable, .probe = cy8ctmg110_probe, - .remove = __devexit_p(cy8ctmg110_remove), + .remove = cy8ctmg110_remove, }; module_i2c_driver(cy8ctmg110_driver); diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 2af1d0c..1a7aca9 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -124,7 +124,7 @@ static struct i2c_driver cyttsp_i2c_driver = { .pm = &cyttsp_pm_ops, }, .probe = cyttsp_i2c_probe, - .remove = __devexit_p(cyttsp_i2c_remove), + .remove = cyttsp_i2c_remove, .id_table = cyttsp_i2c_id, }; diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c index 9f26341..915af4c 100644 --- a/drivers/input/touchscreen/cyttsp_spi.c +++ b/drivers/input/touchscreen/cyttsp_spi.c @@ -188,7 +188,7 @@ static struct spi_driver cyttsp_spi_driver = { .pm = &cyttsp_pm_ops, }, .probe = cyttsp_spi_probe, - .remove = __devexit_p(cyttsp_spi_remove), + .remove = cyttsp_spi_remove, }; module_spi_driver(cyttsp_spi_driver); diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c index 36b65cf..ec156a6 100644 --- a/drivers/input/touchscreen/da9034-ts.c +++ b/drivers/input/touchscreen/da9034-ts.c @@ -377,7 +377,7 @@ static struct platform_driver da9034_touch_driver = { .owner = THIS_MODULE, }, .probe = da9034_touch_probe, - .remove = __devexit_p(da9034_touch_remove), + .remove = da9034_touch_remove, }; module_platform_driver(da9034_touch_driver); diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index e8df341..5dfb39b 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c @@ -355,7 +355,7 @@ static int __devexit da9052_ts_remove(struct platform_device *pdev) static struct platform_driver da9052_tsi_driver = { .probe = da9052_ts_probe, - .remove = __devexit_p(da9052_ts_remove), + .remove = da9052_ts_remove, .driver = { .name = "da9052-tsi", .owner = THIS_MODULE, diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index d9c6007..65ed9d9 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -883,7 +883,7 @@ static struct i2c_driver edt_ft5x06_ts_driver = { }, .id_table = edt_ft5x06_ts_id, .probe = edt_ft5x06_ts_probe, - .remove = __devexit_p(edt_ft5x06_ts_remove), + .remove = edt_ft5x06_ts_remove, }; module_i2c_driver(edt_ft5x06_ts_driver); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 908407e..a2d9a65 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -321,7 +321,7 @@ static struct i2c_driver eeti_ts_driver = { #endif }, .probe = eeti_ts_probe, - .remove = __devexit_p(eeti_ts_remove), + .remove = eeti_ts_remove, .id_table = eeti_ts_id, }; diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 13fa62f..d85078d 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -301,7 +301,7 @@ static struct i2c_driver egalax_ts_driver = { }, .id_table = egalax_ts_id, .probe = egalax_ts_probe, - .remove = __devexit_p(egalax_ts_remove), + .remove = egalax_ts_remove, }; module_i2c_driver(egalax_ts_driver); diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c index d13143b..5cc3240 100644 --- a/drivers/input/touchscreen/htcpen.c +++ b/drivers/input/touchscreen/htcpen.c @@ -210,7 +210,7 @@ static int htcpen_isa_resume(struct device *dev, unsigned int n) static struct isa_driver htcpen_isa_driver = { .probe = htcpen_isa_probe, - .remove = __devexit_p(htcpen_isa_remove), + .remove = htcpen_isa_remove, #ifdef CONFIG_PM .suspend = htcpen_isa_suspend, .resume = htcpen_isa_resume, diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 4ac6976..e8fd6c2 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -350,7 +350,7 @@ static struct i2c_driver ili210x_ts_driver = { }, .id_table = ili210x_i2c_id, .probe = ili210x_i2c_probe, - .remove = __devexit_p(ili210x_i2c_remove), + .remove = ili210x_i2c_remove, }; module_i2c_driver(ili210x_ts_driver); diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c index cf29937..f27364f 100644 --- a/drivers/input/touchscreen/intel-mid-touch.c +++ b/drivers/input/touchscreen/intel-mid-touch.c @@ -662,7 +662,7 @@ static struct platform_driver mrstouch_driver = { .owner = THIS_MODULE, }, .probe = mrstouch_probe, - .remove = __devexit_p(mrstouch_remove), + .remove = mrstouch_remove, }; module_platform_driver(mrstouch_driver); diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index 7f03d1bd..ad35c8c 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -168,7 +168,7 @@ MODULE_ALIAS("platform:jornada_ts"); static struct platform_driver jornada720_ts_driver = { .probe = jornada720_ts_probe, - .remove = __devexit_p(jornada720_ts_remove), + .remove = jornada720_ts_remove, .driver = { .name = "jornada_ts", .owner = THIS_MODULE, diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index 4c2b8ed..8134f61 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -394,7 +394,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match); static struct platform_driver lpc32xx_ts_driver = { .probe = lpc32xx_ts_probe, - .remove = __devexit_p(lpc32xx_ts_remove), + .remove = lpc32xx_ts_remove, .driver = { .name = MOD_NAME, .owner = THIS_MODULE, diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index 4eab50b..e3e637f 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -252,7 +252,7 @@ static struct i2c_driver max11801_ts_driver = { }, .id_table = max11801_ts_id, .probe = max11801_ts_probe, - .remove = __devexit_p(max11801_ts_remove), + .remove = max11801_ts_remove, }; module_i2c_driver(max11801_ts_driver); diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index 48dc5b0..5c18c5c 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -243,7 +243,7 @@ static int __devexit mc13783_ts_remove(struct platform_device *pdev) } static struct platform_driver mc13783_ts_driver = { - .remove = __devexit_p(mc13783_ts_remove), + .remove = mc13783_ts_remove, .driver = { .owner = THIS_MODULE, .name = MC13783_TS_NAME, diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index b528511..94a4ff6 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -292,7 +292,7 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id); static struct i2c_driver mcs5000_ts_driver = { .probe = mcs5000_ts_probe, - .remove = __devexit_p(mcs5000_ts_remove), + .remove = mcs5000_ts_remove, .driver = { .name = "mcs5000_ts", #ifdef CONFIG_PM diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 3426d2e..f4c1bc8 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -590,7 +590,7 @@ static struct i2c_driver mms114_driver = { .of_match_table = of_match_ptr(mms114_dt_match), }, .probe = mms114_probe, - .remove = __devexit_p(mms114_remove), + .remove = mms114_remove, .id_table = mms114_id, }; diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c index f57aeb8..97f07ba 100644 --- a/drivers/input/touchscreen/pcap_ts.c +++ b/drivers/input/touchscreen/pcap_ts.c @@ -245,7 +245,7 @@ static const struct dev_pm_ops pcap_ts_pm_ops = { static struct platform_driver pcap_ts_driver = { .probe = pcap_ts_probe, - .remove = __devexit_p(pcap_ts_remove), + .remove = pcap_ts_remove, .driver = { .name = "pcap-ts", .owner = THIS_MODULE, diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 953b4c1..4fcb63e 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -218,7 +218,7 @@ static struct i2c_driver pixcir_i2c_ts_driver = { .pm = &pixcir_dev_pm_ops, }, .probe = pixcir_i2c_ts_probe, - .remove = __devexit_p(pixcir_i2c_ts_remove), + .remove = pixcir_i2c_ts_remove, .id_table = pixcir_i2c_ts_id, }; diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index 549fa29..4dda765 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -430,7 +430,7 @@ static struct platform_driver s3c_ts_driver = { }, .id_table = s3cts_driver_ids, .probe = s3c2410ts_probe, - .remove = __devexit_p(s3c2410ts_remove), + .remove = s3c2410ts_remove, }; module_platform_driver(s3c_ts_driver); diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 6cb68a1..62a4b5d 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -264,7 +264,7 @@ MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids); static struct i2c_driver st1232_ts_driver = { .probe = st1232_ts_probe, - .remove = __devexit_p(st1232_ts_remove), + .remove = st1232_ts_remove, .id_table = st1232_ts_id, .driver = { .name = ST1232_TS_NAME, diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 43e7967..f489754 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -386,7 +386,7 @@ static struct platform_driver stmpe_ts_driver = { .owner = THIS_MODULE, }, .probe = stmpe_input_probe, - .remove = __devexit_p(stmpe_ts_remove), + .remove = stmpe_ts_remove, }; module_platform_driver(stmpe_ts_driver); diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c index 368d2c6c..62d57e8 100644 --- a/drivers/input/touchscreen/tnetv107x-ts.c +++ b/drivers/input/touchscreen/tnetv107x-ts.c @@ -374,7 +374,7 @@ static int __devexit tsc_remove(struct platform_device *pdev) static struct platform_driver tsc_driver = { .probe = tsc_probe, - .remove = __devexit_p(tsc_remove), + .remove = tsc_remove, .driver.name = "tnetv107x-ts", .driver.owner = THIS_MODULE, }; diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c index f7eda3d..e1ec9e0 100644 --- a/drivers/input/touchscreen/tps6507x-ts.c +++ b/drivers/input/touchscreen/tps6507x-ts.c @@ -367,7 +367,7 @@ static struct platform_driver tps6507x_ts_driver = { .owner = THIS_MODULE, }, .probe = tps6507x_ts_probe, - .remove = __devexit_p(tps6507x_ts_remove), + .remove = tps6507x_ts_remove, }; module_platform_driver(tps6507x_ts_driver); diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 5ce3fa8..db472a8 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -745,7 +745,7 @@ static struct spi_driver tsc2005_driver = { .pm = &tsc2005_pm_ops, }, .probe = tsc2005_probe, - .remove = __devexit_p(tsc2005_remove), + .remove = tsc2005_remove, }; module_spi_driver(tsc2005_driver); diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 1473d23..3b19583 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -396,7 +396,7 @@ static struct i2c_driver tsc2007_driver = { }, .id_table = tsc2007_idtable, .probe = tsc2007_probe, - .remove = __devexit_p(tsc2007_remove), + .remove = tsc2007_remove, }; module_i2c_driver(tsc2007_driver); diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 46e83ad..780eda6 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -442,7 +442,7 @@ static SIMPLE_DEV_PM_OPS(ucb1400_ts_pm_ops, static struct platform_driver ucb1400_ts_driver = { .probe = ucb1400_ts_probe, - .remove = __devexit_p(ucb1400_ts_remove), + .remove = ucb1400_ts_remove, .driver = { .name = "ucb1400_ts", .owner = THIS_MODULE, diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index 9396b21..039e4ea 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -325,7 +325,7 @@ static int __devexit w90x900ts_remove(struct platform_device *pdev) static struct platform_driver w90x900ts_driver = { .probe = w90x900ts_probe, - .remove = __devexit_p(w90x900ts_remove), + .remove = w90x900ts_remove, .driver = { .name = "nuc900-ts", .owner = THIS_MODULE, diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index 0c01657..0c033df 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -272,7 +272,7 @@ static struct i2c_driver wacom_i2c_driver = { }, .probe = wacom_i2c_probe, - .remove = __devexit_p(wacom_i2c_remove), + .remove = wacom_i2c_remove, .id_table = wacom_i2c_id, }; module_i2c_driver(wacom_i2c_driver); diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index c7eee56..17f14b6 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -398,7 +398,7 @@ static struct platform_driver wm831x_ts_driver = { .owner = THIS_MODULE, }, .probe = wm831x_ts_probe, - .remove = __devexit_p(wm831x_ts_remove), + .remove = wm831x_ts_remove, }; module_platform_driver(wm831x_ts_driver); -- cgit v0.10.2 From d6f6dfd941de2b106af1290b810eff9b1c523772 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Fri, 23 Nov 2012 21:30:24 -0800 Subject: Input: remove use of __devinitdata CONFIG_HOTPLUG is going away as an option so __devinitdata is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 48ef283..0bbcf97 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -87,7 +87,7 @@ struct tegra_kbc { struct clk *clk; }; -static const u32 tegra_kbc_default_keymap[] __devinitdata = { +static const u32 tegra_kbc_default_keymap[] = { KEY(0, 2, KEY_W), KEY(0, 3, KEY_S), KEY(0, 4, KEY_A), @@ -223,7 +223,7 @@ static const u32 tegra_kbc_default_keymap[] __devinitdata = { }; static const -struct matrix_keymap_data tegra_kbc_default_keymap_data __devinitdata = { +struct matrix_keymap_data tegra_kbc_default_keymap_data = { .keymap = tegra_kbc_default_keymap, .keymap_size = ARRAY_SIZE(tegra_kbc_default_keymap), }; diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index 0788c94..5b459d7 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -158,7 +158,7 @@ struct bma150_data { * are stated and verified by Bosch Sensortec where they are configured * to provide a generic sensitivity performance. */ -static struct bma150_cfg default_cfg __devinitdata = { +static struct bma150_cfg default_cfg = { .any_motion_int = 1, .hg_int = 1, .lg_int = 1, diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index f4c1bc8..0334898 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -576,7 +576,7 @@ static const struct i2c_device_id mms114_id[] = { MODULE_DEVICE_TABLE(i2c, mms114_id); #ifdef CONFIG_OF -static struct of_device_id __devinitdata mms114_dt_match[] = { +static struct of_device_id mms114_dt_match[] = { { .compatible = "melfas,mms114" }, { } }; -- cgit v0.10.2 From 78f50c246f4286d40a1f42fecc779d47e40503a2 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Fri, 23 Nov 2012 21:31:00 -0800 Subject: Input: remove use of __devinitconst CONFIG_HOTPLUG is going away as an option so __devinitconst is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index 5f66272..dba900c 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -46,7 +46,7 @@ MODULE_LICENSE("GPL"); #define KEY_CENTER KEY_F15 static const unsigned char -locomokbd_keycode[LOCOMOKBD_NUMKEYS] __devinitconst = { +locomokbd_keycode[LOCOMOKBD_NUMKEYS] = { 0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0, /* 0 - 9 */ 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT, /* 10 - 19 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 29 */ diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 63b20d0..38b1c0f 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -71,7 +71,7 @@ struct mpr121_init_register { u8 val; }; -static const struct mpr121_init_register init_reg_table[] __devinitconst = { +static const struct mpr121_init_register init_reg_table[] = { { MHD_RISING_ADDR, 0x1 }, { NHD_RISING_ADDR, 0x1 }, { MHD_FALLING_ADDR, 0x1 }, diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 73f90dd8..f929d8f 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -355,7 +355,7 @@ static int __devexit xps2_of_remove(struct platform_device *of_dev) } /* Match table for of_platform binding */ -static const struct of_device_id xps2_of_match[] __devinitconst = { +static const struct of_device_id xps2_of_match[] = { { .compatible = "xlnx,xps-ps2-1.00.a", }, { /* end of list */ }, }; diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 62a4b5d..5fa0ca3 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -255,7 +255,7 @@ static const struct i2c_device_id st1232_ts_id[] = { MODULE_DEVICE_TABLE(i2c, st1232_ts_id); #ifdef CONFIG_OF -static const struct of_device_id st1232_ts_dt_ids[] __devinitconst = { +static const struct of_device_id st1232_ts_dt_ids[] = { { .compatible = "sitronix,st1232", }, { } }; -- cgit v0.10.2 From 5298cc4cc753bbe4c530b41341834f6ef3344d0d Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Fri, 23 Nov 2012 21:38:25 -0800 Subject: Input: remove use of __devinit CONFIG_HOTPLUG is going away as an option so __devinit is no longer needed. Signed-off-by: Bill Pemberton Acked-by: Mark Brown Acked-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index c300089..786fa31 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -57,7 +57,7 @@ static const struct pci_device_id emu_tbl[] = { MODULE_DEVICE_TABLE(pci, emu_tbl); -static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct emu *emu; struct gameport *port; diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index e3ab458..b1705e1 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -78,7 +78,7 @@ static int fm801_gp_open(struct gameport *gameport, int mode) return 0; } -static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id) +static int fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id) { struct fm801_gp *gp; struct gameport *port; diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index 94f3327..ad76733 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -157,7 +157,7 @@ out: return IRQ_HANDLED; } -static int __devinit as5011_configure_chip(struct as5011_device *as5011, +static int as5011_configure_chip(struct as5011_device *as5011, const struct as5011_platform_data *plat_dat) { struct i2c_client *client = as5011->i2c_client; @@ -225,8 +225,8 @@ static int __devinit as5011_configure_chip(struct as5011_device *as5011, return 0; } -static int __devinit as5011_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int as5011_probe(struct i2c_client *client, + const struct i2c_device_id *id) { const struct as5011_platform_data *plat_data; struct as5011_device *as5011; diff --git a/drivers/input/joystick/maplecontrol.c b/drivers/input/joystick/maplecontrol.c index c843457..5ff3cb4 100644 --- a/drivers/input/joystick/maplecontrol.c +++ b/drivers/input/joystick/maplecontrol.c @@ -78,7 +78,7 @@ static void dc_pad_close(struct input_dev *dev) } /* allow the controller to be used */ -static int __devinit probe_maple_controller(struct device *dev) +static int probe_maple_controller(struct device *dev) { static const short btn_bit[32] = { BTN_C, BTN_B, BTN_A, BTN_START, -1, -1, -1, -1, diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c index 46796b2..64de965 100644 --- a/drivers/input/keyboard/adp5520-keys.c +++ b/drivers/input/keyboard/adp5520-keys.c @@ -69,7 +69,7 @@ static int adp5520_keys_notifier(struct notifier_block *nb, return 0; } -static int __devinit adp5520_keys_probe(struct platform_device *pdev) +static int adp5520_keys_probe(struct platform_device *pdev) { struct adp5520_keys_platform_data *pdata = pdev->dev.platform_data; struct input_dev *input; diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 39c2a6d..a20fe70 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -145,7 +145,7 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip, return ret; } -static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad, +static int adp5588_build_gpiomap(struct adp5588_kpad *kpad, const struct adp5588_kpad_platform_data *pdata) { bool pin_used[ADP5588_MAXGPIO]; @@ -170,7 +170,7 @@ static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad, return n_unused; } -static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad) +static int adp5588_gpio_add(struct adp5588_kpad *kpad) { struct device *dev = &kpad->client->dev; const struct adp5588_kpad_platform_data *pdata = dev->platform_data; @@ -319,7 +319,7 @@ static irqreturn_t adp5588_irq(int irq, void *handle) return IRQ_HANDLED; } -static int __devinit adp5588_setup(struct i2c_client *client) +static int adp5588_setup(struct i2c_client *client) { const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data; @@ -382,7 +382,7 @@ static int __devinit adp5588_setup(struct i2c_client *client) return 0; } -static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad) +static void adp5588_report_switch_state(struct adp5588_kpad *kpad) { int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1); int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2); @@ -420,8 +420,8 @@ static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad) } -static int __devinit adp5588_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adp5588_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct adp5588_kpad *kpad; const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 6e0c2e3..8f591da 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -464,7 +464,7 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, return ret; } -static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad, +static int adp5589_build_gpiomap(struct adp5589_kpad *kpad, const struct adp5589_kpad_platform_data *pdata) { bool pin_used[ADP5589_MAXGPIO]; @@ -496,7 +496,7 @@ static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad, return n_unused; } -static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad) +static int adp5589_gpio_add(struct adp5589_kpad *kpad) { struct device *dev = &kpad->client->dev; const struct adp5589_kpad_platform_data *pdata = dev->platform_data; @@ -641,8 +641,7 @@ static irqreturn_t adp5589_irq(int irq, void *handle) return IRQ_HANDLED; } -static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, - unsigned short key) +static int adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key) { int i; @@ -655,7 +654,7 @@ static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, return -EINVAL; } -static int __devinit adp5589_setup(struct adp5589_kpad *kpad) +static int adp5589_setup(struct adp5589_kpad *kpad) { struct i2c_client *client = kpad->client; const struct adp5589_kpad_platform_data *pdata = @@ -820,7 +819,7 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad) return 0; } -static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad) +static void adp5589_report_switch_state(struct adp5589_kpad *kpad) { int gpi_stat_tmp, pin_loc; int i; @@ -860,8 +859,8 @@ static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad) input_sync(kpad->input); } -static int __devinit adp5589_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adp5589_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct adp5589_kpad *kpad; const struct adp5589_kpad_platform_data *pdata = diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index 8a7909a..8f3c2b6 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c @@ -177,7 +177,7 @@ static irqreturn_t bfin_kpad_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit bfin_kpad_probe(struct platform_device *pdev) +static int bfin_kpad_probe(struct platform_device *pdev) { struct bf54x_kpad *bf54x_kpad; struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data; diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index bdf3261..30c0008 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -232,7 +232,7 @@ static int ep93xx_keypad_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops, ep93xx_keypad_suspend, ep93xx_keypad_resume); -static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) +static int ep93xx_keypad_probe(struct platform_device *pdev) { struct ep93xx_keypad *keypad; const struct matrix_keymap_data *keymap_data; diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 96b5ac5..c714c58 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -423,10 +423,10 @@ out: return IRQ_HANDLED; } -static int __devinit gpio_keys_setup_key(struct platform_device *pdev, - struct input_dev *input, - struct gpio_button_data *bdata, - const struct gpio_keys_button *button) +static int gpio_keys_setup_key(struct platform_device *pdev, + struct input_dev *input, + struct gpio_button_data *bdata, + const struct gpio_keys_button *button) { const char *desc = button->desc ? button->desc : "gpio_keys"; struct device *dev = &pdev->dev; @@ -551,7 +551,7 @@ static void gpio_keys_close(struct input_dev *input) /* * Translate OpenFirmware node properties into platform_data */ -static struct gpio_keys_platform_data * __devinit +static struct gpio_keys_platform_data * gpio_keys_get_devtree_pdata(struct device *dev) { struct device_node *node, *pp; @@ -658,7 +658,7 @@ static void gpio_remove_key(struct gpio_button_data *bdata) gpio_free(bdata->button->gpio); } -static int __devinit gpio_keys_probe(struct platform_device *pdev) +static int gpio_keys_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 922cbbd..8c09ce2 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -103,8 +103,7 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev) } #ifdef CONFIG_OF -static struct gpio_keys_platform_data * __devinit -gpio_keys_polled_get_devtree_pdata(struct device *dev) +static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev) { struct device_node *node, *pp; struct gpio_keys_platform_data *pdata; @@ -196,7 +195,7 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev) } #endif -static int __devinit gpio_keys_polled_probe(struct platform_device *pdev) +static int gpio_keys_polled_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index 97d3151..a5da05a 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -200,7 +200,7 @@ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) /* initialize HIL */ -static int __devinit hil_keyb_init(void) +static int hil_keyb_init(void) { unsigned char c; unsigned int i, kbid; @@ -299,7 +299,7 @@ static void __devexit hil_keyb_exit(void) } #if defined(CONFIG_PARISC) -static int __devinit hil_probe_chip(struct parisc_device *dev) +static int hil_probe_chip(struct parisc_device *dev) { /* Only allow one HIL keyboard */ if (hil_dev.dev) diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 93c3441..d4d9542 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -413,7 +413,7 @@ open_err: return -EIO; } -static int __devinit imx_keypad_probe(struct platform_device *pdev) +static int imx_keypad_probe(struct platform_device *pdev) { const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data; struct imx_keypad *keypad; diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c index bd1a9c3..eac650c 100644 --- a/drivers/input/keyboard/jornada680_kbd.c +++ b/drivers/input/keyboard/jornada680_kbd.c @@ -179,7 +179,7 @@ static void jornadakbd680_poll(struct input_polled_dev *dev) memcpy(jornadakbd->old_scan, jornadakbd->new_scan, JORNADA_SCAN_SIZE); } -static int __devinit jornada680kbd_probe(struct platform_device *pdev) +static int jornada680kbd_probe(struct platform_device *pdev) { struct jornadakbd *jornadakbd; struct input_polled_dev *poll_dev; diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 9771db1..2f08a03 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -94,7 +94,7 @@ static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id) return IRQ_HANDLED; }; -static int __devinit jornada720_kbd_probe(struct platform_device *pdev) +static int jornada720_kbd_probe(struct platform_device *pdev) { struct jornadakbd *jornadakbd; struct input_dev *input_dev; diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 8743285..ee0116b 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -624,7 +624,7 @@ static ssize_t lm8323_set_disable(struct device *dev, } static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable); -static int __devinit lm8323_probe(struct i2c_client *client, +static int lm8323_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lm8323_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c index c76e488..9fc0372 100644 --- a/drivers/input/keyboard/lm8333.c +++ b/drivers/input/keyboard/lm8333.c @@ -128,7 +128,7 @@ static irqreturn_t lm8333_irq_thread(int irq, void *data) return IRQ_HANDLED; } -static int __devinit lm8333_probe(struct i2c_client *client, +static int lm8333_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct lm8333_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index dba900c..e289246 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -236,7 +236,7 @@ static void locomokbd_close(struct input_dev *dev) locomo_writel(r, locomokbd->base + LOCOMO_KIC); } -static int __devinit locomokbd_probe(struct locomo_dev *dev) +static int locomokbd_probe(struct locomo_dev *dev) { struct locomokbd *locomokbd; struct input_dev *input_dev; diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 8872ce6..72f8a0b 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -139,7 +139,7 @@ static void lpc32xx_kscan_close(struct input_dev *dev) clk_disable_unprepare(kscandat->clk); } -static int __devinit lpc32xx_parse_dt(struct device *dev, +static int lpc32xx_parse_dt(struct device *dev, struct lpc32xx_kscan_drv *kscandat) { struct device_node *np = dev->of_node; @@ -166,7 +166,7 @@ static int __devinit lpc32xx_parse_dt(struct device *dev, return 0; } -static int __devinit lpc32xx_kscan_probe(struct platform_device *pdev) +static int lpc32xx_kscan_probe(struct platform_device *pdev) { struct lpc32xx_kscan_drv *kscandat; struct input_dev *input; diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index ed2bacd..b9d67c2 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -301,8 +301,8 @@ static int matrix_keypad_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops, matrix_keypad_suspend, matrix_keypad_resume); -static int __devinit matrix_keypad_init_gpio(struct platform_device *pdev, - struct matrix_keypad *keypad) +static int matrix_keypad_init_gpio(struct platform_device *pdev, + struct matrix_keypad *keypad) { const struct matrix_keypad_platform_data *pdata = keypad->pdata; int i, err; @@ -397,7 +397,7 @@ static void matrix_keypad_free_gpio(struct matrix_keypad *keypad) } #ifdef CONFIG_OF -static struct matrix_keypad_platform_data * __devinit +static struct matrix_keypad_platform_data * matrix_keypad_parse_dt(struct device *dev) { struct matrix_keypad_platform_data *pdata; @@ -465,7 +465,7 @@ matrix_keypad_parse_dt(struct device *dev) } #endif -static int __devinit matrix_keypad_probe(struct platform_device *pdev) +static int matrix_keypad_probe(struct platform_device *pdev) { const struct matrix_keypad_platform_data *pdata; struct matrix_keypad *keypad; diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index 90478d1..98b8ff1 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -179,7 +179,7 @@ static void max7359_initialize(struct i2c_client *client) max7359_fall_deepsleep(client); } -static int __devinit max7359_probe(struct i2c_client *client, +static int max7359_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct matrix_keymap_data *keymap_data = client->dev.platform_data; diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index 751b141..e729774 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -97,7 +97,7 @@ static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit mcs_touchkey_probe(struct i2c_client *client, +static int mcs_touchkey_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct mcs_platform_data *pdata; diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 38b1c0f..854486c 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -123,7 +123,7 @@ out: return IRQ_HANDLED; } -static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata, +static int mpr121_phys_init(const struct mpr121_platform_data *pdata, struct mpr121_touchkey *mpr121, struct i2c_client *client) { @@ -185,8 +185,8 @@ err_i2c_write: return ret; } -static int __devinit mpr_touchkey_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mpr_touchkey_probe(struct i2c_client *client, + const struct i2c_device_id *id) { const struct mpr121_platform_data *pdata = client->dev.platform_data; struct mpr121_touchkey *mpr121; diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 1d17d91..ffb8c6c 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -244,7 +244,7 @@ static int omap_kp_resume(struct platform_device *dev) #define omap_kp_resume NULL #endif -static int __devinit omap_kp_probe(struct platform_device *pdev) +static int omap_kp_probe(struct platform_device *pdev) { struct omap_kp *omap_kp; struct input_dev *input_dev; diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 7145ab3..c16a322 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -211,8 +211,8 @@ static void omap4_keypad_close(struct input_dev *input) } #ifdef CONFIG_OF -static int __devinit omap4_keypad_parse_dt(struct device *dev, - struct omap4_keypad *keypad_data) +static int omap4_keypad_parse_dt(struct device *dev, + struct omap4_keypad *keypad_data) { struct device_node *np = dev->of_node; @@ -241,7 +241,7 @@ static inline int omap4_keypad_parse_dt(struct device *dev, } #endif -static int __devinit omap4_keypad_probe(struct platform_device *pdev) +static int omap4_keypad_probe(struct platform_device *pdev) { const struct omap4_keypad_platform_data *pdata = dev_get_platdata(&pdev->dev); diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c index 7914ede..ddc1c39 100644 --- a/drivers/input/keyboard/opencores-kbd.c +++ b/drivers/input/keyboard/opencores-kbd.c @@ -37,7 +37,7 @@ static irqreturn_t opencores_kbd_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit opencores_kbd_probe(struct platform_device *pdev) +static int opencores_kbd_probe(struct platform_device *pdev) { struct input_dev *input; struct opencores_kbd *opencores_kbd; diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index d3623c5..fa177ab 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -397,7 +397,7 @@ static irqreturn_t pmic8xxx_kp_irq(int irq, void *data) return IRQ_HANDLED; } -static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp) +static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp) { int bits, rc, cycles; u8 scan_val = 0, ctrl_val = 0; @@ -447,7 +447,7 @@ static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp) } -static int __devinit pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios, +static int pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios, struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config) { int rc, i; @@ -518,7 +518,7 @@ static void pmic8xxx_kp_close(struct input_dev *dev) * - set irq edge type. * - enable the keypad controller. */ -static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev) +static int pmic8xxx_kp_probe(struct platform_device *pdev) { const struct pm8xxx_keypad_platform_data *pdata = dev_get_platdata(&pdev->dev); diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index a6bcd31..91778fe 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -482,7 +482,7 @@ static const struct dev_pm_ops pxa27x_keypad_pm_ops = { }; #endif -static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) +static int pxa27x_keypad_probe(struct platform_device *pdev) { struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; struct pxa27x_keypad *keypad; diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c index f8f89d1..60797c2 100644 --- a/drivers/input/keyboard/pxa930_rotary.c +++ b/drivers/input/keyboard/pxa930_rotary.c @@ -82,7 +82,7 @@ static void pxa930_rotary_close(struct input_dev *dev) clear_sbcr(r); } -static int __devinit pxa930_rotary_probe(struct platform_device *pdev) +static int pxa930_rotary_probe(struct platform_device *pdev) { struct pxa930_rotary_platform_data *pdata = pdev->dev.platform_data; struct pxa930_rotary *r; diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index eb46405..f9358e7 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -91,7 +91,7 @@ static int qt1070_write(struct i2c_client *client, u8 reg, u8 data) return ret; } -static bool __devinit qt1070_identify(struct i2c_client *client) +static bool qt1070_identify(struct i2c_client *client) { int id, ver; @@ -140,7 +140,7 @@ static irqreturn_t qt1070_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit qt1070_probe(struct i2c_client *client, +static int qt1070_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct qt1070_data *data; diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 691fe92..69a6a6f 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -183,7 +183,7 @@ static void qt2160_worker(struct work_struct *work) qt2160_schedule_read(qt2160); } -static int __devinit qt2160_read(struct i2c_client *client, u8 reg) +static int qt2160_read(struct i2c_client *client, u8 reg) { int ret; @@ -204,7 +204,7 @@ static int __devinit qt2160_read(struct i2c_client *client, u8 reg) return ret; } -static int __devinit qt2160_write(struct i2c_client *client, u8 reg, u8 data) +static int qt2160_write(struct i2c_client *client, u8 reg, u8 data) { int ret; @@ -217,7 +217,7 @@ static int __devinit qt2160_write(struct i2c_client *client, u8 reg, u8 data) } -static bool __devinit qt2160_identify(struct i2c_client *client) +static bool qt2160_identify(struct i2c_client *client) { int id, ver, rev; @@ -248,7 +248,7 @@ static bool __devinit qt2160_identify(struct i2c_client *client) return true; } -static int __devinit qt2160_probe(struct i2c_client *client, +static int qt2160_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct qt2160_data *qt2160; diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index f02772a..5c6a808 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -366,7 +366,7 @@ static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) } #endif -static int __devinit samsung_keypad_probe(struct platform_device *pdev) +static int samsung_keypad_probe(struct platform_device *pdev) { const struct samsung_keypad_platdata *pdata; const struct matrix_keymap_data *keymap_data; diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 07415a3..ffa9adb 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -162,7 +162,7 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit sh_keysc_probe(struct platform_device *pdev) +static int sh_keysc_probe(struct platform_device *pdev) { struct sh_keysc_priv *priv; struct sh_keysc_info *pdata; diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index 0c88623..3c503da 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -146,7 +146,7 @@ static void spear_kbd_close(struct input_dev *dev) } #ifdef CONFIG_OF -static int __devinit spear_kbd_parse_dt(struct platform_device *pdev, +static int spear_kbd_parse_dt(struct platform_device *pdev, struct spear_kbd *kbd) { struct device_node *np = pdev->dev.of_node; @@ -181,7 +181,7 @@ static inline int spear_kbd_parse_dt(struct platform_device *pdev, } #endif -static int __devinit spear_kbd_probe(struct platform_device *pdev) +static int spear_kbd_probe(struct platform_device *pdev) { struct kbd_platform_data *pdata = dev_get_platdata(&pdev->dev); const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL; diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index 286719f..b3f917d 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -166,7 +166,7 @@ static irqreturn_t stmpe_keypad_irq(int irq, void *dev) return IRQ_HANDLED; } -static int __devinit stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad) +static int stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad) { const struct stmpe_keypad_variant *variant = keypad->variant; unsigned int col_gpios = variant->col_gpios; @@ -207,7 +207,7 @@ static int __devinit stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad) return stmpe_set_altfunc(stmpe, pins, STMPE_BLOCK_KEYPAD); } -static int __devinit stmpe_keypad_chip_init(struct stmpe_keypad *keypad) +static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad) { const struct stmpe_keypad_platform_data *plat = keypad->plat; const struct stmpe_keypad_variant *variant = keypad->variant; @@ -257,7 +257,7 @@ static int __devinit stmpe_keypad_chip_init(struct stmpe_keypad *keypad) (plat->debounce_ms << 1)); } -static int __devinit stmpe_keypad_probe(struct platform_device *pdev) +static int stmpe_keypad_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); const struct stmpe_keypad_platform_data *plat; diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 75fa2b9..6d725d6 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -299,7 +299,7 @@ static void tc3589x_keypad_close(struct input_dev *input) tc3589x_keypad_disable(keypad); } -static int __devinit tc3589x_keypad_probe(struct platform_device *pdev) +static int tc3589x_keypad_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); struct tc_keypad *keypad; diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index f5fa75a..4f44579 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -166,7 +166,7 @@ static void tca6416_keys_close(struct input_dev *dev) disable_irq(chip->irqnum); } -static int __devinit tca6416_setup_registers(struct tca6416_keypad_chip *chip) +static int tca6416_setup_registers(struct tca6416_keypad_chip *chip) { int error; @@ -197,7 +197,7 @@ static int __devinit tca6416_setup_registers(struct tca6416_keypad_chip *chip) return 0; } -static int __devinit tca6416_keypad_probe(struct i2c_client *client, +static int tca6416_keypad_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tca6416_keys_platform_data *pdata; diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 672b5f8..6f97096 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -241,7 +241,7 @@ exit: /* * Configure the TCA8418 for keypad operation */ -static int __devinit tca8418_configure(struct tca8418_keypad *keypad_data) +static int tca8418_configure(struct tca8418_keypad *keypad_data) { int reg, error; @@ -270,7 +270,7 @@ static int __devinit tca8418_configure(struct tca8418_keypad *keypad_data) return error; } -static int __devinit tca8418_keypad_probe(struct i2c_client *client, +static int tca8418_keypad_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct tca8418_keypad_platform_data *pdata = diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 0bbcf97..cf8ab68 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -573,7 +573,7 @@ static void tegra_kbc_close(struct input_dev *dev) return tegra_kbc_stop(kbc); } -static bool __devinit +static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata, struct device *dev, unsigned int *num_rows) { @@ -619,7 +619,7 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata, } #ifdef CONFIG_OF -static struct tegra_kbc_platform_data * __devinit tegra_kbc_dt_parse_pdata( +static struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata( struct platform_device *pdev) { struct tegra_kbc_platform_data *pdata; @@ -670,7 +670,7 @@ static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata( } #endif -static int __devinit tegra_kbd_setup_keymap(struct tegra_kbc *kbc) +static int tegra_kbd_setup_keymap(struct tegra_kbc *kbc) { const struct tegra_kbc_platform_data *pdata = kbc->pdata; const struct matrix_keymap_data *keymap_data = pdata->keymap_data; @@ -697,7 +697,7 @@ static int __devinit tegra_kbd_setup_keymap(struct tegra_kbc *kbc) return retval; } -static int __devinit tegra_kbc_probe(struct platform_device *pdev) +static int tegra_kbc_probe(struct platform_device *pdev) { const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data; struct tegra_kbc *kbc; diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c index 05d923c..55cd070 100644 --- a/drivers/input/keyboard/tnetv107x-keypad.c +++ b/drivers/input/keyboard/tnetv107x-keypad.c @@ -153,7 +153,7 @@ static void keypad_stop(struct input_dev *dev) clk_disable(kp->clk); } -static int __devinit keypad_probe(struct platform_device *pdev) +static int keypad_probe(struct platform_device *pdev) { const struct matrix_keypad_platform_data *pdata; const struct matrix_keymap_data *keymap_data; diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index ae25909..78dd9f27 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -271,7 +271,7 @@ static irqreturn_t do_kp_irq(int irq, void *_kp) return IRQ_HANDLED; } -static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) +static int twl4030_kp_program(struct twl4030_keypad *kp) { u8 reg; int i; @@ -328,7 +328,7 @@ static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) * Registers keypad device with input subsystem * and configures TWL4030 keypad registers */ -static int __devinit twl4030_kp_probe(struct platform_device *pdev) +static int twl4030_kp_probe(struct platform_device *pdev) { struct twl4030_keypad_data *pdata = pdev->dev.platform_data; const struct matrix_keymap_data *keymap_data; diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index a90fdfc..7574e10 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -118,7 +118,7 @@ static void w90p910_keypad_close(struct input_dev *dev) clk_disable(keypad->clk); } -static int __devinit w90p910_keypad_probe(struct platform_device *pdev) +static int w90p910_keypad_probe(struct platform_device *pdev) { const struct w90p910_keypad_platform_data *pdata = pdev->dev.platform_data; diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c index f775575..946edca 100644 --- a/drivers/input/misc/88pm80x_onkey.c +++ b/drivers/input/misc/88pm80x_onkey.c @@ -62,7 +62,7 @@ static irqreturn_t pm80x_onkey_handler(int irq, void *data) static SIMPLE_DEV_PM_OPS(pm80x_onkey_pm_ops, pm80x_dev_suspend, pm80x_dev_resume); -static int __devinit pm80x_onkey_probe(struct platform_device *pdev) +static int pm80x_onkey_probe(struct platform_device *pdev) { struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent); diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c index 8391a9d..81af2d7 100644 --- a/drivers/input/misc/88pm860x_onkey.c +++ b/drivers/input/misc/88pm860x_onkey.c @@ -56,7 +56,7 @@ static irqreturn_t pm860x_onkey_handler(int irq, void *data) return IRQ_HANDLED; } -static int __devinit pm860x_onkey_probe(struct platform_device *pdev) +static int pm860x_onkey_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_onkey_info *info; diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index ae9c205..f188222 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c @@ -45,7 +45,7 @@ static irqreturn_t ab8500_ponkey_handler(int irq, void *data) return IRQ_HANDLED; } -static int __devinit ab8500_ponkey_probe(struct platform_device *pdev) +static int ab8500_ponkey_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); struct ab8500_ponkey *ponkey; diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index 02e21d4..9477602 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -72,7 +72,7 @@ static int ad714x_i2c_read(struct ad714x_chip *chip, return 0; } -static int __devinit ad714x_i2c_probe(struct i2c_client *client, +static int ad714x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ad714x_chip *chip; diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c index eee820b..497871e 100644 --- a/drivers/input/misc/ad714x-spi.c +++ b/drivers/input/misc/ad714x-spi.c @@ -83,7 +83,7 @@ static int ad714x_spi_write(struct ad714x_chip *chip, return 0; } -static int __devinit ad714x_spi_probe(struct spi_device *spi) +static int ad714x_spi_probe(struct spi_device *spi) { struct ad714x_chip *chip; int err; diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index 09094ca..e262885 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -73,7 +73,7 @@ static const struct adxl34x_bus_ops adxl34x_i2c_bops = { .read_block = adxl34x_i2c_read_block, }; -static int __devinit adxl34x_i2c_probe(struct i2c_client *client, +static int adxl34x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adxl34x *ac; diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c index 756c899..1071d25 100644 --- a/drivers/input/misc/adxl34x-spi.c +++ b/drivers/input/misc/adxl34x-spi.c @@ -65,7 +65,7 @@ static const struct adxl34x_bus_ops adxl34x_spi_bops = { .read_block = adxl34x_spi_read_block, }; -static int __devinit adxl34x_spi_probe(struct spi_device *spi) +static int adxl34x_spi_probe(struct spi_device *spi) { struct adxl34x *ac; diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c index 6df3f88..9cb4a74 100644 --- a/drivers/input/misc/bfin_rotary.c +++ b/drivers/input/misc/bfin_rotary.c @@ -90,7 +90,7 @@ static irqreturn_t bfin_rotary_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit bfin_rotary_probe(struct platform_device *pdev) +static int bfin_rotary_probe(struct platform_device *pdev) { struct bfin_rotary_platform_data *pdata = pdev->dev.platform_data; struct bfin_rot *rotary; diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index 5b459d7..a3219c2 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -224,7 +224,7 @@ static int bma150_set_mode(struct bma150_data *bma150, u8 mode) return 0; } -static int __devinit bma150_soft_reset(struct bma150_data *bma150) +static int bma150_soft_reset(struct bma150_data *bma150) { int error; @@ -237,19 +237,19 @@ static int __devinit bma150_soft_reset(struct bma150_data *bma150) return 0; } -static int __devinit bma150_set_range(struct bma150_data *bma150, u8 range) +static int bma150_set_range(struct bma150_data *bma150, u8 range) { return bma150_set_reg_bits(bma150->client, range, BMA150_RANGE_POS, BMA150_RANGE_MSK, BMA150_RANGE_REG); } -static int __devinit bma150_set_bandwidth(struct bma150_data *bma150, u8 bw) +static int bma150_set_bandwidth(struct bma150_data *bma150, u8 bw) { return bma150_set_reg_bits(bma150->client, bw, BMA150_BANDWIDTH_POS, BMA150_BANDWIDTH_MSK, BMA150_BANDWIDTH_REG); } -static int __devinit bma150_set_low_g_interrupt(struct bma150_data *bma150, +static int bma150_set_low_g_interrupt(struct bma150_data *bma150, u8 enable, u8 hyst, u8 dur, u8 thres) { int error; @@ -273,7 +273,7 @@ static int __devinit bma150_set_low_g_interrupt(struct bma150_data *bma150, BMA150_LOW_G_EN_REG); } -static int __devinit bma150_set_high_g_interrupt(struct bma150_data *bma150, +static int bma150_set_high_g_interrupt(struct bma150_data *bma150, u8 enable, u8 hyst, u8 dur, u8 thres) { int error; @@ -300,7 +300,7 @@ static int __devinit bma150_set_high_g_interrupt(struct bma150_data *bma150, } -static int __devinit bma150_set_any_motion_interrupt(struct bma150_data *bma150, +static int bma150_set_any_motion_interrupt(struct bma150_data *bma150, u8 enable, u8 dur, u8 thres) { int error; @@ -424,7 +424,7 @@ static void bma150_poll_close(struct input_polled_dev *ipoll_dev) bma150_close(bma150); } -static int __devinit bma150_initialize(struct bma150_data *bma150, +static int bma150_initialize(struct bma150_data *bma150, const struct bma150_cfg *cfg) { int error; @@ -465,7 +465,7 @@ static int __devinit bma150_initialize(struct bma150_data *bma150, return bma150_set_mode(bma150, BMA150_MODE_SLEEP); } -static void __devinit bma150_init_input_device(struct bma150_data *bma150, +static void bma150_init_input_device(struct bma150_data *bma150, struct input_dev *idev) { idev->name = BMA150_DRIVER; @@ -479,7 +479,7 @@ static void __devinit bma150_init_input_device(struct bma150_data *bma150, input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0); } -static int __devinit bma150_register_input_device(struct bma150_data *bma150) +static int bma150_register_input_device(struct bma150_data *bma150) { struct input_dev *idev; int error; @@ -504,7 +504,7 @@ static int __devinit bma150_register_input_device(struct bma150_data *bma150) return 0; } -static int __devinit bma150_register_polled_device(struct bma150_data *bma150) +static int bma150_register_polled_device(struct bma150_data *bma150) { struct input_polled_dev *ipoll_dev; int error; @@ -535,7 +535,7 @@ static int __devinit bma150_register_polled_device(struct bma150_data *bma150) return 0; } -static int __devinit bma150_probe(struct i2c_client *client, +static int bma150_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct bma150_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c index 523b6aa..ca2103e 100644 --- a/drivers/input/misc/cma3000_d0x_i2c.c +++ b/drivers/input/misc/cma3000_d0x_i2c.c @@ -55,7 +55,7 @@ static const struct cma3000_bus_ops cma3000_i2c_bops = { .write = cma3000_i2c_set, }; -static int __devinit cma3000_i2c_probe(struct i2c_client *client, +static int cma3000_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct cma3000_accl_data *data; diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c index 659f20d..beeb53d 100644 --- a/drivers/input/misc/cobalt_btns.c +++ b/drivers/input/misc/cobalt_btns.c @@ -73,7 +73,7 @@ static void handle_buttons(struct input_polled_dev *dev) } } -static int __devinit cobalt_buttons_probe(struct platform_device *pdev) +static int cobalt_buttons_probe(struct platform_device *pdev) { struct buttons_dev *bdev; struct input_polled_dev *poll_dev; diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c index acd07e8..8464029 100644 --- a/drivers/input/misc/da9052_onkey.c +++ b/drivers/input/misc/da9052_onkey.c @@ -71,7 +71,7 @@ static irqreturn_t da9052_onkey_irq(int irq, void *data) return IRQ_HANDLED; } -static int __devinit da9052_onkey_probe(struct platform_device *pdev) +static int da9052_onkey_probe(struct platform_device *pdev) { struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); struct da9052_onkey *onkey; diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c index fe434e0..cbf4989 100644 --- a/drivers/input/misc/da9055_onkey.c +++ b/drivers/input/misc/da9055_onkey.c @@ -73,7 +73,7 @@ static irqreturn_t da9055_onkey_irq(int irq, void *data) return IRQ_HANDLED; } -static int __devinit da9055_onkey_probe(struct platform_device *pdev) +static int da9055_onkey_probe(struct platform_device *pdev) { struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent); struct da9055_onkey *onkey; diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index 1afb91c..5409ab7 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -173,7 +173,7 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) /*----------------------------------------------------------------------*/ -static int __devinit dm355evm_keys_probe(struct platform_device *pdev) +static int dm355evm_keys_probe(struct platform_device *pdev) { struct dm355evm_keys *keys; struct input_dev *input; diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c index 99ec8d0..8ad99be 100644 --- a/drivers/input/misc/gp2ap002a00f.c +++ b/drivers/input/misc/gp2ap002a00f.c @@ -98,7 +98,7 @@ static void gp2a_device_close(struct input_dev *dev) "unable to deactivate, err %d\n", error); } -static int __devinit gp2a_initialize(struct gp2a_data *dt) +static int gp2a_initialize(struct gp2a_data *dt) { int error; @@ -122,7 +122,7 @@ static int __devinit gp2a_initialize(struct gp2a_data *dt) return error; } -static int __devinit gp2a_probe(struct i2c_client *client, +static int gp2a_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct gp2a_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/input/misc/gpio_tilt_polled.c b/drivers/input/misc/gpio_tilt_polled.c index bf97679..467884b 100644 --- a/drivers/input/misc/gpio_tilt_polled.c +++ b/drivers/input/misc/gpio_tilt_polled.c @@ -96,7 +96,7 @@ static void gpio_tilt_polled_close(struct input_polled_dev *dev) pdata->disable(tdev->dev); } -static int __devinit gpio_tilt_polled_probe(struct platform_device *pdev) +static int gpio_tilt_polled_probe(struct platform_device *pdev) { const struct gpio_tilt_platform_data *pdata = pdev->dev.platform_data; struct device *dev = &pdev->dev; diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index 18a2970..97620d5 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -87,7 +87,7 @@ static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit ixp4xx_spkr_probe(struct platform_device *dev) +static int ixp4xx_spkr_probe(struct platform_device *dev) { struct input_dev *input_dev; int err; diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index 8414ddb..57f1f12 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -295,7 +295,7 @@ static void kxtj9_input_close(struct input_dev *dev) kxtj9_disable(tj9); } -static void __devinit kxtj9_init_input_device(struct kxtj9_data *tj9, +static void kxtj9_init_input_device(struct kxtj9_data *tj9, struct input_dev *input_dev) { __set_bit(EV_ABS, input_dev->evbit); @@ -308,7 +308,7 @@ static void __devinit kxtj9_init_input_device(struct kxtj9_data *tj9, input_dev->dev.parent = &tj9->client->dev; } -static int __devinit kxtj9_setup_input_device(struct kxtj9_data *tj9) +static int kxtj9_setup_input_device(struct kxtj9_data *tj9) { struct input_dev *input_dev; int err; @@ -433,7 +433,7 @@ static void kxtj9_polled_input_close(struct input_polled_dev *dev) kxtj9_disable(tj9); } -static int __devinit kxtj9_setup_polled_device(struct kxtj9_data *tj9) +static int kxtj9_setup_polled_device(struct kxtj9_data *tj9) { int err; struct input_polled_dev *poll_dev; @@ -485,7 +485,7 @@ static inline void kxtj9_teardown_polled_device(struct kxtj9_data *tj9) #endif -static int __devinit kxtj9_verify(struct kxtj9_data *tj9) +static int kxtj9_verify(struct kxtj9_data *tj9) { int retval; @@ -506,7 +506,7 @@ out: return retval; } -static int __devinit kxtj9_probe(struct i2c_client *client, +static int kxtj9_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct kxtj9_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c index f3a3c5e..ec8f59d 100644 --- a/drivers/input/misc/m68kspkr.c +++ b/drivers/input/misc/m68kspkr.c @@ -48,7 +48,7 @@ static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int return 0; } -static int __devinit m68kspkr_probe(struct platform_device *dev) +static int m68kspkr_probe(struct platform_device *dev) { struct input_dev *input_dev; int err; diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c index 3c3db67..57bc42c 100644 --- a/drivers/input/misc/max8925_onkey.c +++ b/drivers/input/misc/max8925_onkey.c @@ -62,7 +62,7 @@ static irqreturn_t max8925_onkey_handler(int irq, void *data) return IRQ_HANDLED; } -static int __devinit max8925_onkey_probe(struct platform_device *pdev) +static int max8925_onkey_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); struct max8925_onkey_info *info; diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index 8db64f6..2613b2f 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -241,7 +241,7 @@ static void max8997_haptic_close(struct input_dev *dev) max8997_haptic_disable(chip); } -static int __devinit max8997_haptic_probe(struct platform_device *pdev) +static int max8997_haptic_probe(struct platform_device *pdev) { struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); const struct max8997_platform_data *pdata = diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c index a0c35a05..a50ad91 100644 --- a/drivers/input/misc/mc13783-pwrbutton.c +++ b/drivers/input/misc/mc13783-pwrbutton.c @@ -89,7 +89,7 @@ static irqreturn_t button_irq(int irq, void *_priv) return IRQ_HANDLED; } -static int __devinit mc13783_pwrbutton_probe(struct platform_device *pdev) +static int mc13783_pwrbutton_probe(struct platform_device *pdev) { const struct mc13xxx_buttons_platform_data *pdata; struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index 050a246..d4528cc 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -167,7 +167,7 @@ static void mma8450_close(struct input_polled_dev *dev) /* * I2C init/probing/exit functions */ -static int __devinit mma8450_probe(struct i2c_client *c, +static int mma8450_probe(struct i2c_client *c, const struct i2c_device_id *id) { struct input_polled_dev *idev; diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c index ab11409..ff60056 100644 --- a/drivers/input/misc/mpu3050.c +++ b/drivers/input/misc/mpu3050.c @@ -257,7 +257,7 @@ static irqreturn_t mpu3050_interrupt_thread(int irq, void *data) * * Called during device probe; configures the sampling method. */ -static int __devinit mpu3050_hw_init(struct mpu3050_sensor *sensor) +static int mpu3050_hw_init(struct mpu3050_sensor *sensor) { struct i2c_client *client = sensor->client; int ret; @@ -306,7 +306,7 @@ static int __devinit mpu3050_hw_init(struct mpu3050_sensor *sensor) * * If present install the relevant sysfs interfaces and input device. */ -static int __devinit mpu3050_probe(struct i2c_client *client, +static int mpu3050_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct mpu3050_sensor *sensor; diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c index afd3f5a..56d03ac 100644 --- a/drivers/input/misc/pcap_keys.c +++ b/drivers/input/misc/pcap_keys.c @@ -48,7 +48,7 @@ static irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys) return IRQ_HANDLED; } -static int __devinit pcap_keys_probe(struct platform_device *pdev) +static int pcap_keys_probe(struct platform_device *pdev) { int err = -ENOMEM; struct pcap_keys *pcap_keys; diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c index 3896b0f..8efb898 100644 --- a/drivers/input/misc/pcf50633-input.c +++ b/drivers/input/misc/pcf50633-input.c @@ -53,7 +53,7 @@ pcf50633_input_irq(int irq, void *data) input_sync(input->input_dev); } -static int __devinit pcf50633_input_probe(struct platform_device *pdev) +static int pcf50633_input_probe(struct platform_device *pdev) { struct pcf50633_input *input; struct input_dev *input_dev; diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index 6c480bf..dbe2093 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -82,7 +82,7 @@ static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id) { int i, ret; struct input_dev *idev; diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 17d6555f..943b461 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -63,7 +63,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c return 0; } -static int __devinit pcspkr_probe(struct platform_device *dev) +static int pcspkr_probe(struct platform_device *dev) { struct input_dev *pcspkr_dev; int err; diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 2e0a3bf..1ac2b1f 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -178,7 +178,7 @@ static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data, return 0; } -static int __devinit pm8xxx_vib_probe(struct platform_device *pdev) +static int pm8xxx_vib_probe(struct platform_device *pdev) { struct pm8xxx_vib *vib; diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index b2396e2..26e49ac 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -81,7 +81,7 @@ static int pmic8xxx_pwrkey_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops, pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume); -static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev) +static int pmic8xxx_pwrkey_probe(struct platform_device *pdev) { struct input_dev *pwr; int key_release_irq = platform_get_irq(pdev, 0); diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index d40c2f6..48b505b 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -65,7 +65,7 @@ static int pwm_beeper_event(struct input_dev *input, return 0; } -static int __devinit pwm_beeper_probe(struct platform_device *pdev) +static int pwm_beeper_probe(struct platform_device *pdev) { unsigned long pwm_id = (unsigned long)pdev->dev.platform_data; struct pwm_beeper *beeper; diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c index 718dd83..91f71d6 100644 --- a/drivers/input/misc/rb532_button.c +++ b/drivers/input/misc/rb532_button.c @@ -51,7 +51,7 @@ static void rb532_button_poll(struct input_polled_dev *poll_dev) input_sync(poll_dev->input); } -static int __devinit rb532_button_probe(struct platform_device *pdev) +static int rb532_button_probe(struct platform_device *pdev) { struct input_polled_dev *poll_dev; int error; diff --git a/drivers/input/misc/retu-pwrbutton.c b/drivers/input/misc/retu-pwrbutton.c index 4500027..389e84e 100644 --- a/drivers/input/misc/retu-pwrbutton.c +++ b/drivers/input/misc/retu-pwrbutton.c @@ -42,7 +42,7 @@ static irqreturn_t retu_pwrbutton_irq(int irq, void *_pwr) return IRQ_HANDLED; } -static int __devinit retu_pwrbutton_probe(struct platform_device *pdev) +static int retu_pwrbutton_probe(struct platform_device *pdev) { struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent); struct input_dev *idev; diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index b183a0e..cd3c363 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -149,8 +149,7 @@ static struct of_device_id rotary_encoder_of_match[] = { }; MODULE_DEVICE_TABLE(of, rotary_encoder_of_match); -static struct rotary_encoder_platform_data * __devinit -rotary_encoder_parse_dt(struct device *dev) +static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct device *dev) { const struct of_device_id *of_id = of_match_device(rotary_encoder_of_match, dev); @@ -192,7 +191,7 @@ rotary_encoder_parse_dt(struct device *dev) } #endif -static int __devinit rotary_encoder_probe(struct platform_device *pdev) +static int rotary_encoder_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct rotary_encoder_platform_data *pdata = dev_get_platdata(dev); diff --git a/drivers/input/misc/sgi_btns.c b/drivers/input/misc/sgi_btns.c index fd731e8..22ccd3f 100644 --- a/drivers/input/misc/sgi_btns.c +++ b/drivers/input/misc/sgi_btns.c @@ -91,7 +91,7 @@ static void handle_buttons(struct input_polled_dev *dev) } } -static int __devinit sgi_buttons_probe(struct platform_device *pdev) +static int sgi_buttons_probe(struct platform_device *pdev) { struct buttons_dev *bdev; struct input_polled_dev *poll_dev; diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index b9c8702..d0239b4 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -139,7 +139,7 @@ static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned return 0; } -static int __devinit sparcspkr_probe(struct device *dev) +static int sparcspkr_probe(struct device *dev) { struct sparcspkr_state *state = dev_get_drvdata(dev); struct input_dev *input_dev; @@ -182,7 +182,7 @@ static void sparcspkr_shutdown(struct platform_device *dev) state->event(input_dev, EV_SND, SND_BELL, 0); } -static int __devinit bbc_beep_probe(struct platform_device *op) +static int bbc_beep_probe(struct platform_device *op) { struct sparcspkr_state *state; struct bbc_beep_info *info; @@ -267,7 +267,7 @@ static struct platform_driver bbc_beep_driver = { .shutdown = sparcspkr_shutdown, }; -static int __devinit grover_beep_probe(struct platform_device *op) +static int grover_beep_probe(struct platform_device *op) { struct sparcspkr_state *state; struct grover_beep_info *info; diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 29f2207..2103026 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -207,7 +207,7 @@ static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata, return false; } -static int __devinit twl4030_vibra_probe(struct platform_device *pdev) +static int twl4030_vibra_probe(struct platform_device *pdev) { struct twl4030_vibra_data *pdata = pdev->dev.platform_data; struct device_node *twl4030_core_node = pdev->dev.parent->of_node; diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index 463e963..4b650e4 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -255,7 +255,7 @@ static int twl6040_vibra_suspend(struct device *dev) static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL); -static int __devinit twl6040_vibra_probe(struct platform_device *pdev) +static int twl6040_vibra_probe(struct platform_device *pdev) { struct twl6040_vibra_data *pdata = pdev->dev.platform_data; struct device *twl6040_core_dev = pdev->dev.parent; diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 3f9ad23..46d79c5 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -170,7 +170,7 @@ static u16 bios_pop_queue(void) return regs.eax; } -static void __devinit bios_attach(void) +static void bios_attach(void) { struct regs regs; @@ -190,7 +190,7 @@ static void bios_detach(void) call_bios(®s); } -static u8 __devinit bios_get_cmos_address(void) +static u8 bios_get_cmos_address(void) { struct regs regs; @@ -202,7 +202,7 @@ static u8 __devinit bios_get_cmos_address(void) return regs.ecx; } -static u16 __devinit bios_get_default_setting(u8 subsys) +static u16 bios_get_default_setting(u8 subsys) { struct regs regs; @@ -1052,7 +1052,7 @@ static struct led_classdev wistron_wifi_led = { .brightness_set = wistron_wifi_led_set, }; -static void __devinit wistron_led_init(struct device *parent) +static void wistron_led_init(struct device *parent) { if (leds_present & FE_WIFI_LED) { u16 wifi = bios_get_default_setting(WIFI); @@ -1168,7 +1168,7 @@ static void wistron_poll(struct input_polled_dev *dev) dev->poll_interval = POLL_INTERVAL_DEFAULT; } -static int __devinit wistron_setup_keymap(struct input_dev *dev, +static int wistron_setup_keymap(struct input_dev *dev, struct key_entry *entry) { switch (entry->type) { @@ -1199,7 +1199,7 @@ static int __devinit wistron_setup_keymap(struct input_dev *dev, return 0; } -static int __devinit setup_input_dev(void) +static int setup_input_dev(void) { struct input_dev *input_dev; int error; @@ -1237,7 +1237,7 @@ static int __devinit setup_input_dev(void) /* Driver core */ -static int __devinit wistron_probe(struct platform_device *dev) +static int wistron_probe(struct platform_device *dev) { int err; diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c index 3a12951..de7751e 100644 --- a/drivers/input/misc/wm831x-on.c +++ b/drivers/input/misc/wm831x-on.c @@ -69,7 +69,7 @@ static irqreturn_t wm831x_on_irq(int irq, void *data) return IRQ_HANDLED; } -static int __devinit wm831x_on_probe(struct platform_device *pdev) +static int wm831x_on_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_on *wm831x_on; diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 6f7d990..e21c181 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -104,7 +104,7 @@ static irqreturn_t input_handler(int rq, void *dev_id) return IRQ_HANDLED; } -static int __devinit xenkbd_probe(struct xenbus_device *dev, +static int xenkbd_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { int ret, i, abs; diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c index b3a8aa9..8e1fe82 100644 --- a/drivers/input/mouse/gpio_mouse.c +++ b/drivers/input/mouse/gpio_mouse.c @@ -46,7 +46,7 @@ static void gpio_mouse_scan(struct input_polled_dev *dev) input_sync(input); } -static int __devinit gpio_mouse_probe(struct platform_device *pdev) +static int gpio_mouse_probe(struct platform_device *pdev) { struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data; struct input_polled_dev *input_poll; diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c index 03ccf02..3541f36 100644 --- a/drivers/input/mouse/maplemouse.c +++ b/drivers/input/mouse/maplemouse.c @@ -64,7 +64,7 @@ static void dc_mouse_close(struct input_dev *dev) } /* allow the mouse to be used */ -static int __devinit probe_maple_mouse(struct device *dev) +static int probe_maple_mouse(struct device *dev) { struct maple_device *mdev = to_maple_dev(dev); struct maple_driver *mdrv = to_maple_driver(dev->driver); diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c index ac4e077..f51df6b 100644 --- a/drivers/input/mouse/navpoint.c +++ b/drivers/input/mouse/navpoint.c @@ -206,7 +206,7 @@ static void navpoint_close(struct input_dev *input) navpoint_down(navpoint); } -static int __devinit navpoint_probe(struct platform_device *pdev) +static int navpoint_probe(struct platform_device *pdev) { const struct navpoint_platform_data *pdata = dev_get_platdata(&pdev->dev); diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c index 953a048..ed808fc 100644 --- a/drivers/input/mouse/pxa930_trkball.c +++ b/drivers/input/mouse/pxa930_trkball.c @@ -143,7 +143,7 @@ static void pxa930_trkball_close(struct input_dev *dev) pxa930_trkball_disable(trkball); } -static int __devinit pxa930_trkball_probe(struct platform_device *pdev) +static int pxa930_trkball_probe(struct platform_device *pdev) { struct pxa930_trkball *trkball; struct input_dev *input; diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index fa8f162..007c378 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -535,7 +535,7 @@ static struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *clien return touch; } -static int __devinit synaptics_i2c_probe(struct i2c_client *client, +static int synaptics_i2c_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) { int ret; diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c index 50da8e5..ea46ddc 100644 --- a/drivers/input/serio/altera_ps2.c +++ b/drivers/input/serio/altera_ps2.c @@ -81,7 +81,7 @@ static void altera_ps2_close(struct serio *io) /* * Add one device to this driver. */ -static int __devinit altera_ps2_probe(struct platform_device *pdev) +static int altera_ps2_probe(struct platform_device *pdev) { struct ps2if *ps2if; struct serio *serio; diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index beb0816..7c502c3 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -107,7 +107,7 @@ static void amba_kmi_close(struct serio *io) clk_disable_unprepare(kmi->clk); } -static int __devinit amba_kmi_probe(struct amba_device *dev, +static int amba_kmi_probe(struct amba_device *dev, const struct amba_id *id) { struct amba_kmi_port *kmi; diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c index 72fda8f..e618c2a 100644 --- a/drivers/input/serio/arc_ps2.c +++ b/drivers/input/serio/arc_ps2.c @@ -123,7 +123,7 @@ static void arc_ps2_close(struct serio *io) port->status_addr); } -static void __iomem * __devinit arc_ps2_calc_addr(struct arc_ps2_data *arc_ps2, +static void __iomem *arc_ps2_calc_addr(struct arc_ps2_data *arc_ps2, int index, bool status) { void __iomem *addr; @@ -135,7 +135,7 @@ static void __iomem * __devinit arc_ps2_calc_addr(struct arc_ps2_data *arc_ps2, return addr; } -static void __devinit arc_ps2_inhibit_ports(struct arc_ps2_data *arc_ps2) +static void arc_ps2_inhibit_ports(struct arc_ps2_data *arc_ps2) { void __iomem *addr; u32 val; @@ -149,7 +149,7 @@ static void __devinit arc_ps2_inhibit_ports(struct arc_ps2_data *arc_ps2) } } -static int __devinit arc_ps2_create_port(struct platform_device *pdev, +static int arc_ps2_create_port(struct platform_device *pdev, struct arc_ps2_data *arc_ps2, int index) { @@ -180,7 +180,7 @@ static int __devinit arc_ps2_create_port(struct platform_device *pdev, return 0; } -static int __devinit arc_ps2_probe(struct platform_device *pdev) +static int arc_ps2_probe(struct platform_device *pdev) { struct arc_ps2_data *arc_ps2; struct resource *res; diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index 64bcd15..e8a8748 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -175,7 +175,7 @@ static int __init ct82c710_detect(void) return 0; } -static int __devinit ct82c710_probe(struct platform_device *dev) +static int ct82c710_probe(struct platform_device *dev) { ct82c710_port = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!ct82c710_port) diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 49cb7ca..a36a466 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -327,7 +327,7 @@ static void gscps2_close(struct serio *port) * @return: success/error report */ -static int __devinit gscps2_probe(struct parisc_device *dev) +static int gscps2_probe(struct parisc_device *dev) { struct gscps2port *ps2port; struct serio *serio; diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index 3f6c835..c117485 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -49,7 +49,7 @@ static inline void i8042_write_command(int val) #define OBP_PS2MS_NAME1 "kdmouse" #define OBP_PS2MS_NAME2 "mouse" -static int __devinit sparc_i8042_probe(struct platform_device *op) +static int sparc_i8042_probe(struct platform_device *op) { struct device_node *dp = op->dev.of_node; diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index 2226277..057240e 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -116,7 +116,7 @@ static void maceps2_close(struct serio *dev) } -static struct serio * __devinit maceps2_allocate_port(int idx) +static struct serio *maceps2_allocate_port(int idx) { struct serio *serio; @@ -135,7 +135,7 @@ static struct serio * __devinit maceps2_allocate_port(int idx) return serio; } -static int __devinit maceps2_probe(struct platform_device *dev) +static int maceps2_probe(struct platform_device *dev) { maceps2_port[0] = maceps2_allocate_port(0); maceps2_port[1] = maceps2_allocate_port(1); diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 9809373..1914290 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -127,7 +127,7 @@ static void pcips2_close(struct serio *io) free_irq(ps2if->dev->irq, ps2if); } -static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) +static int pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct pcips2_data *ps2if; struct serio *serio; diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 5304880..3c58f6b 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -122,7 +122,7 @@ static void q40kbd_close(struct serio *port) q40kbd_flush(q40kbd); } -static int __devinit q40kbd_probe(struct platform_device *pdev) +static int q40kbd_probe(struct platform_device *pdev) { struct q40kbd *q40kbd; struct serio *port; diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index a5100d4..d64f053 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -114,7 +114,7 @@ static void rpckbd_close(struct serio *port) * Allocate and initialize serio structure for subsequent registration * with serio core. */ -static int __devinit rpckbd_probe(struct platform_device *dev) +static int rpckbd_probe(struct platform_device *dev) { struct rpckbd_data *rpckbd; struct serio *serio; diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 4aacf4f..4458ec3 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -193,7 +193,7 @@ static void ps2_close(struct serio *io) /* * Clear the input buffer. */ -static void __devinit ps2_clear_input(struct ps2if *ps2if) +static void ps2_clear_input(struct ps2if *ps2if) { int maxread = 100; @@ -203,7 +203,7 @@ static void __devinit ps2_clear_input(struct ps2if *ps2if) } } -static unsigned int __devinit ps2_test_one(struct ps2if *ps2if, +static unsigned int ps2_test_one(struct ps2if *ps2if, unsigned int mask) { unsigned int val; @@ -220,7 +220,7 @@ static unsigned int __devinit ps2_test_one(struct ps2if *ps2if, * Test the keyboard interface. We basically check to make sure that * we can drive each line to the keyboard independently of each other. */ -static int __devinit ps2_test(struct ps2if *ps2if) +static int ps2_test(struct ps2if *ps2if) { unsigned int stat; int ret = 0; @@ -251,7 +251,7 @@ static int __devinit ps2_test(struct ps2if *ps2if) /* * Add one device to this driver. */ -static int __devinit ps2_probe(struct sa1111_dev *dev) +static int ps2_probe(struct sa1111_dev *dev) { struct ps2if *ps2if; struct serio *serio; diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index f929d8f..ed5e8e6 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -233,7 +233,7 @@ static void sxps2_close(struct serio *pserio) * It returns 0, if the driver is bound to the PS/2 device, or a negative * value if there is an error. */ -static int __devinit xps2_of_probe(struct platform_device *ofdev) +static int xps2_of_probe(struct platform_device *ofdev) { struct resource r_irq; /* Interrupt resources */ struct resource r_mem; /* IO mem resources */ diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index e609db8..183d35b 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -115,7 +115,7 @@ static void pm860x_touch_close(struct input_dev *dev) } #ifdef CONFIG_OF -static int __devinit pm860x_touch_dt_init(struct platform_device *pdev, +static int pm860x_touch_dt_init(struct platform_device *pdev, struct pm860x_chip *chip, int *res_x) { @@ -169,7 +169,7 @@ static int __devinit pm860x_touch_dt_init(struct platform_device *pdev, #define pm860x_touch_dt_init(x, y, z) (-1) #endif -static int __devinit pm860x_touch_probe(struct platform_device *pdev) +static int pm860x_touch_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_touch_pdata *pdata = pdev->dev.platform_data; diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index d2df6a4..61c0a98 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -682,7 +682,7 @@ static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts) } } -static int __devinit ad7877_probe(struct spi_device *spi) +static int ad7877_probe(struct spi_device *spi) { struct ad7877 *ts; struct input_dev *input_dev; diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index 850c95d..b155770 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -54,7 +54,7 @@ static const struct ad7879_bus_ops ad7879_i2c_bus_ops = { .write = ad7879_i2c_write, }; -static int __devinit ad7879_i2c_probe(struct i2c_client *client, +static int ad7879_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ad7879 *ts; diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index 86b0fdb..c9b73e0 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -110,7 +110,7 @@ static const struct ad7879_bus_ops ad7879_spi_bus_ops = { .write = ad7879_spi_write, }; -static int __devinit ad7879_spi_probe(struct spi_device *spi) +static int ad7879_spi_probe(struct spi_device *spi) { struct ad7879 *ts; int err; diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 560484d..156a36b 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -955,7 +955,7 @@ static int ads7846_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume); -static int __devinit ads7846_setup_pendown(struct spi_device *spi, +static int ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts) { struct ads7846_platform_data *pdata = spi->dev.platform_data; @@ -997,7 +997,7 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, * Set up the transfers to read touchscreen state; this assumes we * use formula #2 for pressure, not #3. */ -static void __devinit ads7846_setup_spi_msg(struct ads7846 *ts, +static void ads7846_setup_spi_msg(struct ads7846 *ts, const struct ads7846_platform_data *pdata) { struct spi_message *m = &ts->msg[0]; @@ -1196,7 +1196,7 @@ static void __devinit ads7846_setup_spi_msg(struct ads7846 *ts, spi_message_add_tail(x, m); } -static int __devinit ads7846_probe(struct spi_device *spi) +static int ads7846_probe(struct spi_device *spi) { struct ads7846 *ts; struct ads7846_packet *packet; diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 6199303..cd961bc 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1095,7 +1095,7 @@ static void mxt_input_close(struct input_dev *dev) mxt_stop(data); } -static int __devinit mxt_probe(struct i2c_client *client, +static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct mxt_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 53712b9..4b4f5ab 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -177,7 +177,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) * The functions for inserting/removing us as a module. */ -static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) +static int atmel_tsadcc_probe(struct platform_device *pdev) { struct atmel_tsadcc *ts_dev; struct input_dev *input_dev; diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 912926d..cdd233f 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -286,7 +286,7 @@ static int auo_pixcir_power_mode(struct auo_pixcir_ts *ts, int mode) return 0; } -static __devinit int auo_pixcir_int_config(struct auo_pixcir_ts *ts, +static int auo_pixcir_int_config(struct auo_pixcir_ts *ts, int int_setting) { struct i2c_client *client = ts->client; @@ -482,7 +482,7 @@ unlock: static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, auo_pixcir_suspend, auo_pixcir_resume); -static int __devinit auo_pixcir_probe(struct i2c_client *client, +static int auo_pixcir_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data; diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index c2be1fe..bf90391 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -429,7 +429,7 @@ static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data) * This function used to initializes the i2c-client touchscreen * driver and returns integer. */ -static int __devinit bu21013_probe(struct i2c_client *client, +static int bu21013_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bu21013_ts_data *bu21013_data; diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 9a2044f..0aaa24e 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -175,7 +175,7 @@ static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit cy8ctmg110_probe(struct i2c_client *client, +static int cy8ctmg110_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct cy8ctmg110_pdata *pdata = client->dev.platform_data; diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 1a7aca9..167e983 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -81,7 +81,7 @@ static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = { .read = cyttsp_i2c_read_block_data, }; -static int __devinit cyttsp_i2c_probe(struct i2c_client *client, +static int cyttsp_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct cyttsp *ts; diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c index 915af4c..8ea29d9 100644 --- a/drivers/input/touchscreen/cyttsp_spi.c +++ b/drivers/input/touchscreen/cyttsp_spi.c @@ -147,7 +147,7 @@ static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = { .read = cyttsp_spi_read_block_data, }; -static int __devinit cyttsp_spi_probe(struct spi_device *spi) +static int cyttsp_spi_probe(struct spi_device *spi) { struct cyttsp *ts; int error; diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c index ec156a6..53a9524 100644 --- a/drivers/input/touchscreen/da9034-ts.c +++ b/drivers/input/touchscreen/da9034-ts.c @@ -297,7 +297,7 @@ static void da9034_touch_close(struct input_dev *dev) } -static int __devinit da9034_touch_probe(struct platform_device *pdev) +static int da9034_touch_probe(struct platform_device *pdev) { struct da9034_touch_pdata *pdata = pdev->dev.platform_data; struct da9034_touch *touch; diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index 5dfb39b..8a493b9 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c @@ -143,7 +143,7 @@ static void da9052_ts_pen_work(struct work_struct *work) } } -static int __devinit da9052_ts_configure_gpio(struct da9052 *da9052) +static int da9052_ts_configure_gpio(struct da9052 *da9052) { int error; @@ -162,7 +162,7 @@ static int __devinit da9052_ts_configure_gpio(struct da9052 *da9052) return 0; } -static int __devinit da9052_configure_tsi(struct da9052_tsi *tsi) +static int da9052_configure_tsi(struct da9052_tsi *tsi) { int error; @@ -229,7 +229,7 @@ static void da9052_ts_input_close(struct input_dev *input_dev) da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0); } -static int __devinit da9052_ts_probe(struct platform_device *pdev) +static int da9052_ts_probe(struct platform_device *pdev) { struct da9052 *da9052; struct da9052_tsi *tsi; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 65ed9d9..677e788 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -575,7 +575,7 @@ static const struct file_operations debugfs_raw_data_fops = { .read = edt_ft5x06_debugfs_raw_data_read, }; -static void __devinit +static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, const char *debugfs_name) { @@ -617,7 +617,7 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) -static int __devinit edt_ft5x06_ts_reset(struct i2c_client *client, +static int edt_ft5x06_ts_reset(struct i2c_client *client, int reset_pin) { int error; @@ -641,7 +641,7 @@ static int __devinit edt_ft5x06_ts_reset(struct i2c_client *client, return 0; } -static int __devinit edt_ft5x06_ts_identify(struct i2c_client *client, +static int edt_ft5x06_ts_identify(struct i2c_client *client, char *model_name, char *fw_version) { @@ -675,7 +675,7 @@ static int __devinit edt_ft5x06_ts_identify(struct i2c_client *client, pdata->name <= edt_ft5x06_attr_##name.limit_high) \ edt_ft5x06_register_write(tsdata, reg, pdata->name) -static void __devinit +static void edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, const struct edt_ft5x06_platform_data *pdata) { @@ -689,7 +689,7 @@ edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE); } -static void __devinit +static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) { tsdata->threshold = edt_ft5x06_register_read(tsdata, @@ -702,7 +702,7 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y); } -static int __devinit edt_ft5x06_ts_probe(struct i2c_client *client, +static int edt_ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct edt_ft5x06_platform_data *pdata = diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index a2d9a65..a657099 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -154,7 +154,7 @@ static void eeti_ts_close(struct input_dev *dev) eeti_ts_stop(priv); } -static int __devinit eeti_ts_probe(struct i2c_client *client, +static int eeti_ts_probe(struct i2c_client *client, const struct i2c_device_id *idp) { struct eeti_ts_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index d85078d..f5e09ca 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -153,7 +153,7 @@ static int egalax_wake_up_device(struct i2c_client *client) return 0; } -static int __devinit egalax_firmware_version(struct i2c_client *client) +static int egalax_firmware_version(struct i2c_client *client) { static const u8 cmd[MAX_I2C_DATA_LEN] = { 0x03, 0x03, 0xa, 0x01, 0x41 }; int ret; @@ -165,7 +165,7 @@ static int __devinit egalax_firmware_version(struct i2c_client *client) return 0; } -static int __devinit egalax_ts_probe(struct i2c_client *client, +static int egalax_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct egalax_ts *ts; diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c index 5cc3240..32a451c 100644 --- a/drivers/input/touchscreen/htcpen.c +++ b/drivers/input/touchscreen/htcpen.c @@ -102,7 +102,7 @@ static void htcpen_close(struct input_dev *dev) synchronize_irq(HTCPEN_IRQ); } -static int __devinit htcpen_isa_probe(struct device *dev, unsigned int id) +static int htcpen_isa_probe(struct device *dev, unsigned int id) { struct input_dev *htcpen_dev; int err = -EBUSY; diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index e8fd6c2..7e6221c 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -180,7 +180,7 @@ static const struct attribute_group ili210x_attr_group = { .attrs = ili210x_attributes, }; -static int __devinit ili210x_i2c_probe(struct i2c_client *client, +static int ili210x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c index f27364f..e413f33 100644 --- a/drivers/input/touchscreen/intel-mid-touch.c +++ b/drivers/input/touchscreen/intel-mid-touch.c @@ -427,7 +427,7 @@ out: } /* Utility to read PMIC ID */ -static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev) +static int mrstouch_read_pmic_id(uint *vendor, uint *rev) { int err; u8 r; @@ -446,7 +446,7 @@ static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev) * Parse ADC channels to find end of the channel configured by other ADC user * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels */ -static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev) +static int mrstouch_chan_parse(struct mrstouch_dev *tsdev) { int found = 0; int err, i; @@ -478,7 +478,7 @@ static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev) /* * Writes touch screen channels to ADC address selection registers */ -static int __devinit mrstouch_ts_chan_set(uint offset) +static int mrstouch_ts_chan_set(uint offset) { u16 chan; @@ -494,7 +494,7 @@ static int __devinit mrstouch_ts_chan_set(uint offset) } /* Initialize ADC */ -static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev) +static int mrstouch_adc_init(struct mrstouch_dev *tsdev) { int err, start; u8 ra, rm; @@ -568,7 +568,7 @@ static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev) /* Probe function for touch screen driver */ -static int __devinit mrstouch_probe(struct platform_device *pdev) +static int mrstouch_probe(struct platform_device *pdev) { struct mrstouch_dev *tsdev; struct input_dev *input; diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index ad35c8c..7ef90def 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -99,7 +99,7 @@ static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit jornada720_ts_probe(struct platform_device *pdev) +static int jornada720_ts_probe(struct platform_device *pdev) { struct jornada_ts *jornada_ts; struct input_dev *input_dev; diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index 8134f61..39d50b7 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -203,7 +203,7 @@ static void lpc32xx_ts_close(struct input_dev *dev) lpc32xx_stop_tsc(tsc); } -static int __devinit lpc32xx_ts_probe(struct platform_device *pdev) +static int lpc32xx_ts_probe(struct platform_device *pdev) { struct lpc32xx_tsc *tsc; struct input_dev *input; diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index e3e637f..ac06db6 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -156,7 +156,7 @@ out: return IRQ_HANDLED; } -static void __devinit max11801_ts_phy_init(struct max11801_data *data) +static void max11801_ts_phy_init(struct max11801_data *data) { struct i2c_client *client = data->client; @@ -174,7 +174,7 @@ static void __devinit max11801_ts_phy_init(struct max11801_data *data) max11801_write_reg(client, OP_MODE_CONF_REG, 0x36); } -static int __devinit max11801_ts_probe(struct i2c_client *client, +static int max11801_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max11801_data *data; diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index 94a4ff6..c9da87b 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -187,7 +187,7 @@ static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data) OP_MODE_ACTIVE | REPORT_RATE_80); } -static int __devinit mcs5000_ts_probe(struct i2c_client *client, +static int mcs5000_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct mcs5000_ts_data *data; diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 0334898..633737e 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -362,7 +362,7 @@ static void mms114_input_close(struct input_dev *dev) } #ifdef CONFIG_OF -static struct mms114_platform_data * __devinit mms114_parse_dt(struct device *dev) +static struct mms114_platform_data *mms114_parse_dt(struct device *dev) { struct mms114_platform_data *pdata; struct device_node *np = dev->of_node; @@ -405,7 +405,7 @@ static inline struct mms114_platform_data *mms114_parse_dt(struct device *dev) } #endif -static int __devinit mms114_probe(struct i2c_client *client, +static int mms114_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct mms114_platform_data *pdata; diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c index 97f07ba..900dc78 100644 --- a/drivers/input/touchscreen/pcap_ts.c +++ b/drivers/input/touchscreen/pcap_ts.c @@ -137,7 +137,7 @@ static void pcap_ts_close(struct input_dev *dev) pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); } -static int __devinit pcap_ts_probe(struct platform_device *pdev) +static int pcap_ts_probe(struct platform_device *pdev) { struct input_dev *input_dev; struct pcap_ts *pcap_ts; diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 4fcb63e..cffea4c 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -125,7 +125,7 @@ static int pixcir_i2c_ts_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume); -static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client, +static int pixcir_i2c_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct pixcir_ts_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index 4dda765..8f2f22b 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -238,7 +238,7 @@ static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select) * Initialise, find and allocate any resources we need to run and then * register with the ADC and input systems. */ -static int __devinit s3c2410ts_probe(struct platform_device *pdev) +static int s3c2410ts_probe(struct platform_device *pdev) { struct s3c2410_ts_mach_info *info; struct device *dev = &pdev->dev; diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 5fa0ca3..2a71dfd 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -139,7 +139,7 @@ end: return IRQ_HANDLED; } -static int __devinit st1232_ts_probe(struct i2c_client *client, +static int st1232_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct st1232_ts_data *ts; diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index f489754..011b686 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -168,7 +168,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data) return IRQ_HANDLED; } -static int __devinit stmpe_init_hw(struct stmpe_touch *ts) +static int stmpe_init_hw(struct stmpe_touch *ts) { int ret; u8 adc_ctrl1, adc_ctrl1_mask, tsc_cfg, tsc_cfg_mask; @@ -308,7 +308,7 @@ static void stmpe_ts_get_platform_info(struct platform_device *pdev, } } -static int __devinit stmpe_input_probe(struct platform_device *pdev) +static int stmpe_input_probe(struct platform_device *pdev) { struct stmpe_touch *ts; struct input_dev *idev; diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c index d229c74..bcedf2e 100644 --- a/drivers/input/touchscreen/ti_tscadc.c +++ b/drivers/input/touchscreen/ti_tscadc.c @@ -303,7 +303,7 @@ static irqreturn_t tscadc_irq(int irq, void *dev) * The functions for inserting/removing driver as a module. */ -static int __devinit tscadc_probe(struct platform_device *pdev) +static int tscadc_probe(struct platform_device *pdev) { const struct tsc_data *pdata = pdev->dev.platform_data; struct resource *res; diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c index 62d57e8..63f75eb 100644 --- a/drivers/input/touchscreen/tnetv107x-ts.c +++ b/drivers/input/touchscreen/tnetv107x-ts.c @@ -243,7 +243,7 @@ static void tsc_stop(struct input_dev *dev) clk_disable(ts->clk); } -static int __devinit tsc_probe(struct platform_device *pdev) +static int tsc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct tsc_data *ts; diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index db472a8..2088930 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -555,7 +555,7 @@ static void tsc2005_close(struct input_dev *input) mutex_unlock(&ts->mutex); } -static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) +static void tsc2005_setup_spi_xfer(struct tsc2005 *ts) { tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, false); tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, false); @@ -569,7 +569,7 @@ static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg); } -static int __devinit tsc2005_probe(struct spi_device *spi) +static int tsc2005_probe(struct spi_device *spi) { const struct tsc2005_platform_data *pdata = spi->dev.platform_data; struct tsc2005 *ts; diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 3b19583..47b41eb 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -273,7 +273,7 @@ static void tsc2007_close(struct input_dev *input_dev) tsc2007_stop(ts); } -static int __devinit tsc2007_probe(struct i2c_client *client, +static int tsc2007_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tsc2007 *ts; diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 780eda6..518363d 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -274,7 +274,7 @@ static void ucb1400_ts_close(struct input_dev *idev) * Try to probe our interrupt, rather than relying on lots of * hard-coded machine dependencies. */ -static int __devinit ucb1400_ts_detect_irq(struct ucb1400_ts *ucb, +static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb, struct platform_device *pdev) { unsigned long mask, timeout; @@ -318,7 +318,7 @@ static int __devinit ucb1400_ts_detect_irq(struct ucb1400_ts *ucb, return 0; } -static int __devinit ucb1400_ts_probe(struct platform_device *pdev) +static int ucb1400_ts_probe(struct platform_device *pdev) { struct ucb1400_ts *ucb = pdev->dev.platform_data; int error, x_res, y_res; diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index 039e4ea..f0378a9 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -215,7 +215,7 @@ static void w90p910_close(struct input_dev *dev) clk_disable(w90p910_ts->clk); } -static int __devinit w90x900ts_probe(struct platform_device *pdev) +static int w90x900ts_probe(struct platform_device *pdev) { struct w90p910_ts *w90p910_ts; struct input_dev *input_dev; diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index 0c033df..bb02ccd 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -144,7 +144,7 @@ static void wacom_i2c_close(struct input_dev *dev) disable_irq(client->irq); } -static int __devinit wacom_i2c_probe(struct i2c_client *client, +static int wacom_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct wacom_i2c *wac_i2c; diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 17f14b6..28d8125 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -233,7 +233,7 @@ static void wm831x_ts_input_close(struct input_dev *idev) } } -static __devinit int wm831x_ts_probe(struct platform_device *pdev) +static int wm831x_ts_probe(struct platform_device *pdev) { struct wm831x_ts *wm831x_ts; struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); -- cgit v0.10.2 From e2619cf78e19476bfd7ceaefa9eff0847529346e Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Fri, 23 Nov 2012 21:50:47 -0800 Subject: Input: remove use of __devexit CONFIG_HOTPLUG is going away as an option so __devexit is no longer needed. Signed-off-by: Bill Pemberton Acked-by: Mark Brown Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index 786fa31..fa7a95c 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -107,7 +107,7 @@ static int emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return error; } -static void __devexit emu_remove(struct pci_dev *pdev) +static void emu_remove(struct pci_dev *pdev) { struct emu *emu = pci_get_drvdata(pdev); diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index b1705e1..ae912d3 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -129,7 +129,7 @@ static int fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id) return error; } -static void __devexit fm801_gp_remove(struct pci_dev *pci) +static void fm801_gp_remove(struct pci_dev *pci) { struct fm801_gp *gp = pci_get_drvdata(pci); diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index ad76733..121cd63 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -341,7 +341,7 @@ err_free_mem: return error; } -static int __devexit as5011_remove(struct i2c_client *client) +static int as5011_remove(struct i2c_client *client) { struct as5011_device *as5011 = i2c_get_clientdata(client); diff --git a/drivers/input/joystick/maplecontrol.c b/drivers/input/joystick/maplecontrol.c index 5ff3cb4..59c10ec 100644 --- a/drivers/input/joystick/maplecontrol.c +++ b/drivers/input/joystick/maplecontrol.c @@ -157,7 +157,7 @@ fail: return error; } -static int __devexit remove_maple_controller(struct device *dev) +static int remove_maple_controller(struct device *dev) { struct maple_device *mdev = to_maple_dev(dev); struct dc_pad *pad = maple_get_drvdata(mdev); diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c index 64de965..ef26b17 100644 --- a/drivers/input/keyboard/adp5520-keys.c +++ b/drivers/input/keyboard/adp5520-keys.c @@ -182,7 +182,7 @@ err: return ret; } -static int __devexit adp5520_keys_remove(struct platform_device *pdev) +static int adp5520_keys_remove(struct platform_device *pdev) { struct adp5520_keys *dev = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index a20fe70..dbd2047 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -224,7 +224,7 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) return 0; } -static void __devexit adp5588_gpio_remove(struct adp5588_kpad *kpad) +static void adp5588_gpio_remove(struct adp5588_kpad *kpad) { struct device *dev = &kpad->client->dev; const struct adp5588_kpad_platform_data *pdata = dev->platform_data; @@ -587,7 +587,7 @@ static int adp5588_probe(struct i2c_client *client, return error; } -static int __devexit adp5588_remove(struct i2c_client *client) +static int adp5588_remove(struct i2c_client *client) { struct adp5588_kpad *kpad = i2c_get_clientdata(client); diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 8f591da..67d12b3 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -550,7 +550,7 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad) return 0; } -static void __devexit adp5589_gpio_remove(struct adp5589_kpad *kpad) +static void adp5589_gpio_remove(struct adp5589_kpad *kpad) { struct device *dev = &kpad->client->dev; const struct adp5589_kpad_platform_data *pdata = dev->platform_data; @@ -1044,7 +1044,7 @@ err_free_mem: return error; } -static int __devexit adp5589_remove(struct i2c_client *client) +static int adp5589_remove(struct i2c_client *client) { struct adp5589_kpad *kpad = i2c_get_clientdata(client); diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index 8f3c2b6..20b9fa9 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c @@ -331,7 +331,7 @@ out: return error; } -static int __devexit bfin_kpad_remove(struct platform_device *pdev) +static int bfin_kpad_remove(struct platform_device *pdev) { struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data; struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c index 8e4b438..4e4e453 100644 --- a/drivers/input/keyboard/davinci_keyscan.c +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -303,7 +303,7 @@ fail1: return error; } -static int __devexit davinci_ks_remove(struct platform_device *pdev) +static int davinci_ks_remove(struct platform_device *pdev) { struct davinci_ks *davinci_ks = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 30c0008..9857e8f 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -346,7 +346,7 @@ failed_free: return err; } -static int __devexit ep93xx_keypad_remove(struct platform_device *pdev) +static int ep93xx_keypad_remove(struct platform_device *pdev) { struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); struct resource *res; diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index c714c58..1a5cb6f 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -760,7 +760,7 @@ static int gpio_keys_probe(struct platform_device *pdev) return error; } -static int __devexit gpio_keys_remove(struct platform_device *pdev) +static int gpio_keys_remove(struct platform_device *pdev) { struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); struct input_dev *input = ddata->input; diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 8c09ce2..32e5087 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -328,7 +328,7 @@ err_free_pdata: return error; } -static int __devexit gpio_keys_polled_remove(struct platform_device *pdev) +static int gpio_keys_polled_remove(struct platform_device *pdev) { struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev); const struct gpio_keys_platform_data *pdata = bdev->pdata; diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index a5da05a..198dc07 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -286,7 +286,7 @@ err1: return err; } -static void __devexit hil_keyb_exit(void) +static void hil_keyb_exit(void) { if (HIL_IRQ) free_irq(HIL_IRQ, hil_dev.dev_id); @@ -320,7 +320,7 @@ static int hil_probe_chip(struct parisc_device *dev) return hil_keyb_init(); } -static int __devexit hil_remove_chip(struct parisc_device *dev) +static int hil_remove_chip(struct parisc_device *dev) { hil_keyb_exit(); diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index d4d9542..7ad7451 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -554,7 +554,7 @@ failed_rel_mem: return error; } -static int __devexit imx_keypad_remove(struct platform_device *pdev) +static int imx_keypad_remove(struct platform_device *pdev) { struct imx_keypad *keypad = platform_get_drvdata(pdev); struct resource *res; diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c index eac650c..74e75a6 100644 --- a/drivers/input/keyboard/jornada680_kbd.c +++ b/drivers/input/keyboard/jornada680_kbd.c @@ -240,7 +240,7 @@ static int jornada680kbd_probe(struct platform_device *pdev) } -static int __devexit jornada680kbd_remove(struct platform_device *pdev) +static int jornada680kbd_remove(struct platform_device *pdev) { struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 2f08a03..5ceef63 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -152,7 +152,7 @@ static int jornada720_kbd_probe(struct platform_device *pdev) return err; }; -static int __devexit jornada720_kbd_remove(struct platform_device *pdev) +static int jornada720_kbd_remove(struct platform_device *pdev) { struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index ee0116b..93c8126 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -764,7 +764,7 @@ fail1: return err; } -static int __devexit lm8323_remove(struct i2c_client *client) +static int lm8323_remove(struct i2c_client *client) { struct lm8323_chip *lm = i2c_get_clientdata(client); int i; diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c index 9fc0372..5a8ca35 100644 --- a/drivers/input/keyboard/lm8333.c +++ b/drivers/input/keyboard/lm8333.c @@ -202,7 +202,7 @@ static int lm8333_probe(struct i2c_client *client, return err; } -static int __devexit lm8333_remove(struct i2c_client *client) +static int lm8333_remove(struct i2c_client *client) { struct lm8333 *lm8333 = i2c_get_clientdata(client); diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index e289246..c94d610 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -321,7 +321,7 @@ static int locomokbd_probe(struct locomo_dev *dev) return err; } -static int __devexit locomokbd_remove(struct locomo_dev *dev) +static int locomokbd_remove(struct locomo_dev *dev) { struct locomokbd *locomokbd = locomo_get_drvdata(dev); diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 72f8a0b..1b8add6 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -310,7 +310,7 @@ err_free_mem: return error; } -static int __devexit lpc32xx_kscan_remove(struct platform_device *pdev) +static int lpc32xx_kscan_remove(struct platform_device *pdev) { struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index b9d67c2..f4ff0dd 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -539,7 +539,7 @@ err_free_mem: return err; } -static int __devexit matrix_keypad_remove(struct platform_device *pdev) +static int matrix_keypad_remove(struct platform_device *pdev) { struct matrix_keypad *keypad = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index 98b8ff1..7c7af2b 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -260,7 +260,7 @@ failed_free_mem: return error; } -static int __devexit max7359_remove(struct i2c_client *client) +static int max7359_remove(struct i2c_client *client) { struct max7359_keypad *keypad = i2c_get_clientdata(client); diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index e729774..7c236f9 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -200,7 +200,7 @@ err_free_mem: return error; } -static int __devexit mcs_touchkey_remove(struct i2c_client *client) +static int mcs_touchkey_remove(struct i2c_client *client) { struct mcs_touchkey_data *data = i2c_get_clientdata(client); diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 854486c..f7f3e9a 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -272,7 +272,7 @@ err_free_mem: return error; } -static int __devexit mpr_touchkey_remove(struct i2c_client *client) +static int mpr_touchkey_remove(struct i2c_client *client) { struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client); diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 2304a81..0e6a815 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -366,7 +366,7 @@ err_free_mem: return error; } -static int __devexit ske_keypad_remove(struct platform_device *pdev) +static int ske_keypad_remove(struct platform_device *pdev) { struct ske_keypad *keypad = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index ffb8c6c..d0d5226 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -357,7 +357,7 @@ err2: return -EINVAL; } -static int __devexit omap_kp_remove(struct platform_device *pdev) +static int omap_kp_remove(struct platform_device *pdev) { struct omap_kp *omap_kp = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index c16a322..e25b022 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -406,7 +406,7 @@ err_free_keypad: return error; } -static int __devexit omap4_keypad_remove(struct platform_device *pdev) +static int omap4_keypad_remove(struct platform_device *pdev) { struct omap4_keypad *keypad_data = platform_get_drvdata(pdev); struct resource *res; diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c index ddc1c39..7ac5f17 100644 --- a/drivers/input/keyboard/opencores-kbd.c +++ b/drivers/input/keyboard/opencores-kbd.c @@ -139,7 +139,7 @@ static int opencores_kbd_probe(struct platform_device *pdev) return error; } -static int __devexit opencores_kbd_remove(struct platform_device *pdev) +static int opencores_kbd_remove(struct platform_device *pdev) { struct opencores_kbd *opencores_kbd = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index fa177ab..74339e1 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -712,7 +712,7 @@ err_alloc_device: return rc; } -static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev) +static int pmic8xxx_kp_remove(struct platform_device *pdev) { struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 91778fe..5330d8f 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -595,7 +595,7 @@ failed_free: return error; } -static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) +static int pxa27x_keypad_remove(struct platform_device *pdev) { struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); struct resource *res; diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c index 60797c2..bcad95b 100644 --- a/drivers/input/keyboard/pxa930_rotary.c +++ b/drivers/input/keyboard/pxa930_rotary.c @@ -174,7 +174,7 @@ failed_free: return err; } -static int __devexit pxa930_rotary_remove(struct platform_device *pdev) +static int pxa930_rotary_remove(struct platform_device *pdev) { struct pxa930_rotary *r = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index f9358e7..42b773b 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -230,7 +230,7 @@ err_free_mem: return err; } -static int __devexit qt1070_remove(struct i2c_client *client) +static int qt1070_remove(struct i2c_client *client) { struct qt1070_data *data = i2c_get_clientdata(client); diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 69a6a6f..3dc2b0f 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -335,7 +335,7 @@ err_free_mem: return error; } -static int __devexit qt2160_remove(struct i2c_client *client) +static int qt2160_remove(struct i2c_client *client) { struct qt2160_data *qt2160 = i2c_get_clientdata(client); diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 5c6a808..acc1619 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -523,7 +523,7 @@ err_free_mem: return error; } -static int __devexit samsung_keypad_remove(struct platform_device *pdev) +static int samsung_keypad_remove(struct platform_device *pdev) { struct samsung_keypad *keypad = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index ffa9adb..fdb9eb2 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -272,7 +272,7 @@ static int sh_keysc_probe(struct platform_device *pdev) return error; } -static int __devexit sh_keysc_remove(struct platform_device *pdev) +static int sh_keysc_remove(struct platform_device *pdev) { struct sh_keysc_priv *priv = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index 3c503da..d70093b 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -279,7 +279,7 @@ static int spear_kbd_probe(struct platform_device *pdev) return 0; } -static int __devexit spear_kbd_remove(struct platform_device *pdev) +static int spear_kbd_remove(struct platform_device *pdev) { device_init_wakeup(&pdev->dev, 0); platform_set_drvdata(pdev, NULL); diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index b3f917d..7bac052 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -335,7 +335,7 @@ static int stmpe_keypad_probe(struct platform_device *pdev) return 0; } -static int __devexit stmpe_keypad_remove(struct platform_device *pdev) +static int stmpe_keypad_remove(struct platform_device *pdev) { struct stmpe_keypad *keypad = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 6d725d6..2fb0d76 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -382,7 +382,7 @@ err_free_mem: return error; } -static int __devexit tc3589x_keypad_remove(struct platform_device *pdev) +static int tc3589x_keypad_remove(struct platform_device *pdev) { struct tc_keypad *keypad = platform_get_drvdata(pdev); int irq = platform_get_irq(pdev, 0); diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 4f44579..bfc832c 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -313,7 +313,7 @@ fail1: return error; } -static int __devexit tca6416_keypad_remove(struct i2c_client *client) +static int tca6416_keypad_remove(struct i2c_client *client) { struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 6f97096..f1e966b 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -388,7 +388,7 @@ fail1: return error; } -static int __devexit tca8418_keypad_remove(struct i2c_client *client) +static int tca8418_keypad_remove(struct i2c_client *client) { struct tca8418_keypad *keypad_data = i2c_get_clientdata(client); diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index cf8ab68..c76f968 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -838,7 +838,7 @@ err_free_pdata: return err; } -static int __devexit tegra_kbc_remove(struct platform_device *pdev) +static int tegra_kbc_remove(struct platform_device *pdev) { struct tegra_kbc *kbc = platform_get_drvdata(pdev); struct resource *res; diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c index 55cd070..ee16350 100644 --- a/drivers/input/keyboard/tnetv107x-keypad.c +++ b/drivers/input/keyboard/tnetv107x-keypad.c @@ -301,7 +301,7 @@ error_res: return error; } -static int __devexit keypad_remove(struct platform_device *pdev) +static int keypad_remove(struct platform_device *pdev) { struct keypad_data *kp = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 78dd9f27..04f84fd 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -432,7 +432,7 @@ err1: return error; } -static int __devexit twl4030_kp_remove(struct platform_device *pdev) +static int twl4030_kp_remove(struct platform_device *pdev) { struct twl4030_keypad *kp = platform_get_drvdata(pdev); diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index 7574e10..ee163be 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -234,7 +234,7 @@ failed_free: return error; } -static int __devexit w90p910_keypad_remove(struct platform_device *pdev) +static int w90p910_keypad_remove(struct platform_device *pdev) { struct w90p910_keypad *keypad = platform_get_drvdata(pdev); struct resource *res; diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c index 946edca..ee43e5b 100644 --- a/drivers/input/misc/88pm80x_onkey.c +++ b/drivers/input/misc/88pm80x_onkey.c @@ -139,7 +139,7 @@ out: return err; } -static int __devexit pm80x_onkey_remove(struct platform_device *pdev) +static int pm80x_onkey_remove(struct platform_device *pdev) { struct pm80x_onkey_info *info = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c index 81af2d7..abd8453 100644 --- a/drivers/input/misc/88pm860x_onkey.c +++ b/drivers/input/misc/88pm860x_onkey.c @@ -121,7 +121,7 @@ out: return ret; } -static int __devexit pm860x_onkey_remove(struct platform_device *pdev) +static int pm860x_onkey_remove(struct platform_device *pdev) { struct pm860x_onkey_info *info = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index f188222..2f090b4 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c @@ -118,7 +118,7 @@ err_free_mem: return error; } -static int __devexit ab8500_ponkey_remove(struct platform_device *pdev) +static int ab8500_ponkey_remove(struct platform_device *pdev) { struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index 9477602..29d2064 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -87,7 +87,7 @@ static int ad714x_i2c_probe(struct i2c_client *client, return 0; } -static int __devexit ad714x_i2c_remove(struct i2c_client *client) +static int ad714x_i2c_remove(struct i2c_client *client) { struct ad714x_chip *chip = i2c_get_clientdata(client); diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c index 497871e..bdccca4 100644 --- a/drivers/input/misc/ad714x-spi.c +++ b/drivers/input/misc/ad714x-spi.c @@ -103,7 +103,7 @@ static int ad714x_spi_probe(struct spi_device *spi) return 0; } -static int __devexit ad714x_spi_remove(struct spi_device *spi) +static int ad714x_spi_remove(struct spi_device *spi) { struct ad714x_chip *chip = spi_get_drvdata(spi); diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index e262885..535dda4 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -98,7 +98,7 @@ static int adxl34x_i2c_probe(struct i2c_client *client, return 0; } -static int __devexit adxl34x_i2c_remove(struct i2c_client *client) +static int adxl34x_i2c_remove(struct i2c_client *client) { struct adxl34x *ac = i2c_get_clientdata(client); diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c index 1071d25..ad5f40d 100644 --- a/drivers/input/misc/adxl34x-spi.c +++ b/drivers/input/misc/adxl34x-spi.c @@ -87,7 +87,7 @@ static int adxl34x_spi_probe(struct spi_device *spi) return 0; } -static int __devexit adxl34x_spi_remove(struct spi_device *spi) +static int adxl34x_spi_remove(struct spi_device *spi) { struct adxl34x *ac = dev_get_drvdata(&spi->dev); diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c index 9cb4a74..a6666e1 100644 --- a/drivers/input/misc/bfin_rotary.c +++ b/drivers/input/misc/bfin_rotary.c @@ -196,7 +196,7 @@ out1: return error; } -static int __devexit bfin_rotary_remove(struct platform_device *pdev) +static int bfin_rotary_remove(struct platform_device *pdev) { struct bfin_rot *rotary = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index a3219c2..08ffcab 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -613,7 +613,7 @@ err_free_mem: return error; } -static int __devexit bma150_remove(struct i2c_client *client) +static int bma150_remove(struct i2c_client *client) { struct bma150_data *bma150 = i2c_get_clientdata(client); diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c index ca2103e..4fdef98 100644 --- a/drivers/input/misc/cma3000_d0x_i2c.c +++ b/drivers/input/misc/cma3000_d0x_i2c.c @@ -69,7 +69,7 @@ static int cma3000_i2c_probe(struct i2c_client *client, return 0; } -static int __devexit cma3000_i2c_remove(struct i2c_client *client) +static int cma3000_i2c_remove(struct i2c_client *client) { struct cma3000_accl_data *data = i2c_get_clientdata(client); diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c index beeb53d..4f77f87 100644 --- a/drivers/input/misc/cobalt_btns.c +++ b/drivers/input/misc/cobalt_btns.c @@ -135,7 +135,7 @@ static int cobalt_buttons_probe(struct platform_device *pdev) return error; } -static int __devexit cobalt_buttons_remove(struct platform_device *pdev) +static int cobalt_buttons_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct buttons_dev *bdev = dev_get_drvdata(dev); diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c index 8464029..630c1ce 100644 --- a/drivers/input/misc/da9052_onkey.c +++ b/drivers/input/misc/da9052_onkey.c @@ -141,7 +141,7 @@ err_free_mem: return error; } -static int __devexit da9052_onkey_remove(struct platform_device *pdev) +static int da9052_onkey_remove(struct platform_device *pdev) { struct da9052_onkey *onkey = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c index cbf4989..ee6ae3a 100644 --- a/drivers/input/misc/da9055_onkey.c +++ b/drivers/input/misc/da9055_onkey.c @@ -141,7 +141,7 @@ err_free_input: return err; } -static int __devexit da9055_onkey_remove(struct platform_device *pdev) +static int da9055_onkey_remove(struct platform_device *pdev) { struct da9055_onkey *onkey = platform_get_drvdata(pdev); int irq = platform_get_irq_byname(pdev, "ONKEY"); diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index 5409ab7..a309a5c 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -239,7 +239,7 @@ fail1: return status; } -static int __devexit dm355evm_keys_remove(struct platform_device *pdev) +static int dm355evm_keys_remove(struct platform_device *pdev) { struct dm355evm_keys *keys = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c index 8ad99be..fe30bd0 100644 --- a/drivers/input/misc/gp2ap002a00f.c +++ b/drivers/input/misc/gp2ap002a00f.c @@ -205,7 +205,7 @@ err_hw_shutdown: return error; } -static int __devexit gp2a_remove(struct i2c_client *client) +static int gp2a_remove(struct i2c_client *client) { struct gp2a_data *dt = i2c_get_clientdata(client); const struct gp2a_platform_data *pdata = dt->pdata; diff --git a/drivers/input/misc/gpio_tilt_polled.c b/drivers/input/misc/gpio_tilt_polled.c index 467884b..da05cca 100644 --- a/drivers/input/misc/gpio_tilt_polled.c +++ b/drivers/input/misc/gpio_tilt_polled.c @@ -179,7 +179,7 @@ err_free_tdev: return error; } -static int __devexit gpio_tilt_polled_remove(struct platform_device *pdev) +static int gpio_tilt_polled_remove(struct platform_device *pdev) { struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev); const struct gpio_tilt_platform_data *pdata = tdev->pdata; diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index 97620d5..6ab3dec 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -132,7 +132,7 @@ static int ixp4xx_spkr_probe(struct platform_device *dev) return err; } -static int __devexit ixp4xx_spkr_remove(struct platform_device *dev) +static int ixp4xx_spkr_remove(struct platform_device *dev) { struct input_dev *input_dev = platform_get_drvdata(dev); unsigned int pin = (unsigned int) input_get_drvdata(input_dev); diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index 57f1f12..a993b67 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -466,7 +466,7 @@ static int kxtj9_setup_polled_device(struct kxtj9_data *tj9) return 0; } -static void __devexit kxtj9_teardown_polled_device(struct kxtj9_data *tj9) +static void kxtj9_teardown_polled_device(struct kxtj9_data *tj9) { input_unregister_polled_device(tj9->poll_dev); input_free_polled_device(tj9->poll_dev); @@ -594,7 +594,7 @@ err_free_mem: return err; } -static int __devexit kxtj9_remove(struct i2c_client *client) +static int kxtj9_remove(struct i2c_client *client) { struct kxtj9_data *tj9 = i2c_get_clientdata(client); diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c index ec8f59d..b40ee4b 100644 --- a/drivers/input/misc/m68kspkr.c +++ b/drivers/input/misc/m68kspkr.c @@ -80,7 +80,7 @@ static int m68kspkr_probe(struct platform_device *dev) return 0; } -static int __devexit m68kspkr_remove(struct platform_device *dev) +static int m68kspkr_remove(struct platform_device *dev) { struct input_dev *input_dev = platform_get_drvdata(dev); diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c index 57bc42c..369a39d 100644 --- a/drivers/input/misc/max8925_onkey.c +++ b/drivers/input/misc/max8925_onkey.c @@ -141,7 +141,7 @@ err_free_mem: return error; } -static int __devexit max8925_onkey_remove(struct platform_device *pdev) +static int max8925_onkey_remove(struct platform_device *pdev) { struct max8925_onkey_info *info = platform_get_drvdata(pdev); struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index 2613b2f..e973133 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -354,7 +354,7 @@ err_free_mem: return error; } -static int __devexit max8997_haptic_remove(struct platform_device *pdev) +static int max8997_haptic_remove(struct platform_device *pdev) { struct max8997_haptic *chip = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c index a50ad91..0906ca5 100644 --- a/drivers/input/misc/mc13783-pwrbutton.c +++ b/drivers/input/misc/mc13783-pwrbutton.c @@ -230,7 +230,7 @@ free_input_dev: return err; } -static int __devexit mc13783_pwrbutton_remove(struct platform_device *pdev) +static int mc13783_pwrbutton_remove(struct platform_device *pdev) { struct mc13783_pwrb *priv = platform_get_drvdata(pdev); const struct mc13xxx_buttons_platform_data *pdata; diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index d4528cc..480557f 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -212,7 +212,7 @@ err_free_mem: return err; } -static int __devexit mma8450_remove(struct i2c_client *c) +static int mma8450_remove(struct i2c_client *c) { struct mma8450 *m = i2c_get_clientdata(c); struct input_polled_dev *idev = m->idev; diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c index ff60056..dce0d95 100644 --- a/drivers/input/misc/mpu3050.c +++ b/drivers/input/misc/mpu3050.c @@ -402,7 +402,7 @@ err_free_mem: * * Our sensor is going away, clean up the resources. */ -static int __devexit mpu3050_remove(struct i2c_client *client) +static int mpu3050_remove(struct i2c_client *client) { struct mpu3050_sensor *sensor = i2c_get_clientdata(client); diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c index 56d03ac..40ac9a5 100644 --- a/drivers/input/misc/pcap_keys.c +++ b/drivers/input/misc/pcap_keys.c @@ -104,7 +104,7 @@ fail: return err; } -static int __devexit pcap_keys_remove(struct platform_device *pdev) +static int pcap_keys_remove(struct platform_device *pdev) { struct pcap_keys *pcap_keys = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c index 8efb898..73b13eb 100644 --- a/drivers/input/misc/pcf50633-input.c +++ b/drivers/input/misc/pcf50633-input.c @@ -93,7 +93,7 @@ static int pcf50633_input_probe(struct platform_device *pdev) return 0; } -static int __devexit pcf50633_input_remove(struct platform_device *pdev) +static int pcf50633_input_remove(struct platform_device *pdev) { struct pcf50633_input *input = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index dbe2093..e373929 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -156,7 +156,7 @@ static int pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_i return ret; } -static int __devexit pcf8574_kp_remove(struct i2c_client *client) +static int pcf8574_kp_remove(struct i2c_client *client) { struct kp_data *lp = i2c_get_clientdata(client); diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 943b461..199db78 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -95,7 +95,7 @@ static int pcspkr_probe(struct platform_device *dev) return 0; } -static int __devexit pcspkr_remove(struct platform_device *dev) +static int pcspkr_remove(struct platform_device *dev) { struct input_dev *pcspkr_dev = platform_get_drvdata(dev); diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 1ac2b1f..a9da65e 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -242,7 +242,7 @@ err_free_mem: return error; } -static int __devexit pm8xxx_vib_remove(struct platform_device *pdev) +static int pm8xxx_vib_remove(struct platform_device *pdev) { struct pm8xxx_vib *vib = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index 26e49ac..4b811be 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -187,7 +187,7 @@ free_pwrkey: return err; } -static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev) +static int pmic8xxx_pwrkey_remove(struct platform_device *pdev) { struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev); int key_release_irq = platform_get_irq(pdev, 0); diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index 48b505b..0808868 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -129,7 +129,7 @@ err_free: return error; } -static int __devexit pwm_beeper_remove(struct platform_device *pdev) +static int pwm_beeper_remove(struct platform_device *pdev) { struct pwm_beeper *beeper = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c index 91f71d6..fb4f8ac 100644 --- a/drivers/input/misc/rb532_button.c +++ b/drivers/input/misc/rb532_button.c @@ -81,7 +81,7 @@ static int rb532_button_probe(struct platform_device *pdev) return 0; } -static int __devexit rb532_button_remove(struct platform_device *pdev) +static int rb532_button_remove(struct platform_device *pdev) { struct input_polled_dev *poll_dev = dev_get_drvdata(&pdev->dev); diff --git a/drivers/input/misc/retu-pwrbutton.c b/drivers/input/misc/retu-pwrbutton.c index 389e84e..7ca09ba 100644 --- a/drivers/input/misc/retu-pwrbutton.c +++ b/drivers/input/misc/retu-pwrbutton.c @@ -76,7 +76,7 @@ static int retu_pwrbutton_probe(struct platform_device *pdev) return 0; } -static int __devexit retu_pwrbutton_remove(struct platform_device *pdev) +static int retu_pwrbutton_remove(struct platform_device *pdev) { return 0; } diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index cd3c363..aff47b2 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -301,7 +301,7 @@ exit_free_mem: return err; } -static int __devexit rotary_encoder_remove(struct platform_device *pdev) +static int rotary_encoder_remove(struct platform_device *pdev) { struct rotary_encoder *encoder = platform_get_drvdata(pdev); const struct rotary_encoder_platform_data *pdata = encoder->pdata; diff --git a/drivers/input/misc/sgi_btns.c b/drivers/input/misc/sgi_btns.c index 22ccd3f..ad6415c 100644 --- a/drivers/input/misc/sgi_btns.c +++ b/drivers/input/misc/sgi_btns.c @@ -143,7 +143,7 @@ static int sgi_buttons_probe(struct platform_device *pdev) return error; } -static int __devexit sgi_buttons_remove(struct platform_device *pdev) +static int sgi_buttons_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct buttons_dev *bdev = dev_get_drvdata(dev); diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index d0239b4..a53586a 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -229,7 +229,7 @@ out_err: return err; } -static int __devexit bbc_remove(struct platform_device *op) +static int bbc_remove(struct platform_device *op) { struct sparcspkr_state *state = dev_get_drvdata(&op->dev); struct input_dev *input_dev = state->input_dev; @@ -310,7 +310,7 @@ out_err: return err; } -static int __devexit grover_remove(struct platform_device *op) +static int grover_remove(struct platform_device *op) { struct sparcspkr_state *state = dev_get_drvdata(&op->dev); struct grover_beep_info *info = &state->u.grover; diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 2103026..78eb6b3 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -269,7 +269,7 @@ err_kzalloc: return ret; } -static int __devexit twl4030_vibra_remove(struct platform_device *pdev) +static int twl4030_vibra_remove(struct platform_device *pdev) { struct vibra_info *info = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index 4b650e4..71a28ee 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -418,7 +418,7 @@ err_kzalloc: return ret; } -static int __devexit twl6040_vibra_remove(struct platform_device *pdev) +static int twl6040_vibra_remove(struct platform_device *pdev) { struct vibra_info *info = platform_get_drvdata(pdev); diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 46d79c5..56536f4b9 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -1077,7 +1077,7 @@ static void wistron_led_init(struct device *parent) } } -static void __devexit wistron_led_remove(void) +static void wistron_led_remove(void) { if (leds_present & FE_MAIL_LED) led_classdev_unregister(&wistron_mail_led); @@ -1277,7 +1277,7 @@ static int wistron_probe(struct platform_device *dev) return 0; } -static int __devexit wistron_remove(struct platform_device *dev) +static int wistron_remove(struct platform_device *dev) { wistron_led_remove(); input_unregister_polled_device(wistron_idev); diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c index de7751e..558767d 100644 --- a/drivers/input/misc/wm831x-on.c +++ b/drivers/input/misc/wm831x-on.c @@ -124,7 +124,7 @@ err: return ret; } -static int __devexit wm831x_on_remove(struct platform_device *pdev) +static int wm831x_on_remove(struct platform_device *pdev) { struct wm831x_on *wm831x_on = platform_get_drvdata(pdev); int irq = platform_get_irq(pdev, 0); diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c index 8e1fe82..532eaca 100644 --- a/drivers/input/mouse/gpio_mouse.c +++ b/drivers/input/mouse/gpio_mouse.c @@ -150,7 +150,7 @@ static int gpio_mouse_probe(struct platform_device *pdev) return error; } -static int __devexit gpio_mouse_remove(struct platform_device *pdev) +static int gpio_mouse_remove(struct platform_device *pdev) { struct input_polled_dev *input = platform_get_drvdata(pdev); struct gpio_mouse_platform_data *pdata = input->private; diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c index 3541f36..0a60717 100644 --- a/drivers/input/mouse/maplemouse.c +++ b/drivers/input/mouse/maplemouse.c @@ -114,7 +114,7 @@ fail: return error; } -static int __devexit remove_maple_mouse(struct device *dev) +static int remove_maple_mouse(struct device *dev) { struct maple_device *mdev = to_maple_dev(dev); struct dc_mouse *mse = maple_get_drvdata(mdev); diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c index f51df6b..8e1b98e 100644 --- a/drivers/input/mouse/navpoint.c +++ b/drivers/input/mouse/navpoint.c @@ -299,7 +299,7 @@ err_free_gpio: return error; } -static int __devexit navpoint_remove(struct platform_device *pdev) +static int navpoint_remove(struct platform_device *pdev) { const struct navpoint_platform_data *pdata = dev_get_platdata(&pdev->dev); diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c index ed808fc..0ecb9e7 100644 --- a/drivers/input/mouse/pxa930_trkball.c +++ b/drivers/input/mouse/pxa930_trkball.c @@ -230,7 +230,7 @@ failed: return error; } -static int __devexit pxa930_trkball_remove(struct platform_device *pdev) +static int pxa930_trkball_remove(struct platform_device *pdev) { struct pxa930_trkball *trkball = platform_get_drvdata(pdev); int irq = platform_get_irq(pdev, 0); diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 007c378..ad82260 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -601,7 +601,7 @@ err_mem_free: return ret; } -static int __devexit synaptics_i2c_remove(struct i2c_client *client) +static int synaptics_i2c_remove(struct i2c_client *client) { struct synaptics_i2c *touch = i2c_get_clientdata(client); diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c index ea46ddc..479ce5f 100644 --- a/drivers/input/serio/altera_ps2.c +++ b/drivers/input/serio/altera_ps2.c @@ -159,7 +159,7 @@ static int altera_ps2_probe(struct platform_device *pdev) /* * Remove one device from this driver. */ -static int __devexit altera_ps2_remove(struct platform_device *pdev) +static int altera_ps2_remove(struct platform_device *pdev) { struct ps2if *ps2if = platform_get_drvdata(pdev); diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 7c502c3..4e2fd44 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -163,7 +163,7 @@ static int amba_kmi_probe(struct amba_device *dev, return ret; } -static int __devexit amba_kmi_remove(struct amba_device *dev) +static int amba_kmi_remove(struct amba_device *dev) { struct amba_kmi_port *kmi = amba_get_drvdata(dev); diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c index e618c2a..b571eb3 100644 --- a/drivers/input/serio/arc_ps2.c +++ b/drivers/input/serio/arc_ps2.c @@ -242,7 +242,7 @@ static int arc_ps2_probe(struct platform_device *pdev) return 0; } -static int __devexit arc_ps2_remove(struct platform_device *pdev) +static int arc_ps2_remove(struct platform_device *pdev) { struct arc_ps2_data *arc_ps2 = platform_get_drvdata(pdev); int i; diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index e8a8748..cfe549d 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -199,7 +199,7 @@ static int ct82c710_probe(struct platform_device *dev) return 0; } -static int __devexit ct82c710_remove(struct platform_device *dev) +static int ct82c710_remove(struct platform_device *dev) { serio_unregister_port(ct82c710_port); diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index a36a466..8d9ba0c 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -414,7 +414,7 @@ fail_nomem: * @return: success/error report */ -static int __devexit gscps2_remove(struct parisc_device *dev) +static int gscps2_remove(struct parisc_device *dev) { struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index c117485..d6aa4c6 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -80,7 +80,7 @@ static int sparc_i8042_probe(struct platform_device *op) return 0; } -static int __devexit sparc_i8042_remove(struct platform_device *op) +static int sparc_i8042_remove(struct platform_device *op) { of_iounmap(kbd_res, kbd_iobase, 8); diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 2539195..78e4de4 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1284,7 +1284,7 @@ static void __init i8042_register_ports(void) } } -static void __devexit i8042_unregister_ports(void) +static void i8042_unregister_ports(void) { int i; @@ -1437,7 +1437,7 @@ static int __init i8042_probe(struct platform_device *dev) return error; } -static int __devexit i8042_remove(struct platform_device *dev) +static int i8042_remove(struct platform_device *dev) { i8042_unregister_ports(); i8042_free_irqs(); diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index 057240e..bc85e1c 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -151,7 +151,7 @@ static int maceps2_probe(struct platform_device *dev) return 0; } -static int __devexit maceps2_remove(struct platform_device *dev) +static int maceps2_remove(struct platform_device *dev) { serio_unregister_port(maceps2_port[0]); serio_unregister_port(maceps2_port[1]); diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 1914290..76f8383 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -176,7 +176,7 @@ static int pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) return ret; } -static void __devexit pcips2_remove(struct pci_dev *dev) +static void pcips2_remove(struct pci_dev *dev) { struct pcips2_data *ps2if = pci_get_drvdata(dev); diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 3c58f6b..70fe542 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -168,7 +168,7 @@ err_free_mem: return error; } -static int __devexit q40kbd_remove(struct platform_device *pdev) +static int q40kbd_remove(struct platform_device *pdev) { struct q40kbd *q40kbd = platform_get_drvdata(pdev); diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index d64f053..567566a 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -153,7 +153,7 @@ static int rpckbd_probe(struct platform_device *dev) return 0; } -static int __devexit rpckbd_remove(struct platform_device *dev) +static int rpckbd_remove(struct platform_device *dev) { struct serio *serio = platform_get_drvdata(dev); struct rpckbd_data *rpckbd = serio->port_data; diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 4458ec3..b3e6889 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -334,7 +334,7 @@ static int ps2_probe(struct sa1111_dev *dev) /* * Remove one device from this driver. */ -static int __devexit ps2_remove(struct sa1111_dev *dev) +static int ps2_remove(struct sa1111_dev *dev) { struct ps2if *ps2if = sa1111_get_drvdata(dev); diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index ed5e8e6..17be859 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -333,7 +333,7 @@ failed1: * if the driver module is being unloaded. It frees any resources allocated to * the device. */ -static int __devexit xps2_of_remove(struct platform_device *of_dev) +static int xps2_of_remove(struct platform_device *of_dev) { struct xps2data *drvdata = platform_get_drvdata(of_dev); struct resource r_mem; /* IO mem resources */ diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 183d35b..c706894 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -293,7 +293,7 @@ out: return ret; } -static int __devexit pm860x_touch_remove(struct platform_device *pdev) +static int pm860x_touch_remove(struct platform_device *pdev) { struct pm860x_touch *touch = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index 61c0a98..23fa829b8 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -810,7 +810,7 @@ err_free_mem: return err; } -static int __devexit ad7877_remove(struct spi_device *spi) +static int ad7877_remove(struct spi_device *spi) { struct ad7877 *ts = dev_get_drvdata(&spi->dev); diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index b155770..dcf3907 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -75,7 +75,7 @@ static int ad7879_i2c_probe(struct i2c_client *client, return 0; } -static int __devexit ad7879_i2c_remove(struct i2c_client *client) +static int ad7879_i2c_remove(struct i2c_client *client) { struct ad7879 *ts = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index c9b73e0..606da5b 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -137,7 +137,7 @@ static int ad7879_spi_probe(struct spi_device *spi) return 0; } -static int __devexit ad7879_spi_remove(struct spi_device *spi) +static int ad7879_spi_remove(struct spi_device *spi) { struct ad7879 *ts = spi_get_drvdata(spi); diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 156a36b..4f702b3 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -1390,7 +1390,7 @@ static int ads7846_probe(struct spi_device *spi) return err; } -static int __devexit ads7846_remove(struct spi_device *spi) +static int ads7846_remove(struct spi_device *spi) { struct ads7846 *ts = dev_get_drvdata(&spi->dev); diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index cd961bc..d04f810 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1200,7 +1200,7 @@ err_free_mem: return error; } -static int __devexit mxt_remove(struct i2c_client *client) +static int mxt_remove(struct i2c_client *client) { struct mxt_data *data = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 4b4f5ab..55092d1 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -323,7 +323,7 @@ err_free_mem: return err; } -static int __devexit atmel_tsadcc_remove(struct platform_device *pdev) +static int atmel_tsadcc_remove(struct platform_device *pdev) { struct atmel_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev); struct resource *res; diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index cdd233f..c6e19a9 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -599,7 +599,7 @@ err_gpio_int: return ret; } -static int __devexit auo_pixcir_remove(struct i2c_client *client) +static int auo_pixcir_remove(struct i2c_client *client) { struct auo_pixcir_ts *ts = i2c_get_clientdata(client); const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data; diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index bf90391..59a8ce8 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -549,7 +549,7 @@ err_free_mem: * This function uses to remove the i2c-client * touchscreen driver and returns integer. */ -static int __devexit bu21013_remove(struct i2c_client *client) +static int bu21013_remove(struct i2c_client *client) { struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 0aaa24e..96e0eedc 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -323,7 +323,7 @@ static int cy8ctmg110_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume); #endif -static int __devexit cy8ctmg110_remove(struct i2c_client *client) +static int cy8ctmg110_remove(struct i2c_client *client) { struct cy8ctmg110 *ts = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 167e983..4dbdf44 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -102,7 +102,7 @@ static int cyttsp_i2c_probe(struct i2c_client *client, return 0; } -static int __devexit cyttsp_i2c_remove(struct i2c_client *client) +static int cyttsp_i2c_remove(struct i2c_client *client) { struct cyttsp *ts = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c index 8ea29d9..638e203 100644 --- a/drivers/input/touchscreen/cyttsp_spi.c +++ b/drivers/input/touchscreen/cyttsp_spi.c @@ -172,7 +172,7 @@ static int cyttsp_spi_probe(struct spi_device *spi) return 0; } -static int __devexit cyttsp_spi_remove(struct spi_device *spi) +static int cyttsp_spi_remove(struct spi_device *spi) { struct cyttsp *ts = spi_get_drvdata(spi); diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c index 53a9524..34ad841 100644 --- a/drivers/input/touchscreen/da9034-ts.c +++ b/drivers/input/touchscreen/da9034-ts.c @@ -361,7 +361,7 @@ err_free_touch: return ret; } -static int __devexit da9034_touch_remove(struct platform_device *pdev) +static int da9034_touch_remove(struct platform_device *pdev) { struct da9034_touch *touch = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index 8a493b9..303966f 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c @@ -336,7 +336,7 @@ err_free_mem: return error; } -static int __devexit da9052_ts_remove(struct platform_device *pdev) +static int da9052_ts_remove(struct platform_device *pdev) { struct da9052_tsi *tsi = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 677e788..a917015 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -592,7 +592,7 @@ edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, tsdata->debug_dir, tsdata, &debugfs_raw_data_fops); } -static void __devexit +static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) { if (tsdata->debug_dir) @@ -822,7 +822,7 @@ err_free_mem: return error; } -static int __devexit edt_ft5x06_ts_remove(struct i2c_client *client) +static int edt_ft5x06_ts_remove(struct i2c_client *client) { const struct edt_ft5x06_platform_data *pdata = dev_get_platdata(&client->dev); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index a657099..55255a9 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -248,7 +248,7 @@ err0: return err; } -static int __devexit eeti_ts_remove(struct i2c_client *client) +static int eeti_ts_remove(struct i2c_client *client) { struct eeti_ts_priv *priv = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index f5e09ca..17c9097 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -246,7 +246,7 @@ err_free_ts: return error; } -static __devexit int egalax_ts_remove(struct i2c_client *client) +static int egalax_ts_remove(struct i2c_client *client) { struct egalax_ts *ts = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c index 32a451c..6c4fb84 100644 --- a/drivers/input/touchscreen/htcpen.c +++ b/drivers/input/touchscreen/htcpen.c @@ -174,7 +174,7 @@ static int htcpen_isa_probe(struct device *dev, unsigned int id) return err; } -static int __devexit htcpen_isa_remove(struct device *dev, unsigned int id) +static int htcpen_isa_remove(struct device *dev, unsigned int id) { struct input_dev *htcpen_dev = dev_get_drvdata(dev); diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 7e6221c..1418bdd 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -298,7 +298,7 @@ err_free_mem: return error; } -static int __devexit ili210x_i2c_remove(struct i2c_client *client) +static int ili210x_i2c_remove(struct i2c_client *client) { struct ili210x *priv = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c index e413f33..465db5d 100644 --- a/drivers/input/touchscreen/intel-mid-touch.c +++ b/drivers/input/touchscreen/intel-mid-touch.c @@ -643,7 +643,7 @@ err_free_mem: return err; } -static int __devexit mrstouch_remove(struct platform_device *pdev) +static int mrstouch_remove(struct platform_device *pdev) { struct mrstouch_dev *tsdev = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c index 7ef90def..282d7c7 100644 --- a/drivers/input/touchscreen/jornada720_ts.c +++ b/drivers/input/touchscreen/jornada720_ts.c @@ -151,7 +151,7 @@ static int jornada720_ts_probe(struct platform_device *pdev) return error; } -static int __devexit jornada720_ts_remove(struct platform_device *pdev) +static int jornada720_ts_remove(struct platform_device *pdev) { struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index 39d50b7..9101ee5 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -309,7 +309,7 @@ err_free_mem: return error; } -static int __devexit lpc32xx_ts_remove(struct platform_device *pdev) +static int lpc32xx_ts_remove(struct platform_device *pdev) { struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev); struct resource *res; diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index ac06db6..00bc6ca 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -228,7 +228,7 @@ err_free_mem: return error; } -static __devexit int max11801_ts_remove(struct i2c_client *client) +static int max11801_ts_remove(struct i2c_client *client) { struct max11801_data *data = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index 5c18c5c..02103b6 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -229,7 +229,7 @@ err_free_mem: return ret; } -static int __devexit mc13783_ts_remove(struct platform_device *pdev) +static int mc13783_ts_remove(struct platform_device *pdev) { struct mc13783_ts_priv *priv = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index c9da87b..f9f4e0c 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -249,7 +249,7 @@ err_free_mem: return ret; } -static int __devexit mcs5000_ts_remove(struct i2c_client *client) +static int mcs5000_ts_remove(struct i2c_client *client) { struct mcs5000_ts_data *data = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 633737e..98841d8 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -508,7 +508,7 @@ err_free_mem: return error; } -static int __devexit mms114_remove(struct i2c_client *client) +static int mms114_remove(struct i2c_client *client) { struct mms114_data *data = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c index 900dc78..f22e04d 100644 --- a/drivers/input/touchscreen/pcap_ts.c +++ b/drivers/input/touchscreen/pcap_ts.c @@ -202,7 +202,7 @@ fail: return err; } -static int __devexit pcap_ts_remove(struct platform_device *pdev) +static int pcap_ts_remove(struct platform_device *pdev) { struct pcap_ts *pcap_ts = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index cffea4c..6cc6b36 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -189,7 +189,7 @@ err_free_mem: return error; } -static int __devexit pixcir_i2c_ts_remove(struct i2c_client *client) +static int pixcir_i2c_ts_remove(struct i2c_client *client) { struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index 8f2f22b..b061af2 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -365,7 +365,7 @@ static int s3c2410ts_probe(struct platform_device *pdev) * * Free up our state ready to be removed. */ -static int __devexit s3c2410ts_remove(struct platform_device *pdev) +static int s3c2410ts_remove(struct platform_device *pdev) { free_irq(ts.irq_tc, ts.input); del_timer_sync(&touch_timer); diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 2a71dfd..d9d05e2 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -206,7 +206,7 @@ err_free_mem: return error; } -static int __devexit st1232_ts_remove(struct i2c_client *client) +static int st1232_ts_remove(struct i2c_client *client) { struct st1232_ts_data *ts = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 011b686..84d884b 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -371,7 +371,7 @@ static int stmpe_input_probe(struct platform_device *pdev) return 0; } -static int __devexit stmpe_ts_remove(struct platform_device *pdev) +static int stmpe_ts_remove(struct platform_device *pdev) { struct stmpe_touch *ts = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c index 63f75eb..acfb876 100644 --- a/drivers/input/touchscreen/tnetv107x-ts.c +++ b/drivers/input/touchscreen/tnetv107x-ts.c @@ -357,7 +357,7 @@ error_res: return error; } -static int __devexit tsc_remove(struct platform_device *pdev) +static int tsc_remove(struct platform_device *pdev) { struct tsc_data *ts = platform_get_drvdata(pdev); diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c index e1ec9e0..820a066 100644 --- a/drivers/input/touchscreen/tps6507x-ts.c +++ b/drivers/input/touchscreen/tps6507x-ts.c @@ -345,7 +345,7 @@ err0: return error; } -static int __devexit tps6507x_ts_remove(struct platform_device *pdev) +static int tps6507x_ts_remove(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); struct tps6507x_ts *tsc = tps6507x_dev->ts; diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 2088930..9c0cdc7 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -686,7 +686,7 @@ err_free_mem: return error; } -static int __devexit tsc2005_remove(struct spi_device *spi) +static int tsc2005_remove(struct spi_device *spi) { struct tsc2005 *ts = spi_get_drvdata(spi); diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 47b41eb..0b67ba4 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -366,7 +366,7 @@ static int tsc2007_probe(struct i2c_client *client, return err; } -static int __devexit tsc2007_remove(struct i2c_client *client) +static int tsc2007_remove(struct i2c_client *client) { struct tsc2007 *ts = i2c_get_clientdata(client); struct tsc2007_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 518363d..1271f97 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -397,7 +397,7 @@ err: return error; } -static int __devexit ucb1400_ts_remove(struct platform_device *pdev) +static int ucb1400_ts_remove(struct platform_device *pdev) { struct ucb1400_ts *ucb = pdev->dev.platform_data; diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index f0378a9..d2ef8f0 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -301,7 +301,7 @@ fail1: input_free_device(input_dev); return err; } -static int __devexit w90x900ts_remove(struct platform_device *pdev) +static int w90x900ts_remove(struct platform_device *pdev) { struct w90p910_ts *w90p910_ts = platform_get_drvdata(pdev); struct resource *res; diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index bb02ccd..bf0d076 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -225,7 +225,7 @@ err_free_mem: return error; } -static int __devexit wacom_i2c_remove(struct i2c_client *client) +static int wacom_i2c_remove(struct i2c_client *client) { struct wacom_i2c *wac_i2c = i2c_get_clientdata(client); diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 28d8125..f88fab5 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -381,7 +381,7 @@ err_alloc: return error; } -static __devexit int wm831x_ts_remove(struct platform_device *pdev) +static int wm831x_ts_remove(struct platform_device *pdev) { struct wm831x_ts *wm831x_ts = platform_get_drvdata(pdev); -- cgit v0.10.2 From 6ea32387a0c7fb9ca0213fd22b47c5a1ca4c2972 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 14 Nov 2012 08:55:21 -0800 Subject: Input: stmpe-keypad - add support for Device Tree bindings This patch allows the STMPE driver to be successfully probed and initialised when Device Tree support is enabled. Besides the usual platform data changes, we also separate the process of filling in the 'in use' pin bitmap, as we have to extract the information from Device Tree in the DT boot case. Acked-by: Arnd Bergmann Acked-by: Linus Walleij Signed-off-by: Lee Jones Signed-off-by: Dmitry Torokhov diff --git a/Documentation/devicetree/bindings/input/stmpe-keypad.txt b/Documentation/devicetree/bindings/input/stmpe-keypad.txt new file mode 100644 index 0000000..1b97222 --- /dev/null +++ b/Documentation/devicetree/bindings/input/stmpe-keypad.txt @@ -0,0 +1,39 @@ +* STMPE Keypad + +Required properties: + - compatible : "st,stmpe-keypad" + - linux,keymap : See ./matrix-keymap.txt + +Optional properties: + - debounce-interval : Debouncing interval time in milliseconds + - st,scan-count : Scanning cycles elapsed before key data is updated + - st,no-autorepeat : If specified device will not autorepeat + +Example: + + stmpe_keypad { + compatible = "st,stmpe-keypad"; + + debounce-interval = <64>; + st,scan-count = <8>; + st,no-autorepeat; + + linux,keymap = <0x205006b + 0x4010074 + 0x3050072 + 0x1030004 + 0x502006a + 0x500000a + 0x5008b + 0x706001c + 0x405000b + 0x6070003 + 0x3040067 + 0x303006c + 0x60400e7 + 0x602009e + 0x4020073 + 0x5050002 + 0x4030069 + 0x3020008>; + }; diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index 7bac052..5cbec56 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -257,6 +257,51 @@ static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad) (plat->debounce_ms << 1)); } +static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad) +{ + int row, col; + + for (row = 0; row < STMPE_KEYPAD_MAX_ROWS; row++) { + for (col = 0; col < STMPE_KEYPAD_MAX_COLS; col++) { + int code = MATRIX_SCAN_CODE(row, col, + STMPE_KEYPAD_ROW_SHIFT); + if (keypad->keymap[code] != KEY_RESERVED) { + keypad->rows |= 1 << row; + keypad->cols |= 1 << col; + } + } + } +} + +#ifdef CONFIG_OF +static const struct stmpe_keypad_platform_data * +stmpe_keypad_of_probe(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct stmpe_keypad_platform_data *plat; + + if (!np) + return ERR_PTR(-ENODEV); + + plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL); + if (!plat) + return ERR_PTR(-ENOMEM); + + of_property_read_u32(np, "debounce-interval", &plat->debounce_ms); + of_property_read_u32(np, "st,scan-count", &plat->scan_count); + + plat->no_autorepeat = of_property_read_bool(np, "st,no-autorepeat"); + + return plat; +} +#else +static inline const struct stmpe_keypad_platform_data * +stmpe_keypad_of_probe(struct device *dev) +{ + return ERR_PTR(-EINVAL); +} +#endif + static int stmpe_keypad_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); @@ -265,11 +310,13 @@ static int stmpe_keypad_probe(struct platform_device *pdev) struct input_dev *input; int error; int irq; - int i; plat = stmpe->pdata->keypad; - if (!plat) - return -ENODEV; + if (!plat) { + plat = stmpe_keypad_of_probe(&pdev->dev); + if (IS_ERR(plat)) + return PTR_ERR(plat); + } irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -299,12 +346,7 @@ static int stmpe_keypad_probe(struct platform_device *pdev) if (!plat->no_autorepeat) __set_bit(EV_REP, input->evbit); - for (i = 0; i < plat->keymap_data->keymap_size; i++) { - unsigned int key = plat->keymap_data->keymap[i]; - - keypad->cols |= 1 << KEY_COL(key); - keypad->rows |= 1 << KEY_ROW(key); - } + stmpe_keypad_fill_used_pins(keypad); keypad->stmpe = stmpe; keypad->plat = plat; diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 55c7b95..bf1ba93 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -324,6 +324,7 @@ static struct resource stmpe_keypad_resources[] = { static struct mfd_cell stmpe_keypad_cell = { .name = "stmpe-keypad", + .of_compatible = "st,stmpe-keypad", .resources = stmpe_keypad_resources, .num_resources = ARRAY_SIZE(stmpe_keypad_resources), }; -- cgit v0.10.2 From f32198176598fffdc8dca65a1a719dd9fba7d581 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 14 Nov 2012 10:10:49 -0800 Subject: Input: twl4030-pwrbutton - switch to using TWL_MODULE_PM_MASTER define To facilitate upcoming cleanup in twl stack switch from using TWL4030_MODULE_PM_MASTER define to usingTWL_MODULE_PM_MASTER. There are no functional changes. Signed-off-by: Peter Ujfalusi Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index b3dd96d..27c2bc8 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -39,8 +39,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr) int err; u8 value; - err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, - STS_HW_CONDITIONS); + err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &value, STS_HW_CONDITIONS); if (!err) { pm_wakeup_event(pwr->dev.parent, 0); input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); -- cgit v0.10.2 From cd32e6ccdda15be1bf5b1b0a52631b06bb243d9e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 23 Nov 2012 17:03:16 +0100 Subject: i2c: at91: fix compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the following warning: drivers/i2c/busses/i2c-at91.c: In function ‘at91_twi_get_driver_data’: drivers/i2c/busses/i2c-at91.c:411:3: warning: return discards ‘const’ qualifier from pointer target type [enabled by default] Signed-off-by: Ludovic Desroches Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index c02bf20..511bd75 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -413,7 +413,7 @@ static struct at91_twi_pdata * __devinit at91_twi_get_driver_data( match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node); if (!match) return NULL; - return match->data; + return (struct at91_twi_pdata *)match->data; } return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data; } -- cgit v0.10.2 From 5f433819b3ee4d8603f834e1438462c4ad58b185 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 23 Nov 2012 10:09:03 +0100 Subject: i2c: at91: change struct members indentation Replace tabs for struct members indentation by space to minimise line changes when adding new members which would require extra tabs to keep alignment. Signed-off-by: Ludovic Desroches Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 511bd75..4f7577f 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -66,24 +66,24 @@ #define AT91_TWI_THR 0x0034 /* Transmit Holding Register */ struct at91_twi_pdata { - unsigned clk_max_div; - unsigned clk_offset; - bool has_unre_flag; + unsigned clk_max_div; + unsigned clk_offset; + bool has_unre_flag; }; struct at91_twi_dev { - struct device *dev; - void __iomem *base; - struct completion cmd_complete; - struct clk *clk; - u8 *buf; - size_t buf_len; - struct i2c_msg *msg; - int irq; - unsigned transfer_status; - struct i2c_adapter adapter; - unsigned twi_cwgr_reg; - struct at91_twi_pdata *pdata; + struct device *dev; + void __iomem *base; + struct completion cmd_complete; + struct clk *clk; + u8 *buf; + size_t buf_len; + struct i2c_msg *msg; + int irq; + unsigned transfer_status; + struct i2c_adapter adapter; + unsigned twi_cwgr_reg; + struct at91_twi_pdata *pdata; }; static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg) -- cgit v0.10.2 From 60937b2cdbf948ddb84cbf5d728012519ff4b321 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 23 Nov 2012 10:09:04 +0100 Subject: i2c: at91: add dma support Add dma support for Atmel TWI which is available on sam9x5 and later. When using dma for reception, you have to read only n-2 bytes. The last two bytes are read manually. Don't doing this should cause to send the STOP command too late and then to get extra data in the receive register. Signed-off-by: Ludovic Desroches Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 4f7577f..b4575ee 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -29,9 +31,11 @@ #include #include #include +#include #define TWI_CLK_HZ 100000 /* max 400 Kbits/s */ #define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */ +#define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */ /* AT91 TWI register definitions */ #define AT91_TWI_CR 0x0000 /* Control Register */ @@ -69,6 +73,18 @@ struct at91_twi_pdata { unsigned clk_max_div; unsigned clk_offset; bool has_unre_flag; + bool has_dma_support; + struct at_dma_slave dma_slave; +}; + +struct at91_twi_dma { + struct dma_chan *chan_rx; + struct dma_chan *chan_tx; + struct scatterlist sg; + struct dma_async_tx_descriptor *data_desc; + enum dma_data_direction direction; + bool buf_mapped; + bool xfer_in_progress; }; struct at91_twi_dev { @@ -80,10 +96,13 @@ struct at91_twi_dev { size_t buf_len; struct i2c_msg *msg; int irq; + unsigned imr; unsigned transfer_status; struct i2c_adapter adapter; unsigned twi_cwgr_reg; struct at91_twi_pdata *pdata; + bool use_dma; + struct at91_twi_dma dma; }; static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg) @@ -102,6 +121,17 @@ static void at91_disable_twi_interrupts(struct at91_twi_dev *dev) AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY); } +static void at91_twi_irq_save(struct at91_twi_dev *dev) +{ + dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7; + at91_disable_twi_interrupts(dev); +} + +static void at91_twi_irq_restore(struct at91_twi_dev *dev) +{ + at91_twi_write(dev, AT91_TWI_IER, dev->imr); +} + static void at91_init_twi_bus(struct at91_twi_dev *dev) { at91_disable_twi_interrupts(dev); @@ -138,6 +168,28 @@ static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk) dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv); } +static void at91_twi_dma_cleanup(struct at91_twi_dev *dev) +{ + struct at91_twi_dma *dma = &dev->dma; + + at91_twi_irq_save(dev); + + if (dma->xfer_in_progress) { + if (dma->direction == DMA_FROM_DEVICE) + dmaengine_terminate_all(dma->chan_rx); + else + dmaengine_terminate_all(dma->chan_tx); + dma->xfer_in_progress = false; + } + if (dma->buf_mapped) { + dma_unmap_single(dev->dev, sg_dma_address(&dma->sg), + dev->buf_len, dma->direction); + dma->buf_mapped = false; + } + + at91_twi_irq_restore(dev); +} + static void at91_twi_write_next_byte(struct at91_twi_dev *dev) { if (dev->buf_len <= 0) @@ -154,6 +206,60 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev) ++dev->buf; } +static void at91_twi_write_data_dma_callback(void *data) +{ + struct at91_twi_dev *dev = (struct at91_twi_dev *)data; + + dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), + dev->buf_len, DMA_MEM_TO_DEV); + + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); +} + +static void at91_twi_write_data_dma(struct at91_twi_dev *dev) +{ + dma_addr_t dma_addr; + struct dma_async_tx_descriptor *txdesc; + struct at91_twi_dma *dma = &dev->dma; + struct dma_chan *chan_tx = dma->chan_tx; + + if (dev->buf_len <= 0) + return; + + dma->direction = DMA_TO_DEVICE; + + at91_twi_irq_save(dev); + dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len, + DMA_TO_DEVICE); + if (dma_mapping_error(dev->dev, dma_addr)) { + dev_err(dev->dev, "dma map failed\n"); + return; + } + dma->buf_mapped = true; + at91_twi_irq_restore(dev); + sg_dma_len(&dma->sg) = dev->buf_len; + sg_dma_address(&dma->sg) = dma_addr; + + txdesc = dmaengine_prep_slave_sg(chan_tx, &dma->sg, 1, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!txdesc) { + dev_err(dev->dev, "dma prep slave sg failed\n"); + goto error; + } + + txdesc->callback = at91_twi_write_data_dma_callback; + txdesc->callback_param = dev; + + dma->xfer_in_progress = true; + dmaengine_submit(txdesc); + dma_async_issue_pending(chan_tx); + + return; + +error: + at91_twi_dma_cleanup(dev); +} + static void at91_twi_read_next_byte(struct at91_twi_dev *dev) { if (dev->buf_len <= 0) @@ -179,6 +285,61 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) ++dev->buf; } +static void at91_twi_read_data_dma_callback(void *data) +{ + struct at91_twi_dev *dev = (struct at91_twi_dev *)data; + + dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), + dev->buf_len, DMA_DEV_TO_MEM); + + /* The last two bytes have to be read without using dma */ + dev->buf += dev->buf_len - 2; + dev->buf_len = 2; + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY); +} + +static void at91_twi_read_data_dma(struct at91_twi_dev *dev) +{ + dma_addr_t dma_addr; + struct dma_async_tx_descriptor *rxdesc; + struct at91_twi_dma *dma = &dev->dma; + struct dma_chan *chan_rx = dma->chan_rx; + + dma->direction = DMA_FROM_DEVICE; + + /* Keep in mind that we won't use dma to read the last two bytes */ + at91_twi_irq_save(dev); + dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len - 2, + DMA_FROM_DEVICE); + if (dma_mapping_error(dev->dev, dma_addr)) { + dev_err(dev->dev, "dma map failed\n"); + return; + } + dma->buf_mapped = true; + at91_twi_irq_restore(dev); + dma->sg.dma_address = dma_addr; + sg_dma_len(&dma->sg) = dev->buf_len - 2; + + rxdesc = dmaengine_prep_slave_sg(chan_rx, &dma->sg, 1, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!rxdesc) { + dev_err(dev->dev, "dma prep slave sg failed\n"); + goto error; + } + + rxdesc->callback = at91_twi_read_data_dma_callback; + rxdesc->callback_param = dev; + + dma->xfer_in_progress = true; + dmaengine_submit(rxdesc); + dma_async_issue_pending(dma->chan_rx); + + return; + +error: + at91_twi_dma_cleanup(dev); +} + static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) { struct at91_twi_dev *dev = dev_id; @@ -229,12 +390,36 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN)) start_flags |= AT91_TWI_STOP; at91_twi_write(dev, AT91_TWI_CR, start_flags); - at91_twi_write(dev, AT91_TWI_IER, + /* + * When using dma, the last byte has to be read manually in + * order to not send the stop command too late and then + * to receive extra data. In practice, there are some issues + * if you use the dma to read n-1 bytes because of latency. + * Reading n-2 bytes with dma and the two last ones manually + * seems to be the best solution. + */ + if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) { + at91_twi_read_data_dma(dev); + /* + * It is important to enable TXCOMP irq here because + * doing it only when transferring the last two bytes + * will mask NACK errors since TXCOMP is set when a + * NACK occurs. + */ + at91_twi_write(dev, AT91_TWI_IER, + AT91_TWI_TXCOMP); + } else + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP | AT91_TWI_RXRDY); } else { - at91_twi_write_next_byte(dev); - at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP | AT91_TWI_TXRDY); + if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) { + at91_twi_write_data_dma(dev); + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); + } else { + at91_twi_write_next_byte(dev); + at91_twi_write(dev, AT91_TWI_IER, + AT91_TWI_TXCOMP | AT91_TWI_TXRDY); + } } ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, @@ -242,23 +427,31 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) if (ret == 0) { dev_err(dev->dev, "controller timed out\n"); at91_init_twi_bus(dev); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto error; } if (dev->transfer_status & AT91_TWI_NACK) { dev_dbg(dev->dev, "received nack\n"); - return -EREMOTEIO; + ret = -EREMOTEIO; + goto error; } if (dev->transfer_status & AT91_TWI_OVRE) { dev_err(dev->dev, "overrun while reading\n"); - return -EIO; + ret = -EIO; + goto error; } if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) { dev_err(dev->dev, "underrun while writing\n"); - return -EIO; + ret = -EIO; + goto error; } dev_dbg(dev->dev, "transfer complete\n"); return 0; + +error: + at91_twi_dma_cleanup(dev); + return ret; } static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) @@ -329,36 +522,42 @@ static struct at91_twi_pdata at91rm9200_config = { .clk_max_div = 5, .clk_offset = 3, .has_unre_flag = true, + .has_dma_support = false, }; static struct at91_twi_pdata at91sam9261_config = { .clk_max_div = 5, .clk_offset = 4, .has_unre_flag = false, + .has_dma_support = false, }; static struct at91_twi_pdata at91sam9260_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_dma_support = false, }; static struct at91_twi_pdata at91sam9g20_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_dma_support = false, }; static struct at91_twi_pdata at91sam9g10_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_dma_support = false, }; static struct at91_twi_pdata at91sam9x5_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_dma_support = true, }; static const struct platform_device_id at91_twi_devtypes[] = { @@ -405,6 +604,90 @@ MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids); #define atmel_twi_dt_ids NULL #endif +static bool __devinit filter(struct dma_chan *chan, void *slave) +{ + struct at_dma_slave *sl = slave; + + if (sl->dma_dev == chan->device->dev) { + chan->private = sl; + return true; + } else { + return false; + } +} + +static int __devinit at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) +{ + int ret = 0; + struct at_dma_slave *sdata; + struct dma_slave_config slave_config; + struct at91_twi_dma *dma = &dev->dma; + + sdata = &dev->pdata->dma_slave; + + memset(&slave_config, 0, sizeof(slave_config)); + slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR; + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.src_maxburst = 1; + slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR; + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_maxburst = 1; + slave_config.device_fc = false; + + if (sdata && sdata->dma_dev) { + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma->chan_tx = dma_request_channel(mask, filter, sdata); + if (!dma->chan_tx) { + dev_err(dev->dev, "no DMA channel available for tx\n"); + ret = -EBUSY; + goto error; + } + dma->chan_rx = dma_request_channel(mask, filter, sdata); + if (!dma->chan_rx) { + dev_err(dev->dev, "no DMA channel available for rx\n"); + ret = -EBUSY; + goto error; + } + } else { + ret = -EINVAL; + goto error; + } + + slave_config.direction = DMA_MEM_TO_DEV; + if (dmaengine_slave_config(dma->chan_tx, &slave_config)) { + dev_err(dev->dev, "failed to configure tx channel\n"); + ret = -EINVAL; + goto error; + } + + slave_config.direction = DMA_DEV_TO_MEM; + if (dmaengine_slave_config(dma->chan_rx, &slave_config)) { + dev_err(dev->dev, "failed to configure rx channel\n"); + ret = -EINVAL; + goto error; + } + + sg_init_table(&dma->sg, 1); + dma->buf_mapped = false; + dma->xfer_in_progress = false; + + dev_info(dev->dev, "using %s (tx) and %s (rx) for DMA transfers\n", + dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx)); + + return ret; + +error: + dev_info(dev->dev, "can't use DMA\n"); + if (dma->chan_rx) + dma_release_channel(dma->chan_rx); + if (dma->chan_tx) + dma_release_channel(dma->chan_tx); + return ret; +} + static struct at91_twi_pdata * __devinit at91_twi_get_driver_data( struct platform_device *pdev) { @@ -423,6 +706,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) struct at91_twi_dev *dev; struct resource *mem; int rc; + u32 phy_addr; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) @@ -433,6 +717,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) return -ENODEV; + phy_addr = mem->start; dev->pdata = at91_twi_get_driver_data(pdev); if (!dev->pdata) @@ -462,6 +747,11 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) } clk_prepare_enable(dev->clk); + if (dev->pdata->has_dma_support) { + if (at91_twi_configure_dma(dev, phy_addr) == 0) + dev->use_dma = true; + } + at91_calc_twi_clock(dev, TWI_CLK_HZ); at91_init_twi_bus(dev); -- cgit v0.10.2 From 52ad48a0ce25d4d44ce82b7e28a35eb69598e5f1 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Sat, 24 Nov 2012 23:08:54 -0800 Subject: Input: HIL - do not call tasklet_disable right before tasklet_kill We do not need to call tasklet_disable() before calling tasklet_kill() if taskelt does not reschedult itself. Signed-off-by: Xiaotian Feng Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index 0280167..65605e4 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -1009,8 +1009,6 @@ static int __init hil_mlc_init(void) static void __exit hil_mlc_exit(void) { del_timer_sync(&hil_mlcs_kicker); - - tasklet_disable(&hil_mlcs_tasklet); tasklet_kill(&hil_mlcs_tasklet); } -- cgit v0.10.2 From 92aab96034c2cdf11eb61a6b14409c2da8e5158d Mon Sep 17 00:00:00 2001 From: Andreas Pretzsch Date: Sat, 24 Nov 2012 23:31:38 -0800 Subject: Input: imx_keypad - only set enabled columns to open-drain In imx_keypad_inhibit(), all 8 columns were set to open-drain, in contrast to the rest of the driver, where only the enabled columns are modified/used. Contrary to the normal expectation, this also affects column I/Os not even mapped via IOMUX to the KPP hardware module but used as a GPIO. Therefore only init enabled columns to open-drain and leave all others with their default reset value of 0, i.e. totem-pole. Signed-off-by: Andreas Pretzsch Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 7ad7451..6d150e3 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -362,7 +362,8 @@ static void imx_keypad_inhibit(struct imx_keypad *keypad) writew(reg_val, keypad->mmio_base + KPSR); /* Colums as open drain and disable all rows */ - writew(0xff00, keypad->mmio_base + KPCR); + reg_val = (keypad->cols_en_mask & 0xff) << 8; + writew(reg_val, keypad->mmio_base + KPCR); } static void imx_keypad_close(struct input_dev *dev) -- cgit v0.10.2 From e9c36b0b09f29f4edefa5bfcbc7247bb8419edce Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Tue, 20 Nov 2012 10:01:51 +0530 Subject: powerpc/85xx: p1022ds: Use NULL instead of 0 for pointers The third argument for of_get_property() is a pointer, hence pass NULL instead of 0. Signed-off-by: Tushar Behera Signed-off-by: Kumar Gala diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 8fb1257..7328b8d 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -249,7 +249,7 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) goto exit; } - iprop = of_get_property(law_node, "fsl,num-laws", 0); + iprop = of_get_property(law_node, "fsl,num-laws", NULL); if (!iprop) { pr_err("p1022ds: LAW node is missing fsl,num-laws property\n"); goto exit; -- cgit v0.10.2 From 9655aa6b8034ebb69724dc4b54ad4f64a53096d1 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 17 May 2012 14:10:27 -0500 Subject: drivers/virt: the Freescale hypervisor driver doesn't need to check MSR[GS] The MSR[GS] bit indicates whether the kernel is running in processor guest state mode, but such a check is unnecessary. The driver already checks for the /hypervisor node and the fsl,hv-version property, so it already knows that it's running under the Freescale hypervisor. There is nothing in the driver that inherently requires guest state, anyway. This fixes a break that can occur in some randconfig builds. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c index 4939e0c..d294f67 100644 --- a/drivers/virt/fsl_hypervisor.c +++ b/drivers/virt/fsl_hypervisor.c @@ -796,9 +796,6 @@ static int has_fsl_hypervisor(void) struct device_node *node; int ret; - if (!(mfmsr() & MSR_GS)) - return 0; - node = of_find_node_by_path("/hypervisor"); if (!node) return 0; -- cgit v0.10.2 From b567d1c74ecfe4c321bdba251506a95e4c837c86 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Mon, 15 Oct 2012 14:52:21 -0500 Subject: powerpc/86xx: fsl_pcibios_fixup_bus requires CONFIG_PCI Function fsl_pcibios_fixup_bus() is available only if PCI is enabled. The MPC8610 HPCD platform file was not protecting the assigned with an #ifdef, which results in a link failure when PCI is disabled. Every other platform already has this #ifdef. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index a817398..04d9d31 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -353,5 +353,7 @@ define_machine(mpc86xx_hpcd) { .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, +#ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif }; -- cgit v0.10.2 From a393d8977acd834520357f951bb28ef46ee7db0a Mon Sep 17 00:00:00 2001 From: Jia Hongtao Date: Thu, 8 Nov 2012 10:11:07 +0800 Subject: powerpc/fsl-pci: Add PCI controller ATMU PM support Power supply for PCI controller ATMU registers is off when system go to deep-sleep state. So ATMU registers should be re-setup during PCI controllers resume from sleep. Signed-off-by: Jia Hongtao Signed-off-by: Li Yang Signed-off-by: Kumar Gala diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index ffb93ae..b96885b 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -89,7 +89,7 @@ static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask) return 0; } -static int __init setup_one_atmu(struct ccsr_pci __iomem *pci, +static int setup_one_atmu(struct ccsr_pci __iomem *pci, unsigned int index, const struct resource *res, resource_size_t offset) { @@ -126,7 +126,7 @@ static int __init setup_one_atmu(struct ccsr_pci __iomem *pci, } /* atmu setup for fsl pci/pcie controller */ -static void __init setup_pci_atmu(struct pci_controller *hose, +static void setup_pci_atmu(struct pci_controller *hose, struct resource *rsrc) { struct ccsr_pci __iomem *pci; @@ -902,9 +902,42 @@ static int __devinit fsl_pci_probe(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int fsl_pci_resume(struct device *dev) +{ + struct pci_controller *hose; + struct resource pci_rsrc; + + hose = pci_find_hose_for_OF_device(dev->of_node); + if (!hose) + return -ENODEV; + + if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) { + dev_err(dev, "Get pci register base failed."); + return -ENODEV; + } + + setup_pci_atmu(hose, &pci_rsrc); + + return 0; +} + +static const struct dev_pm_ops pci_pm_ops = { + .resume = fsl_pci_resume, +}; + +#define PCI_PM_OPS (&pci_pm_ops) + +#else + +#define PCI_PM_OPS NULL + +#endif + static struct platform_driver fsl_pci_driver = { .driver = { .name = "fsl-pci", + .pm = PCI_PM_OPS, .of_match_table = pci_ids, }, .probe = fsl_pci_probe, -- cgit v0.10.2 From bc15236fbed1e017b465e38a9d2092393778a2f7 Mon Sep 17 00:00:00 2001 From: York Sun Date: Sat, 29 Sep 2012 16:44:35 -0700 Subject: powerpc/mpc85xx: Change spin table to cached memory ePAPR v1.1 requires the spin table to be in cached memory. So we need to change the call argument of ioremap to enable cache and coherence. We also flush the cache after writing to spin table to keep it compatible with previous cache-inhibit spin table. Flushing before and after accessing spin table is recommended by ePAPR. Signed-off-by: York Sun Acked-by: Timur Tabi Signed-off-by: Kumar Gala diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 6fcfa12..148c2f2 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -128,6 +128,19 @@ static void __cpuinit smp_85xx_mach_cpu_die(void) } #endif +static inline void flush_spin_table(void *spin_table) +{ + flush_dcache_range((ulong)spin_table, + (ulong)spin_table + sizeof(struct epapr_spin_table)); +} + +static inline u32 read_spin_table_addr_l(void *spin_table) +{ + flush_dcache_range((ulong)spin_table, + (ulong)spin_table + sizeof(struct epapr_spin_table)); + return in_be32(&((struct epapr_spin_table *)spin_table)->addr_l); +} + static int __cpuinit smp_85xx_kick_cpu(int nr) { unsigned long flags; @@ -161,8 +174,8 @@ static int __cpuinit smp_85xx_kick_cpu(int nr) /* Map the spin table */ if (ioremappable) - spin_table = ioremap(*cpu_rel_addr, - sizeof(struct epapr_spin_table)); + spin_table = ioremap_prot(*cpu_rel_addr, + sizeof(struct epapr_spin_table), _PAGE_COHERENT); else spin_table = phys_to_virt(*cpu_rel_addr); @@ -173,7 +186,16 @@ static int __cpuinit smp_85xx_kick_cpu(int nr) generic_set_cpu_up(nr); if (system_state == SYSTEM_RUNNING) { + /* + * To keep it compatible with old boot program which uses + * cache-inhibit spin table, we need to flush the cache + * before accessing spin table to invalidate any staled data. + * We also need to flush the cache after writing to spin + * table to push data out. + */ + flush_spin_table(spin_table); out_be32(&spin_table->addr_l, 0); + flush_spin_table(spin_table); /* * We don't set the BPTR register here since it already points @@ -181,9 +203,14 @@ static int __cpuinit smp_85xx_kick_cpu(int nr) */ mpic_reset_core(hw_cpu); - /* wait until core is ready... */ - if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1, - 10000, 100)) { + /* + * wait until core is ready... + * We need to invalidate the stale data, in case the boot + * loader uses a cache-inhibited spin table. + */ + if (!spin_event_timeout( + read_spin_table_addr_l(spin_table) == 1, + 10000, 100)) { pr_err("%s: timeout waiting for core %d to reset\n", __func__, hw_cpu); ret = -ENOENT; @@ -194,12 +221,10 @@ static int __cpuinit smp_85xx_kick_cpu(int nr) __secondary_hold_acknowledge = -1; } #endif + flush_spin_table(spin_table); out_be32(&spin_table->pir, hw_cpu); out_be32(&spin_table->addr_l, __pa(__early_start)); - - if (!ioremappable) - flush_dcache_range((ulong)spin_table, - (ulong)spin_table + sizeof(struct epapr_spin_table)); + flush_spin_table(spin_table); /* Wait a bit for the CPU to ack. */ if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu, @@ -213,13 +238,11 @@ out: #else smp_generic_kick_cpu(nr); + flush_spin_table(spin_table); out_be32(&spin_table->pir, hw_cpu); out_be64((u64 *)(&spin_table->addr_h), __pa((u64)*((unsigned long long *)generic_secondary_smp_init))); - - if (!ioremappable) - flush_dcache_range((ulong)spin_table, - (ulong)spin_table + sizeof(struct epapr_spin_table)); + flush_spin_table(spin_table); #endif local_irq_restore(flags); -- cgit v0.10.2 From 5320b50797a9a5373f31f5b1c26346357f73e179 Mon Sep 17 00:00:00 2001 From: Varun Sethi Date: Tue, 20 Nov 2012 19:24:55 +0530 Subject: powerpc/iommu/fsl: Add PAMU bypass enable register to ccsr_guts struct PAMU bypass enable register added to the ccsr_guts structure. Signed-off-by: Timur Tabi Signed-off-by: Varun Sethi Signed-off-by: Kumar Gala diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h index dd5ba2c..77ced0b 100644 --- a/arch/powerpc/include/asm/fsl_guts.h +++ b/arch/powerpc/include/asm/fsl_guts.h @@ -71,7 +71,9 @@ struct ccsr_guts { u8 res0c4[0x224 - 0xc4]; __be32 iodelay1; /* 0x.0224 - IO delay control register 1 */ __be32 iodelay2; /* 0x.0228 - IO delay control register 2 */ - u8 res22c[0x800 - 0x22c]; + u8 res22c[0x604 - 0x22c]; + __be32 pamubypenr; /* 0x.604 - PAMU bypass enable register */ + u8 res608[0x800 - 0x608]; __be32 clkdvdr; /* 0x.0800 - Clock Divide Register */ u8 res804[0x900 - 0x804]; __be32 ircr; /* 0x.0900 - Infrared Control Register */ -- cgit v0.10.2 From 1723d90915d4689fa2e8cd4151d45ea38c96cb99 Mon Sep 17 00:00:00 2001 From: Xuelin Shi Date: Wed, 21 Nov 2012 17:01:20 +0800 Subject: powerpc/dma/raidengine: add raidengine device The RaidEngine is a new Freescale hardware that used for parity computation offloading in RAID5/6. This patch adds the device node in device tree and related binding documentation. Signed-off-by: Harninder Rai Signed-off-by: Naveen Burmi Signed-off-by: Xuelin Shi Signed-off-by: Kumar Gala diff --git a/Documentation/devicetree/bindings/powerpc/fsl/raideng.txt b/Documentation/devicetree/bindings/powerpc/fsl/raideng.txt new file mode 100644 index 0000000..4ad29b9 --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/fsl/raideng.txt @@ -0,0 +1,81 @@ +* Freescale 85xx RAID Engine nodes + +RAID Engine nodes are defined to describe on-chip RAID accelerators. Each RAID +Engine should have a separate node. + +Supported chips: +P5020, P5040 + +Required properties: + +- compatible: Should contain "fsl,raideng-v1.0" as the value + This identifies RAID Engine block. 1 in 1.0 represents + major number whereas 0 represents minor number. The + version matches the hardware IP version. +- reg: offset and length of the register set for the device +- ranges: standard ranges property specifying the translation + between child address space and parent address space + +Example: + /* P5020 */ + raideng: raideng@320000 { + compatible = "fsl,raideng-v1.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x320000 0x10000>; + ranges = <0 0x320000 0x10000>; + }; + + +There must be a sub-node for each job queue present in RAID Engine +This node must be a sub-node of the main RAID Engine node + +- compatible: Should contain "fsl,raideng-v1.0-job-queue" as the value + This identifies the job queue interface +- reg: offset and length of the register set for job queue +- ranges: standard ranges property specifying the translation + between child address space and parent address space + +Example: + /* P5020 */ + raideng_jq0@1000 { + compatible = "fsl,raideng-v1.0-job-queue"; + reg = <0x1000 0x1000>; + ranges = <0x0 0x1000 0x1000>; + }; + + +There must be a sub-node for each job ring present in RAID Engine +This node must be a sub-node of job queue node + +- compatible: Must contain "fsl,raideng-v1.0-job-ring" as the value + This identifies job ring. Should contain either + "fsl,raideng-v1.0-hp-ring" or "fsl,raideng-v1.0-lp-ring" + depending upon whether ring has high or low priority +- reg: offset and length of the register set for job ring +- interrupts: interrupt mapping for job ring IRQ + +Optional property: + +- fsl,liodn: Specifies the LIODN to be used for Job Ring. This + property is normally set by firmware. Value + is of 12-bits which is the LIODN number for this JR. + This property is used by the IOMMU (PAMU) to distinquish + transactions from this JR and than be able to do address + translation & protection accordingly. + +Example: + /* P5020 */ + raideng_jq0@1000 { + compatible = "fsl,raideng-v1.0-job-queue"; + reg = <0x1000 0x1000>; + ranges = <0x0 0x1000 0x1000>; + + raideng_jr0: jr@0 { + compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-hp-ring"; + reg = <0x0 0x400>; + interrupts = <139 2 0 0>; + interrupt-parent = <&mpic>; + fsl,liodn = <0x41>; + }; + }; diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi index 64b6abe..5d7205b 100644 --- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi @@ -354,4 +354,5 @@ /include/ "qoriq-sata2-0.dtsi" /include/ "qoriq-sata2-1.dtsi" /include/ "qoriq-sec4.2-0.dtsi" +/include/ "qoriq-raid1.0-0.dtsi" }; diff --git a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi index 0a198b0..8df47fc 100644 --- a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi @@ -73,6 +73,12 @@ rtic_c = &rtic_c; rtic_d = &rtic_d; sec_mon = &sec_mon; + + raideng = &raideng; + raideng_jr0 = &raideng_jr0; + raideng_jr1 = &raideng_jr1; + raideng_jr2 = &raideng_jr2; + raideng_jr3 = &raideng_jr3; }; cpus { diff --git a/arch/powerpc/boot/dts/fsl/qoriq-raid1.0-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-raid1.0-0.dtsi new file mode 100644 index 0000000..8d2e8aa --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/qoriq-raid1.0-0.dtsi @@ -0,0 +1,85 @@ +/* + * QorIQ RAID 1.0 device tree stub [ controller @ offset 0x320000 ] + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +raideng: raideng@320000 { + compatible = "fsl,raideng-v1.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x320000 0x10000>; + ranges = <0 0x320000 0x10000>; + + raideng_jq0@1000 { + compatible = "fsl,raideng-v1.0-job-queue"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x1000 0x1000>; + ranges = <0x0 0x1000 0x1000>; + + raideng_jr0: jr@0 { + compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-hp-ring"; + reg = <0x0 0x400>; + interrupts = <139 2 0 0>; + interrupt-parent = <&mpic>; + }; + + raideng_jr1: jr@400 { + compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-lp-ring"; + reg = <0x400 0x400>; + interrupts = <140 2 0 0>; + interrupt-parent = <&mpic>; + }; + }; + + raideng_jq1@2000 { + compatible = "fsl,raideng-v1.0-job-queue"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2000 0x1000>; + ranges = <0x0 0x2000 0x1000>; + + raideng_jr2: jr@0 { + compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-hp-ring"; + reg = <0x0 0x400>; + interrupts = <141 2 0 0>; + interrupt-parent = <&mpic>; + }; + + raideng_jr3: jr@400 { + compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-lp-ring"; + reg = <0x400 0x400>; + interrupts = <142 2 0 0>; + interrupt-parent = <&mpic>; + }; + }; +}; -- cgit v0.10.2 From 4c1002100898d03c5c9142ffaf58351c841ab94a Mon Sep 17 00:00:00 2001 From: Yanchuan Nian Date: Mon, 12 Nov 2012 09:27:37 +0800 Subject: nfs: Fix wrong slab cache in nfs_commit_mempool The slab cache in nfs_commit_mempool is wrong, and I think it is just a slip. I tested it on a x86-32 machine, the size of nfs_write_header is 544, and the size of nfs_commit_data is 408, so it works fine. It is also true that sizeof(struct nfs_write_header) > sizeof(struct nfs_commit_data) on other platforms in my opinoin. Just fix it. Signed-off-by: Yanchuan Nian Signed-off-by: Trond Myklebust diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 9347ab7..f710e39 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1829,7 +1829,7 @@ int __init nfs_init_writepagecache(void) goto out_destroy_write_mempool; nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT, - nfs_wdata_cachep); + nfs_cdata_cachep); if (nfs_commit_mempool == NULL) goto out_destroy_commit_cache; -- cgit v0.10.2 From 57d276d71aef7d8305ff002a070cb98deb2edced Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 16 Nov 2012 15:22:43 -0500 Subject: nfsd: fix v4 reply caching Very embarassing: 1091006c5eb15cba56785bd5b498a8d0b9546903 "nfsd: turn on reply cache for NFSv4" missed a line, effectively leaving the reply cache off in the v4 case. I thought I'd tested that, but I guess not. This time, wrote a pynfs test to confirm it works. Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 2013aa00..30d3784 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -640,7 +640,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) } /* Store reply in cache. */ - nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1); + nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); return 1; } -- cgit v0.10.2 From 447bfcc936ce28636833e89c4b82f424a291dde9 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 16 Nov 2012 21:53:58 -0500 Subject: nfsd4: no, we're not going to check tags for utf8 Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 406d0c4..9dfad58 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1595,12 +1595,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) bool cachethis = false; int i; - /* - * XXX: According to spec, we should check the tag - * for UTF-8 compliance. I'm postponing this for - * now because it seems that some clients do use - * binary tags. - */ READ_BUF(4); READ32(argp->taglen); READ_BUF(argp->taglen + 8); -- cgit v0.10.2 From 8a61b18c9b13987310d0f3ba13aa04af51f02a1c Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 16 Nov 2012 22:28:38 -0500 Subject: nfsd4: simplify reading of opnum The comment here is totally bogus: - OP_WRITE + 1 is RELEASE_LOCKOWNER. Maybe there was some older version of the spec in which that served as a sort of OP_ILLEGAL? No idea, but it's clearly wrong now. - In any case, I can't see that the spec says anything about what to do if the client sends us less ops than promised. It's clearly nutty client behavior, and we should do whatever's easiest: returning an xdr error (even though it won't be consistent with the error on the last op returned) seems fine to me. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 9dfad58..cfebc9c 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1624,38 +1624,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) op = &argp->ops[i]; op->replay = NULL; - /* - * We can't use READ_BUF() here because we need to handle - * a missing opcode as an OP_WRITE + 1. So we need to check - * to see if we're truly at the end of our buffer or if there - * is another page we need to flip to. - */ - - if (argp->p == argp->end) { - if (argp->pagelen < 4) { - /* There isn't an opcode still on the wire */ - op->opnum = OP_WRITE + 1; - op->status = nfserr_bad_xdr; - argp->opcnt = i+1; - break; - } - - /* - * False alarm. We just hit a page boundary, but there - * is still data available. Move pointer across page - * boundary. *snip from READ_BUF* - */ - argp->p = page_address(argp->pagelist[0]); - argp->pagelist++; - if (argp->pagelen < PAGE_SIZE) { - argp->end = argp->p + (argp->pagelen>>2); - argp->pagelen = 0; - } else { - argp->end = argp->p + (PAGE_SIZE>>2); - argp->pagelen -= PAGE_SIZE; - } - } - op->opnum = ntohl(*argp->p++); + READ_BUF(4); + READ32(op->opnum); if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP) op->status = ops->decoders[op->opnum](argp, &op->u); -- cgit v0.10.2 From 5a80a54d21c96590d013378d8c5f65f879451ab4 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 16 Nov 2012 10:01:30 -0500 Subject: nfsd4: reorganize write decoding In preparation for moving some of it elsewhere. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index cfebc9c..579dc70 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1139,12 +1139,30 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify DECODE_TAIL; } +static int fill_in_write_vector(struct kvec *vec, struct kvec *head, struct page **pagelist, int buflen) +{ + int i = 1; + + vec[0].iov_base = head->iov_base; + vec[0].iov_len = min_t(int, buflen, head->iov_len); + buflen -= vec[0].iov_len; + + while (buflen) { + vec[i].iov_base = page_address(pagelist[i - 1]); + vec[i].iov_len = min_t(int, PAGE_SIZE, buflen); + buflen -= vec[i].iov_len; + i++; + } + return i; +} + static __be32 nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) { int avail; - int v; int len; + struct page **pagelist; + struct kvec head; DECODE_HEAD; status = nfsd4_decode_stateid(argp, &write->wr_stateid); @@ -1167,27 +1185,29 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) __FILE__, __LINE__); goto xdr_error; } - argp->rqstp->rq_vec[0].iov_base = p; - argp->rqstp->rq_vec[0].iov_len = avail; - v = 0; - len = write->wr_buflen; - while (len > argp->rqstp->rq_vec[v].iov_len) { - len -= argp->rqstp->rq_vec[v].iov_len; - v++; - argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]); - argp->pagelist++; - if (argp->pagelen >= PAGE_SIZE) { - argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE; - argp->pagelen -= PAGE_SIZE; - } else { - argp->rqstp->rq_vec[v].iov_len = argp->pagelen; - argp->pagelen -= len; - } + head.iov_base = p; + head.iov_len = avail; + WARN_ON(avail != (XDR_QUADLEN(avail) << 2)); + pagelist = argp->pagelist; + + len = XDR_QUADLEN(write->wr_buflen) << 2; + if (len >= avail) { + int pages; + + len -= avail; + + pages = len >> PAGE_SHIFT; + argp->pagelist += pages; + argp->pagelen -= pages * PAGE_SIZE; + len -= pages * PAGE_SIZE; + + argp->p = (__be32 *)page_address(argp->pagelist[0]); + argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); } - argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len); - argp->p = (__be32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2)); - argp->rqstp->rq_vec[v].iov_len = len; - write->wr_vlen = v+1; + argp->p += XDR_QUADLEN(len); + write->wr_vlen = fill_in_write_vector(argp->rqstp->rq_vec, + &head, pagelist, write->wr_buflen); + WARN_ON_ONCE(write->wr_vlen > ARRAY_SIZE(argp->rqstp->rq_vec)); DECODE_TAIL; } -- cgit v0.10.2 From 70cc7f75b1ee4161dfdea1012223db25712ab1a5 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 16 Nov 2012 14:16:46 -0500 Subject: nfsd4: move more write parameters into xdr argument In preparation for moving some of this elsewhere. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 579dc70..cb9f9017 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1139,16 +1139,17 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify DECODE_TAIL; } -static int fill_in_write_vector(struct kvec *vec, struct kvec *head, struct page **pagelist, int buflen) +static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) { int i = 1; + int buflen = write->wr_buflen; - vec[0].iov_base = head->iov_base; - vec[0].iov_len = min_t(int, buflen, head->iov_len); + vec[0].iov_base = write->wr_head.iov_base; + vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len); buflen -= vec[0].iov_len; while (buflen) { - vec[i].iov_base = page_address(pagelist[i - 1]); + vec[i].iov_base = page_address(write->wr_pagelist[i - 1]); vec[i].iov_len = min_t(int, PAGE_SIZE, buflen); buflen -= vec[i].iov_len; i++; @@ -1161,8 +1162,6 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) { int avail; int len; - struct page **pagelist; - struct kvec head; DECODE_HEAD; status = nfsd4_decode_stateid(argp, &write->wr_stateid); @@ -1185,10 +1184,10 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) __FILE__, __LINE__); goto xdr_error; } - head.iov_base = p; - head.iov_len = avail; + write->wr_head.iov_base = p; + write->wr_head.iov_len = avail; WARN_ON(avail != (XDR_QUADLEN(avail) << 2)); - pagelist = argp->pagelist; + write->wr_pagelist = argp->pagelist; len = XDR_QUADLEN(write->wr_buflen) << 2; if (len >= avail) { @@ -1205,8 +1204,7 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); } argp->p += XDR_QUADLEN(len); - write->wr_vlen = fill_in_write_vector(argp->rqstp->rq_vec, - &head, pagelist, write->wr_buflen); + write->wr_vlen = fill_in_write_vector(argp->rqstp->rq_vec, write); WARN_ON_ONCE(write->wr_vlen > ARRAY_SIZE(argp->rqstp->rq_vec)); DECODE_TAIL; diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 3c414c1..152867b 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -386,6 +386,8 @@ struct nfsd4_write { u32 wr_stable_how; /* request */ u32 wr_buflen; /* request */ int wr_vlen; + struct kvec wr_head; + struct page ** wr_pagelist; /* request */ u32 wr_bytes_written; /* response */ u32 wr_how_written; /* response */ -- cgit v0.10.2 From ffe1137ba743cdf1c2414d5a89690aec1daa6bba Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 15 Nov 2012 14:52:19 -0500 Subject: nfsd4: delay filling in write iovec array till after xdr decoding Our server rejects compounds containing more than one write operation. It's unclear whether this is really permitted by the spec; with 4.0, it's possibly OK, with 4.1 (which has clearer limits on compound parameters), it's probably not OK. No client that we're aware of has ever done this, but in theory it could be useful. The source of the limitation: we need an array of iovecs to pass to the write operation. In the worst case that array of iovecs could have hundreds of elements (the maximum rwsize divided by the page size), so it's too big to put on the stack, or in each compound op. So we instead keep a single such array in the compound argument. We fill in that array at the time we decode the xdr operation. But we decode every op in the compound before executing any of them. So once we've used that array we can't decode another write. If we instead delay filling in that array till the time we actually perform the write, we can reuse it. Another option might be to switch to decoding compound ops one at a time. I considered doing that, but it has a number of other side effects, and I'd rather fix just this one problem for now. Signed-off-by: J. Bruce Fields diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt index 392ef63..01c2db7 100644 --- a/Documentation/filesystems/nfs/nfs41-server.txt +++ b/Documentation/filesystems/nfs/nfs41-server.txt @@ -190,7 +190,7 @@ Nonstandard compound limitations: ca_maxrequestsize request and a ca_maxresponsesize reply, so we may fail to live up to the promise we made in CREATE_SESSION fore channel negotiation. -* No more than one IO operation (read, write, readdir) allowed per - compound. +* No more than one read-like operation allowed per compound; encoding + replies that cross page boundaries (except for read data) not handled. See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues. diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 1d2396b..87d24e5 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -881,6 +881,24 @@ out: return status; } +static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) +{ + int i = 1; + int buflen = write->wr_buflen; + + vec[0].iov_base = write->wr_head.iov_base; + vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len); + buflen -= vec[0].iov_len; + + while (buflen) { + vec[i].iov_base = page_address(write->wr_pagelist[i - 1]); + vec[i].iov_len = min_t(int, PAGE_SIZE, buflen); + buflen -= vec[i].iov_len; + i++; + } + return i; +} + static __be32 nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_write *write) @@ -889,6 +907,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct file *filp = NULL; __be32 status = nfs_ok; unsigned long cnt; + int nvecs; /* no need to check permission - this will be done in nfsd_write() */ @@ -911,8 +930,11 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, write->wr_how_written = write->wr_stable_how; gen_boot_verifier(&write->wr_verifier); + nvecs = fill_in_write_vector(rqstp->rq_vec, write); + WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); + status = nfsd_write(rqstp, &cstate->current_fh, filp, - write->wr_offset, rqstp->rq_vec, write->wr_vlen, + write->wr_offset, rqstp->rq_vec, nvecs, &cnt, &write->wr_how_written); if (filp) fput(filp); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index cb9f9017..09204f5 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1139,24 +1139,6 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify DECODE_TAIL; } -static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) -{ - int i = 1; - int buflen = write->wr_buflen; - - vec[0].iov_base = write->wr_head.iov_base; - vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len); - buflen -= vec[0].iov_len; - - while (buflen) { - vec[i].iov_base = page_address(write->wr_pagelist[i - 1]); - vec[i].iov_len = min_t(int, PAGE_SIZE, buflen); - buflen -= vec[i].iov_len; - i++; - } - return i; -} - static __be32 nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) { @@ -1204,8 +1186,6 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); } argp->p += XDR_QUADLEN(len); - write->wr_vlen = fill_in_write_vector(argp->rqstp->rq_vec, write); - WARN_ON_ONCE(write->wr_vlen > ARRAY_SIZE(argp->rqstp->rq_vec)); DECODE_TAIL; } diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 152867b..331f8a3 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -385,7 +385,6 @@ struct nfsd4_write { u64 wr_offset; /* request */ u32 wr_stable_how; /* request */ u32 wr_buflen; /* request */ - int wr_vlen; struct kvec wr_head; struct page ** wr_pagelist; /* request */ -- cgit v0.10.2 From 063b0fb9fadadc0caaea6c8f31e3f6bc978a4904 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 25 Nov 2012 14:48:10 -0500 Subject: nfsd4: downgrade some fs/nfsd/nfs4state.c BUG's Linus has pointed out that indiscriminate use of BUG's can make it harder to diagnose bugs because they can bring a machine down, often before we manage to get any useful debugging information to the logs. (Consider, for example, a BUG() that fires in a workqueue, or while holding a spinlock). Most of these BUG's won't do much more than kill an nfsd thread, but it would still probably be safer to get out the warning without dying. There's still more of this to do in nfsd/. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e75872f..41d2aed 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -190,7 +190,7 @@ static struct list_head file_hashtbl[FILE_HASH_SIZE]; static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) { - BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); + WARN_ON_ONCE(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); atomic_inc(&fp->fi_access[oflag]); } @@ -249,7 +249,7 @@ static inline int get_new_stid(struct nfs4_stid *stid) * preallocations that can exist at a time, but the state lock * prevents anyone from using ours before we get here: */ - BUG_ON(error); + WARN_ON_ONCE(error); /* * It shouldn't be a problem to reuse an opaque stateid value. * I don't think it is for 4.1. But with 4.0 I worry that, for @@ -494,7 +494,8 @@ static int nfs4_access_to_omode(u32 access) case NFS4_SHARE_ACCESS_BOTH: return O_RDWR; } - BUG(); + WARN_ON_ONCE(1); + return O_RDONLY; } /* release all access and file references for a given stateid */ @@ -1605,10 +1606,9 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, switch (exid->spa_how) { case SP4_NONE: break; + default: /* checked by xdr code */ + WARN_ON_ONCE(1); case SP4_SSV: - return nfserr_serverfault; - default: - BUG(); /* checked by xdr code */ case SP4_MACH_CRED: return nfserr_serverfault; /* no excuse :-/ */ } @@ -2912,7 +2912,7 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) open->op_why_no_deleg = WND4_CANCELLED; break; case NFS4_SHARE_WANT_NO_DELEG: - BUG(); /* not supposed to get here */ + WARN_ON_ONCE(1); } } } @@ -3466,7 +3466,11 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, goto out; if (filpp) { *filpp = dp->dl_file->fi_deleg_file; - BUG_ON(!*filpp); + if (!*filpp) { + WARN_ON_ONCE(1); + status = nfserr_serverfault; + goto out; + } } break; case NFS4_OPEN_STID: @@ -3693,7 +3697,7 @@ static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_ac case NFS4_SHARE_ACCESS_BOTH: break; default: - BUG(); + WARN_ON_ONCE(1); } } @@ -3882,7 +3886,7 @@ last_byte_offset(u64 start, u64 len) { u64 end; - BUG_ON(!len); + WARN_ON_ONCE(!len); end = start + len; return end > start ? end - 1: NFS4_MAX_UINT64; } @@ -4552,7 +4556,7 @@ nfs4_release_reclaim(struct nfsd_net *nn) nfs4_remove_reclaim_record(crp, nn); } } - BUG_ON(nn->reclaim_str_hashtbl_size); + WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); } /* -- cgit v0.10.2 From 6eb583da959cf751eb951cc5ff488dd4e41f1b2f Mon Sep 17 00:00:00 2001 From: Sivaram Nair Date: Tue, 20 Nov 2012 09:29:16 +0200 Subject: ARM: tegra: select correct parent clk for pll_p For Tegra30, pll_p clk's parent is wrongly specified as clk_m instead of pll_ref in the tegra30_clk_init_table and this is resulting in a boot-time warning. This patch fixes this by correcting the clk init table. Signed-off-by: Sivaram Nair Signed-off-by: Stephen Warren diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 0b0a5f5..988549a 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -102,7 +102,7 @@ static __initdata struct tegra_clk_init_table tegra20_clk_init_table[] = { static __initdata struct tegra_clk_init_table tegra30_clk_init_table[] = { /* name parent rate enabled */ { "clk_m", NULL, 0, true }, - { "pll_p", "clk_m", 408000000, true }, + { "pll_p", "pll_ref", 408000000, true }, { "pll_p_out1", "pll_p", 9600000, true }, { NULL, NULL, 0, 0}, }; -- cgit v0.10.2 From 6e25e1b178ee3caf34f229bacfad5ae6780bcec6 Mon Sep 17 00:00:00 2001 From: Sivaram Nair Date: Wed, 21 Nov 2012 13:42:27 +0200 Subject: ARM: tegra: fix comment in dsib clk set_parent Since the clk framework has already taken necessary locks before calling into the arch clk ops code, no further locks are needed while setting the parent of dsib clk. This patch removes a comment that indicated otherwise, and yet did not take any locks. Signed-off-by: Sivaram Nair Signed-off-by: Stephen Warren diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index e9de5df..c2102a3 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c @@ -1913,9 +1913,7 @@ struct clk_ops tegra30_periph_clk_ops = { static int tegra30_dsib_clk_set_parent(struct clk_hw *hw, u8 index) { struct clk *d = clk_get_sys(NULL, "pll_d"); - /* The DSIB parent selection bit is in PLLD base - register - can not do direct r-m-w, must be - protected by PLLD lock */ + /* The DSIB parent selection bit is in PLLD base register */ tegra_clk_cfg_ex( d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, index); -- cgit v0.10.2 From f110174910896b7a7d91c0c60d19136815f68c54 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Wed, 21 Nov 2012 14:41:37 +0200 Subject: amba: tegra-ahb: Fix warning w/o PM_SLEEP Fix build warning w/o PM_SLEEP. Signed-off-by: Hiroshi Doyu Signed-off-by: Stephen Warren diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c index 0b6f0b2..ce8fdad 100644 --- a/drivers/amba/tegra-ahb.c +++ b/drivers/amba/tegra-ahb.c @@ -156,6 +156,7 @@ int tegra_ahb_enable_smmu(struct device_node *dn) EXPORT_SYMBOL(tegra_ahb_enable_smmu); #endif +#ifdef CONFIG_PM_SLEEP static int tegra_ahb_suspend(struct device *dev) { int i; @@ -175,6 +176,7 @@ static int tegra_ahb_resume(struct device *dev) gizmo_writel(ahb, ahb->ctx[i], tegra_ahb_gizmo[i]); return 0; } +#endif static UNIVERSAL_DEV_PM_OPS(tegra_ahb_pm, tegra_ahb_suspend, -- cgit v0.10.2 From e3725ec015dfbbeb896295cf2b3a995f28b0630e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 16 Nov 2012 12:25:01 -0500 Subject: NFSv4.1: Shrink struct nfs4_sequence_res by moving the session pointer Move the session pointer into the slot table, then have struct nfs4_slot point to that slot table. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 36880b9..42c5869 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -258,7 +258,8 @@ extern int nfs4_proc_get_lease_time(struct nfs_client *clp, extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync); -extern struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags); +extern struct nfs4_slot *nfs4_alloc_slots(struct nfs4_slot_table *table, + u32 max_slots, gfp_t gfp_flags); static inline bool is_ds_only_client(struct nfs_client *clp) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 14b3974..5b61c4a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -467,25 +467,28 @@ void nfs4_check_drain_bc_complete(struct nfs4_session *ses) static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) { + struct nfs4_session *session; struct nfs4_slot_table *tbl; - tbl = &res->sr_session->fc_slot_table; if (!res->sr_slot) { /* just wake up the next guy waiting since * we may have not consumed a slot after all */ dprintk("%s: No slot\n", __func__); return; } + tbl = res->sr_slot->table; + session = tbl->session; spin_lock(&tbl->slot_tbl_lock); nfs4_free_slot(tbl, res->sr_slot - tbl->slots); - nfs4_check_drain_fc_complete(res->sr_session); + nfs4_check_drain_fc_complete(session); spin_unlock(&tbl->slot_tbl_lock); res->sr_slot = NULL; } static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) { + struct nfs4_session *session; struct nfs4_slot *slot; unsigned long timestamp; struct nfs_client *clp; @@ -504,6 +507,7 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * goto out; slot = res->sr_slot; + session = slot->table->session; /* Check the SEQUENCE operation status */ switch (res->sr_status) { @@ -511,7 +515,7 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * /* Update the slot's sequence and clientid lease timer */ ++slot->seq_nr; timestamp = slot->renewal_time; - clp = res->sr_session->clp; + clp = session->clp; do_renew_lease(clp, timestamp); /* Check sequence flags */ if (res->sr_status_flags != 0) @@ -524,7 +528,7 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * */ dprintk("%s: slot=%td seq=%d: Operation in progress\n", __func__, - slot - res->sr_session->fc_slot_table.slots, + slot - session->fc_slot_table.slots, slot->seq_nr); goto out_retry; default: @@ -546,7 +550,7 @@ out_retry: static int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) { - if (res->sr_session == NULL) + if (res->sr_slot == NULL) return 1; return nfs41_sequence_done(task, res); } @@ -591,7 +595,6 @@ static void nfs41_init_sequence(struct nfs4_sequence_args *args, args->sa_cache_this = 0; if (cache_reply) args->sa_cache_this = 1; - res->sr_session = NULL; res->sr_slot = NULL; } @@ -646,7 +649,6 @@ int nfs41_setup_sequence(struct nfs4_session *session, dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); - res->sr_session = session; res->sr_slot = slot; res->sr_status_flags = 0; /* @@ -5659,9 +5661,18 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) return status; } -struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags) +struct nfs4_slot *nfs4_alloc_slots(struct nfs4_slot_table *table, + u32 max_slots, gfp_t gfp_flags) { - return kmalloc_array(max_slots, sizeof(struct nfs4_slot), gfp_flags); + struct nfs4_slot *tbl; + u32 i; + + tbl = kmalloc_array(max_slots, sizeof(*tbl), gfp_flags); + if (tbl != NULL) { + for (i = 0; i < max_slots; i++) + tbl[i].table = table; + } + return tbl; } static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, @@ -5699,7 +5710,7 @@ static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, /* Does the newly negotiated max_reqs match the existing slot table? */ if (max_reqs != tbl->max_slots) { - new = nfs4_alloc_slots(max_reqs, GFP_NOFS); + new = nfs4_alloc_slots(tbl, max_reqs, GFP_NOFS); if (!new) goto out; } @@ -5738,11 +5749,13 @@ static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) dprintk("--> %s\n", __func__); /* Fore channel */ tbl = &ses->fc_slot_table; + tbl->session = ses; status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1); if (status) /* -ENOMEM */ return status; /* Back channel */ tbl = &ses->bc_slot_table; + tbl->session = ses; status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0); if (status && tbl->slots == NULL) /* Fore and back channel share a connection so get diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 96fcbb9..9495789 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -2033,7 +2033,7 @@ static int nfs4_recall_slot(struct nfs_client *clp) return 0; nfs4_begin_drain_session(clp); fc_tbl = &clp->cl_session->fc_slot_table; - new = nfs4_alloc_slots(fc_tbl->target_max_slots, GFP_NOFS); + new = nfs4_alloc_slots(fc_tbl, fc_tbl->target_max_slots, GFP_NOFS); if (!new) return -ENOMEM; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 672d9b0..4126f05 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -5507,12 +5507,13 @@ static int decode_sequence(struct xdr_stream *xdr, struct rpc_rqst *rqstp) { #if defined(CONFIG_NFS_V4_1) + struct nfs4_session *session; struct nfs4_sessionid id; u32 dummy; int status; __be32 *p; - if (!res->sr_session) + if (res->sr_slot == NULL) return 0; status = decode_op_hdr(xdr, OP_SEQUENCE); @@ -5526,8 +5527,9 @@ static int decode_sequence(struct xdr_stream *xdr, * sequence number, the server is looney tunes. */ status = -EREMOTEIO; + session = res->sr_slot->table->session; - if (memcmp(id.data, res->sr_session->sess_id.data, + if (memcmp(id.data, session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) { dprintk("%s Invalid session id\n", __func__); goto out_err; @@ -5545,7 +5547,7 @@ static int decode_sequence(struct xdr_stream *xdr, } /* slot id */ dummy = be32_to_cpup(p++); - if (dummy != res->sr_slot - res->sr_session->fc_slot_table.slots) { + if (dummy != res->sr_slot - session->fc_slot_table.slots) { dprintk("%s Invalid slot id\n", __func__); goto out_err; } diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 97c8f91..b041287 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -209,6 +209,7 @@ struct nfs_server { /* Sessions */ #define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long)) struct nfs4_slot_table { + struct nfs4_session *session; /* Parent session */ struct nfs4_slot *slots; /* seqid per slot */ unsigned long used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */ spinlock_t slot_tbl_lock; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 9cb1c63..0fd88ab 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -187,6 +187,7 @@ struct nfs4_channel_attrs { /* nfs41 sessions slot seqid */ struct nfs4_slot { + struct nfs4_slot_table *table; unsigned long renewal_time; u32 seq_nr; }; @@ -198,7 +199,6 @@ struct nfs4_sequence_args { }; struct nfs4_sequence_res { - struct nfs4_session *sr_session; struct nfs4_slot *sr_slot; /* slot used to send request */ int sr_status; /* sequence operation status */ u32 sr_status_flags; -- cgit v0.10.2 From df2fabffbace8988f3265585ec793ff9deccdea7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 16 Nov 2012 12:45:06 -0500 Subject: NFSv4.1: Label each entry in the session slot tables with its slot number Instead of doing slot table pointer gymnastics every time we want to know which slot we're using. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5b61c4a..4311dba 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -526,9 +526,9 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * * returned NFS4ERR_DELAY as per Section 2.10.6.2 * of RFC5661. */ - dprintk("%s: slot=%td seq=%d: Operation in progress\n", + dprintk("%s: slot=%u seq=%u: Operation in progress\n", __func__, - slot - session->fc_slot_table.slots, + slot->slot_nr, slot->seq_nr); goto out_retry; default: @@ -671,9 +671,9 @@ int nfs4_setup_sequence(const struct nfs_server *server, if (session == NULL) goto out; - dprintk("--> %s clp %p session %p sr_slot %td\n", + dprintk("--> %s clp %p session %p sr_slot %d\n", __func__, session->clp, session, res->sr_slot ? - res->sr_slot - session->fc_slot_table.slots : -1); + res->sr_slot->slot_nr : -1); ret = nfs41_setup_sequence(session, args, res, task); out: @@ -5669,8 +5669,10 @@ struct nfs4_slot *nfs4_alloc_slots(struct nfs4_slot_table *table, tbl = kmalloc_array(max_slots, sizeof(*tbl), gfp_flags); if (tbl != NULL) { - for (i = 0; i < max_slots; i++) + for (i = 0; i < max_slots; i++) { tbl[i].table = table; + tbl[i].slot_nr = i; + } } return tbl; } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 4126f05..50bac70 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -5547,7 +5547,7 @@ static int decode_sequence(struct xdr_stream *xdr, } /* slot id */ dummy = be32_to_cpup(p++); - if (dummy != res->sr_slot - session->fc_slot_table.slots) { + if (dummy != res->sr_slot->slot_nr) { dprintk("%s Invalid slot id\n", __func__); goto out_err; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 0fd88ab..9c9b76c 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -189,6 +189,7 @@ struct nfs4_channel_attrs { struct nfs4_slot { struct nfs4_slot_table *table; unsigned long renewal_time; + u32 slot_nr; u32 seq_nr; }; -- cgit v0.10.2 From 2b2fa71723f955d5b4a0f4edd99cf3cd69ceafd1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 16 Nov 2012 12:58:36 -0500 Subject: NFSv4.1: Simplify struct nfs4_sequence_args too Replace the session pointer + slotid with a pointer to the allocated slot. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4311dba..6c41a34 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -591,7 +591,7 @@ out: static void nfs41_init_sequence(struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, int cache_reply) { - args->sa_session = NULL; + args->sa_slot = NULL; args->sa_cache_this = 0; if (cache_reply) args->sa_cache_this = 1; @@ -644,8 +644,8 @@ int nfs41_setup_sequence(struct nfs4_session *session, rpc_task_set_priority(task, RPC_PRIORITY_NORMAL); slot = tbl->slots + slotid; slot->renewal_time = jiffies; - args->sa_session = session; - args->sa_slotid = slotid; + + args->sa_slot = slot; dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 50bac70..27b0fec 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1833,18 +1833,16 @@ static void encode_sequence(struct xdr_stream *xdr, struct compound_hdr *hdr) { #if defined(CONFIG_NFS_V4_1) - struct nfs4_session *session = args->sa_session; + struct nfs4_session *session; struct nfs4_slot_table *tp; - struct nfs4_slot *slot; + struct nfs4_slot *slot = args->sa_slot; __be32 *p; - if (!session) + if (slot == NULL) return; - tp = &session->fc_slot_table; - - WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); - slot = tp->slots + args->sa_slotid; + tp = slot->table; + session = tp->session; encode_op_hdr(xdr, OP_SEQUENCE, decode_sequence_maxsz, hdr); @@ -1858,12 +1856,12 @@ static void encode_sequence(struct xdr_stream *xdr, ((u32 *)session->sess_id.data)[1], ((u32 *)session->sess_id.data)[2], ((u32 *)session->sess_id.data)[3], - slot->seq_nr, args->sa_slotid, + slot->seq_nr, slot->slot_nr, tp->highest_used_slotid, args->sa_cache_this); p = reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 16); p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN); *p++ = cpu_to_be32(slot->seq_nr); - *p++ = cpu_to_be32(args->sa_slotid); + *p++ = cpu_to_be32(slot->slot_nr); *p++ = cpu_to_be32(tp->highest_used_slotid); *p = cpu_to_be32(args->sa_cache_this); #endif /* CONFIG_NFS_V4_1 */ @@ -2025,8 +2023,9 @@ static void encode_free_stateid(struct xdr_stream *xdr, static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args) { #if defined(CONFIG_NFS_V4_1) - if (args->sa_session) - return args->sa_session->clp->cl_mvops->minor_version; + + if (args->sa_slot) + return args->sa_slot->table->session->clp->cl_mvops->minor_version; #endif /* CONFIG_NFS_V4_1 */ return 0; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 9c9b76c..deb31bb 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -194,8 +194,7 @@ struct nfs4_slot { }; struct nfs4_sequence_args { - struct nfs4_session *sa_session; - u32 sa_slotid; + struct nfs4_slot *sa_slot; u8 sa_cache_this; }; -- cgit v0.10.2 From 2dc03b7f00d7fcd7dbb9302c5ebbd0c2b7fa3557 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 16 Nov 2012 16:10:11 -0500 Subject: NFSv4.1: Simplify slot allocation Clean up the NFSv4.1 slot allocation by replacing nfs_find_slot() with a function nfs_alloc_slot() that returns a pointer to the nfs4_slot instead of an offset into the slot table. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6c41a34..0789ef1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -556,20 +556,18 @@ static int nfs4_sequence_done(struct rpc_task *task, } /* - * nfs4_find_slot - efficiently look for a free slot + * nfs4_alloc_slot - efficiently look for a free slot * - * nfs4_find_slot looks for an unset bit in the used_slots bitmap. + * nfs4_alloc_slot looks for an unset bit in the used_slots bitmap. * If found, we mark the slot as used, update the highest_used_slotid, * and respectively set up the sequence operation args. - * The slot number is returned if found, or NFS4_NO_SLOT otherwise. * * Note: must be called with under the slot_tbl_lock. */ -static u32 -nfs4_find_slot(struct nfs4_slot_table *tbl) +static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) { + struct nfs4_slot *ret = NULL; u32 slotid; - u32 ret_id = NFS4_NO_SLOT; dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", __func__, tbl->used_slots[0], tbl->highest_used_slotid, @@ -581,11 +579,14 @@ nfs4_find_slot(struct nfs4_slot_table *tbl) if (slotid > tbl->highest_used_slotid || tbl->highest_used_slotid == NFS4_NO_SLOT) tbl->highest_used_slotid = slotid; - ret_id = slotid; + ret = &tbl->slots[slotid]; + ret->renewal_time = jiffies; + out: dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", - __func__, tbl->used_slots[0], tbl->highest_used_slotid, ret_id); - return ret_id; + __func__, tbl->used_slots[0], tbl->highest_used_slotid, + ret ? ret->slot_nr : -1); + return ret; } static void nfs41_init_sequence(struct nfs4_sequence_args *args, @@ -605,7 +606,6 @@ int nfs41_setup_sequence(struct nfs4_session *session, { struct nfs4_slot *slot; struct nfs4_slot_table *tbl; - u32 slotid; dprintk("--> %s\n", __func__); /* slot already allocated? */ @@ -632,8 +632,8 @@ int nfs41_setup_sequence(struct nfs4_session *session, return -EAGAIN; } - slotid = nfs4_find_slot(tbl); - if (slotid == NFS4_NO_SLOT) { + slot = nfs4_alloc_slot(tbl); + if (slot == NULL) { rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); spin_unlock(&tbl->slot_tbl_lock); dprintk("<-- %s: no free slots\n", __func__); @@ -642,12 +642,11 @@ int nfs41_setup_sequence(struct nfs4_session *session, spin_unlock(&tbl->slot_tbl_lock); rpc_task_set_priority(task, RPC_PRIORITY_NORMAL); - slot = tbl->slots + slotid; - slot->renewal_time = jiffies; args->sa_slot = slot; - dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); + dprintk("<-- %s slotid=%d seqid=%d\n", __func__, + slot->slot_nr, slot->seq_nr); res->sr_slot = slot; res->sr_status_flags = 0; -- cgit v0.10.2 From f4af6e2abc8efb1695203a2b76876edf80f79960 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 14:17:32 -0500 Subject: NFSv4.1: Clean up nfs4_free_slot Change the argument to take the pointer to the slot, instead of just the slotid. We know that the new value of highest_used_slot must be less than the current value. No need to scan the whole table. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0789ef1..197ef3e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -412,16 +412,18 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp * Must be called while holding tbl->slot_tbl_lock */ static void -nfs4_free_slot(struct nfs4_slot_table *tbl, u32 slotid) +nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot) { + u32 slotid = slot->slot_nr; + /* clear used bit in bitmap */ __clear_bit(slotid, tbl->used_slots); /* update highest_used_slotid when it is freed */ if (slotid == tbl->highest_used_slotid) { - slotid = find_last_bit(tbl->used_slots, tbl->max_slots); - if (slotid < tbl->max_slots) - tbl->highest_used_slotid = slotid; + u32 new_max = find_last_bit(tbl->used_slots, slotid); + if (new_max < slotid) + tbl->highest_used_slotid = new_max; else tbl->highest_used_slotid = NFS4_NO_SLOT; } @@ -480,7 +482,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) session = tbl->session; spin_lock(&tbl->slot_tbl_lock); - nfs4_free_slot(tbl, res->sr_slot - tbl->slots); + nfs4_free_slot(tbl, res->sr_slot); nfs4_check_drain_fc_complete(session); spin_unlock(&tbl->slot_tbl_lock); res->sr_slot = NULL; -- cgit v0.10.2 From e52966c084f9d9ea12be2ac7df801d610d4a19a5 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 8 Nov 2012 22:38:05 -0500 Subject: tools/power turbostat: prevent infinite loop on migration error path Turbostat assumed if it can't migrate to a CPU, then the CPU must have gone off-line and turbostat should re-initialize with the new topology. But if turbostat can not migrate because it is restricted by a cpuset, then it will fail to migrate even after re-initialization, resulting in an infinite loop. Spit out a warning when we can't migrate and endure only 2 re-initialize cycles in a row before giving up and exiting. Signed-off-by: Len Brown diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 3c063a0..77e76b1 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -656,8 +656,10 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) { int cpu = t->cpu_id; - if (cpu_migrate(cpu)) + if (cpu_migrate(cpu)) { + fprintf(stderr, "Could not migrate to CPU %d\n", cpu); return -1; + } t->tsc = rdtsc(); /* we are running on local CPU of interest */ @@ -1088,15 +1090,22 @@ int mark_cpu_present(int cpu) void turbostat_loop() { int retval; + int restarted = 0; restart: + restarted++; + retval = for_all_cpus(get_counters, EVEN_COUNTERS); if (retval < -1) { exit(retval); } else if (retval == -1) { + if (restarted > 1) { + exit(retval); + } re_initialize(); goto restart; } + restarted = 0; gettimeofday(&tv_even, (struct timezone *)NULL); while (1) { -- cgit v0.10.2 From a36b1725b342c8131a86a0238789d8e7bcb490dd Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 25 Nov 2012 16:31:00 -0500 Subject: nfsd4: return badname, not inval, on "." or "..", or "/" The spec requires badname, not inval, in these cases. Some callers want us to return enoent, but I can see no justification for that. Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 09204f5..250171c 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -65,17 +65,17 @@ #define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL static __be32 -check_filename(char *str, int len, __be32 err) +check_filename(char *str, int len) { int i; if (len == 0) return nfserr_inval; if (isdotent(str, len)) - return err; + return nfserr_badname; for (i = 0; i < len; i++) if (str[i] == '/') - return err; + return nfserr_badname; return 0; } @@ -570,7 +570,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create READ32(create->cr_namelen); READ_BUF(create->cr_namelen); SAVEMEM(create->cr_name, create->cr_namelen); - if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) + if ((status = check_filename(create->cr_name, create->cr_namelen))) return status; status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, @@ -602,7 +602,7 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) READ32(link->li_namelen); READ_BUF(link->li_namelen); SAVEMEM(link->li_name, link->li_namelen); - if ((status = check_filename(link->li_name, link->li_namelen, nfserr_inval))) + if ((status = check_filename(link->li_name, link->li_namelen))) return status; DECODE_TAIL; @@ -696,7 +696,7 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup READ32(lookup->lo_len); READ_BUF(lookup->lo_len); SAVEMEM(lookup->lo_name, lookup->lo_len); - if ((status = check_filename(lookup->lo_name, lookup->lo_len, nfserr_noent))) + if ((status = check_filename(lookup->lo_name, lookup->lo_len))) return status; DECODE_TAIL; @@ -860,7 +860,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) READ32(open->op_fname.len); READ_BUF(open->op_fname.len); SAVEMEM(open->op_fname.data, open->op_fname.len); - if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) + if ((status = check_filename(open->op_fname.data, open->op_fname.len))) return status; break; case NFS4_OPEN_CLAIM_PREVIOUS: @@ -875,7 +875,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) READ32(open->op_fname.len); READ_BUF(open->op_fname.len); SAVEMEM(open->op_fname.data, open->op_fname.len); - if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) + if ((status = check_filename(open->op_fname.data, open->op_fname.len))) return status; break; case NFS4_OPEN_CLAIM_FH: @@ -987,7 +987,7 @@ nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove READ32(remove->rm_namelen); READ_BUF(remove->rm_namelen); SAVEMEM(remove->rm_name, remove->rm_namelen); - if ((status = check_filename(remove->rm_name, remove->rm_namelen, nfserr_noent))) + if ((status = check_filename(remove->rm_name, remove->rm_namelen))) return status; DECODE_TAIL; @@ -1005,9 +1005,9 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename READ32(rename->rn_tnamelen); READ_BUF(rename->rn_tnamelen); SAVEMEM(rename->rn_tname, rename->rn_tnamelen); - if ((status = check_filename(rename->rn_sname, rename->rn_snamelen, nfserr_noent))) + if ((status = check_filename(rename->rn_sname, rename->rn_snamelen))) return status; - if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen, nfserr_inval))) + if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen))) return status; DECODE_TAIL; @@ -1034,8 +1034,7 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, READ32(secinfo->si_namelen); READ_BUF(secinfo->si_namelen); SAVEMEM(secinfo->si_name, secinfo->si_namelen); - status = check_filename(secinfo->si_name, secinfo->si_namelen, - nfserr_noent); + status = check_filename(secinfo->si_name, secinfo->si_namelen); if (status) return status; DECODE_TAIL; -- cgit v0.10.2 From 9336648978c2e9de9bf3c026918db386ace19a86 Mon Sep 17 00:00:00 2001 From: Vipul Kumar Samar Date: Mon, 26 Nov 2012 08:50:08 -0800 Subject: Input: spear-keyboard - add clk_{un}prepare() support clk_{un}prepare is mandatory for platforms using common clock framework. Because for SPEAr we don't do anything in clk_{un}prepare() calls, just call them once in probe/remove. Signed-off-by: Vipul Kumar Samar Signed-off-by: Viresh Kumar Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index d70093b..695d237 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -267,9 +267,14 @@ static int spear_kbd_probe(struct platform_device *pdev) return error; } + error = clk_prepare(kbd->clk); + if (error) + return error; + error = input_register_device(input_dev); if (error) { dev_err(&pdev->dev, "Unable to register keyboard device\n"); + clk_unprepare(kbd->clk); return error; } @@ -281,6 +286,11 @@ static int spear_kbd_probe(struct platform_device *pdev) static int spear_kbd_remove(struct platform_device *pdev) { + struct spear_kbd *kbd = platform_get_drvdata(pdev); + + input_unregister_device(kbd->input); + clk_unprepare(kbd->clk); + device_init_wakeup(&pdev->dev, 0); platform_set_drvdata(pdev, NULL); -- cgit v0.10.2 From a57da34795452bbe44b55e2b69c3ab6b117cc4b4 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 27 Nov 2012 22:34:38 -0800 Subject: Input: samsung-keypad - switch to using managed resources devm_* functions are device managed and make error handling and code simpler. While at it also fix error exit paths. Signed-off-by: Sachin Kamat Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index acc1619..22e357b 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -309,7 +309,7 @@ static void samsung_keypad_parse_dt_gpio(struct device *dev, struct samsung_keypad *keypad) { struct device_node *np = dev->of_node; - int gpio, ret, row, col; + int gpio, error, row, col; for (row = 0; row < keypad->rows; row++) { gpio = of_get_named_gpio(np, "row-gpios", row); @@ -320,10 +320,11 @@ static void samsung_keypad_parse_dt_gpio(struct device *dev, continue; } - ret = gpio_request(gpio, "keypad-row"); - if (ret) - dev_err(dev, "keypad row[%d] gpio request failed\n", - row); + error = devm_gpio_request(dev, gpio, "keypad-row"); + if (error) + dev_err(dev, + "keypad row[%d] gpio request failed: %d\n", + row, error); } for (col = 0; col < keypad->cols; col++) { @@ -335,35 +336,19 @@ static void samsung_keypad_parse_dt_gpio(struct device *dev, continue; } - ret = gpio_request(gpio, "keypad-col"); - if (ret) - dev_err(dev, "keypad column[%d] gpio request failed\n", - col); + error = devm_gpio_request(dev, gpio, "keypad-col"); + if (error) + dev_err(dev, + "keypad column[%d] gpio request failed: %d\n", + col, error); } } - -static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) -{ - int cnt; - - for (cnt = 0; cnt < keypad->rows; cnt++) - if (gpio_is_valid(keypad->row_gpios[cnt])) - gpio_free(keypad->row_gpios[cnt]); - - for (cnt = 0; cnt < keypad->cols; cnt++) - if (gpio_is_valid(keypad->col_gpios[cnt])) - gpio_free(keypad->col_gpios[cnt]); -} #else static struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev) { return NULL; } - -static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad) -{ -} #endif static int samsung_keypad_probe(struct platform_device *pdev) @@ -405,36 +390,30 @@ static int samsung_keypad_probe(struct platform_device *pdev) row_shift = get_count_order(pdata->cols); keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]); - keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL); - input_dev = input_allocate_device(); - if (!keypad || !input_dev) { - error = -ENOMEM; - goto err_free_mem; - } + keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad) + keymap_size, + GFP_KERNEL); + input_dev = devm_input_allocate_device(&pdev->dev); + if (!keypad || !input_dev) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - error = -ENODEV; - goto err_free_mem; - } + if (!res) + return -ENODEV; - keypad->base = ioremap(res->start, resource_size(res)); - if (!keypad->base) { - error = -EBUSY; - goto err_free_mem; - } + keypad->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!keypad->base) + return -EBUSY; - keypad->clk = clk_get(&pdev->dev, "keypad"); + keypad->clk = devm_clk_get(&pdev->dev, "keypad"); if (IS_ERR(keypad->clk)) { dev_err(&pdev->dev, "failed to get keypad clk\n"); - error = PTR_ERR(keypad->clk); - goto err_unmap_base; + return PTR_ERR(keypad->clk); } error = clk_prepare(keypad->clk); if (error) { dev_err(&pdev->dev, "keypad clock prepare failed\n"); - goto err_put_clk; + return error; } keypad->input_dev = input_dev; @@ -479,14 +458,15 @@ static int samsung_keypad_probe(struct platform_device *pdev) keypad->irq = platform_get_irq(pdev, 0); if (keypad->irq < 0) { error = keypad->irq; - goto err_put_clk; + goto err_unprepare_clk; } - error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq, - IRQF_ONESHOT, dev_name(&pdev->dev), keypad); + error = devm_request_threaded_irq(&pdev->dev, keypad->irq, NULL, + samsung_keypad_irq, IRQF_ONESHOT, + dev_name(&pdev->dev), keypad); if (error) { dev_err(&pdev->dev, "failed to register keypad interrupt\n"); - goto err_put_clk; + goto err_unprepare_clk; } device_init_wakeup(&pdev->dev, pdata->wakeup); @@ -495,7 +475,7 @@ static int samsung_keypad_probe(struct platform_device *pdev) error = input_register_device(keypad->input_dev); if (error) - goto err_free_irq; + goto err_disable_runtime_pm; if (pdev->dev.of_node) { devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap); @@ -504,22 +484,12 @@ static int samsung_keypad_probe(struct platform_device *pdev) } return 0; -err_free_irq: - free_irq(keypad->irq, keypad); +err_disable_runtime_pm: pm_runtime_disable(&pdev->dev); device_init_wakeup(&pdev->dev, 0); platform_set_drvdata(pdev, NULL); err_unprepare_clk: clk_unprepare(keypad->clk); -err_put_clk: - clk_put(keypad->clk); - samsung_keypad_dt_gpio_free(keypad); -err_unmap_base: - iounmap(keypad->base); -err_free_mem: - input_free_device(input_dev); - kfree(keypad); - return error; } @@ -533,18 +503,7 @@ static int samsung_keypad_remove(struct platform_device *pdev) input_unregister_device(keypad->input_dev); - /* - * It is safe to free IRQ after unregistering device because - * samsung_keypad_close will shut off interrupts. - */ - free_irq(keypad->irq, keypad); - clk_unprepare(keypad->clk); - clk_put(keypad->clk); - samsung_keypad_dt_gpio_free(keypad); - - iounmap(keypad->base); - kfree(keypad); return 0; } -- cgit v0.10.2 From 5b76d7b4cd965a84d922f303fe51a49cca89f9bb Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 24 Nov 2012 01:22:43 -0800 Subject: Input: gpio_keys - report initial state when opening the device Instead of reporting the initial stage when the device is registered we should do it when the device is opened (so there are users). Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 1a5cb6f..c7764ca 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -526,12 +526,35 @@ fail: return error; } +static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata) +{ + struct input_dev *input = ddata->input; + int i; + + for (i = 0; i < ddata->pdata->nbuttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + if (gpio_is_valid(bdata->button->gpio)) + gpio_keys_gpio_report_event(bdata); + } + input_sync(input); +} + static int gpio_keys_open(struct input_dev *input) { struct gpio_keys_drvdata *ddata = input_get_drvdata(input); const struct gpio_keys_platform_data *pdata = ddata->pdata; + int error; + + if (pdata->enable) { + error = pdata->enable(input->dev.parent); + if (error) + return error; + } - return pdata->enable ? pdata->enable(input->dev.parent) : 0; + /* Report current state of buttons that are connected to GPIOs */ + gpio_keys_report_state(ddata); + + return 0; } static void gpio_keys_close(struct input_dev *input) @@ -731,14 +754,6 @@ static int gpio_keys_probe(struct platform_device *pdev) goto fail3; } - /* get current state of buttons that are connected to GPIOs */ - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_button_data *bdata = &ddata->data[i]; - if (gpio_is_valid(bdata->button->gpio)) - gpio_keys_gpio_report_event(bdata); - } - input_sync(input); - device_init_wakeup(&pdev->dev, wakeup); return 0; @@ -810,11 +825,9 @@ static int gpio_keys_resume(struct device *dev) struct gpio_button_data *bdata = &ddata->data[i]; if (bdata->button->wakeup && device_may_wakeup(dev)) disable_irq_wake(bdata->irq); - - if (gpio_is_valid(bdata->button->gpio)) - gpio_keys_gpio_report_event(bdata); } - input_sync(ddata->input); + + gpio_keys_report_state(ddata); return 0; } -- cgit v0.10.2 From dda19a92f033399641e47db0b75beb01d001146b Mon Sep 17 00:00:00 2001 From: Jonas Aaberg Date: Sat, 24 Nov 2012 00:10:29 -0800 Subject: Input: gpio_keys - disable hardware on suspend Disable hardware if active when suspending if the hw can not wake the system from suspend. [Dmitry Torokhov: use input_dev->users instead of a separate flag] Signed-off-by: Jonas Aaberg Signed-off-by: Philippe Langlais Reviewed-by: Bengt Jonsson Signed-off-by: Lee Jones Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index c7764ca..79435de 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -803,6 +803,7 @@ static int gpio_keys_remove(struct platform_device *pdev) static int gpio_keys_suspend(struct device *dev) { struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); + struct input_dev *input = ddata->input; int i; if (device_may_wakeup(dev)) { @@ -811,6 +812,11 @@ static int gpio_keys_suspend(struct device *dev) if (bdata->button->wakeup) enable_irq_wake(bdata->irq); } + } else { + mutex_lock(&input->mutex); + if (input->users) + gpio_keys_close(input); + mutex_unlock(&input->mutex); } return 0; @@ -819,16 +825,27 @@ static int gpio_keys_suspend(struct device *dev) static int gpio_keys_resume(struct device *dev) { struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); + struct input_dev *input = ddata->input; + int error = 0; int i; - for (i = 0; i < ddata->pdata->nbuttons; i++) { - struct gpio_button_data *bdata = &ddata->data[i]; - if (bdata->button->wakeup && device_may_wakeup(dev)) - disable_irq_wake(bdata->irq); + if (device_may_wakeup(dev)) { + for (i = 0; i < ddata->pdata->nbuttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + if (bdata->button->wakeup) + disable_irq_wake(bdata->irq); + } + } else { + mutex_lock(&input->mutex); + if (input->users) + error = gpio_keys_open(input); + mutex_unlock(&input->mutex); } - gpio_keys_report_state(ddata); + if (error) + return error; + gpio_keys_report_state(ddata); return 0; } #endif -- cgit v0.10.2 From 64db3648e87dceb87ff05d83b1f408f8f691c429 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 27 Sep 2012 11:47:43 +0100 Subject: ARM: ux500: Strip out duplicate touch screen platform information We're currently carrying two 'struct bu21013_platform_device's which are identical for no apparent reason. Here we remove the extra burden and apply the same information to the two different instances of the bu21012_tp driver registration. [Dmitry Torokhov: picked it up to (hopefully) reduce merge conflict with bu21013_ts update that follows.] Acked-by: Arnd Bergmann Acked-by: Linus Walleij Signed-off-by: Lee Jones Signed-off-by: Dmitry Torokhov diff --git a/arch/arm/mach-ux500/board-mop500-stuib.c b/arch/arm/mach-ux500/board-mop500-stuib.c index 8c97977..564f57d 100644 --- a/arch/arm/mach-ux500/board-mop500-stuib.c +++ b/arch/arm/mach-ux500/board-mop500-stuib.c @@ -162,18 +162,6 @@ static struct bu21013_platform_device tsc_plat_device = { .y_flip = true, }; -static struct bu21013_platform_device tsc_plat2_device = { - .cs_en = bu21013_gpio_board_init, - .cs_dis = bu21013_gpio_board_exit, - .irq_read_val = bu21013_read_pin_val, - .irq = NOMADIK_GPIO_TO_IRQ(TOUCH_GPIO_PIN), - .touch_x_max = TOUCH_XMAX, - .touch_y_max = TOUCH_YMAX, - .ext_clk = false, - .x_flip = false, - .y_flip = true, -}; - static struct i2c_board_info __initdata u8500_i2c3_devices_stuib[] = { { I2C_BOARD_INFO("bu21013_tp", 0x5C), @@ -181,21 +169,17 @@ static struct i2c_board_info __initdata u8500_i2c3_devices_stuib[] = { }, { I2C_BOARD_INFO("bu21013_tp", 0x5D), - .platform_data = &tsc_plat2_device, + .platform_data = &tsc_plat_device, }, }; void __init mop500_stuib_init(void) { - if (machine_is_hrefv60()) { + if (machine_is_hrefv60()) tsc_plat_device.cs_pin = HREFV60_TOUCH_RST_GPIO; - tsc_plat2_device.cs_pin = HREFV60_TOUCH_RST_GPIO; - } else { + else tsc_plat_device.cs_pin = GPIO_BU21013_CS; - tsc_plat2_device.cs_pin = GPIO_BU21013_CS; - - } mop500_uib_i2c_add(0, mop500_i2c0_devices_stuib, ARRAY_SIZE(mop500_i2c0_devices_stuib)); -- cgit v0.10.2 From 8c587f7709f7f6377842968562bcf51ee6f47f09 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 21 Nov 2012 19:11:46 -0800 Subject: Input: bu21013_ts - request regulator that actually exists Currently the BU21013 Touch Screen driver requests a regulator by the name of 'V-TOUCH', which doesn't exist anywhere in the kernel. The correct name, as referenced in platform regulator code is 'avdd'. Here, when we request a regulator, we use the correct name instead. Acked-by: Arnd Bergmann Acked-by: Linus Walleij Signed-off-by: Lee Jones Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index 59a8ce8..1e8cddd 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -461,7 +461,7 @@ static int bu21013_probe(struct i2c_client *client, bu21013_data->chip = pdata; bu21013_data->client = client; - bu21013_data->regulator = regulator_get(&client->dev, "V-TOUCH"); + bu21013_data->regulator = regulator_get(&client->dev, "avdd"); if (IS_ERR(bu21013_data->regulator)) { dev_err(&client->dev, "regulator_get failed\n"); error = PTR_ERR(bu21013_data->regulator); -- cgit v0.10.2 From 31fbcda71489d8cbe2b82819eaab4818524e3a49 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 28 Sep 2012 10:29:07 +0100 Subject: Input: bu21013_ts - move GPIO init and exit functions into the driver These GPIO init and exit functions have no place in platform data, they should be part of the driver instead, Acked-by: Arnd Bergmann Acked-by: Linus Walleij Signed-off-by: Lee Jones Signed-off-by: Dmitry Torokhov diff --git a/arch/arm/mach-ux500/board-mop500-stuib.c b/arch/arm/mach-ux500/board-mop500-stuib.c index 564f57d..7e1f294 100644 --- a/arch/arm/mach-ux500/board-mop500-stuib.c +++ b/arch/arm/mach-ux500/board-mop500-stuib.c @@ -77,9 +77,6 @@ static struct i2c_board_info __initdata mop500_i2c0_devices_stuib[] = { * BU21013 ROHM touchscreen interface on the STUIBs */ -/* tracks number of bu21013 devices being enabled */ -static int bu21013_devices; - #define TOUCH_GPIO_PIN 84 #define TOUCH_XMAX 384 @@ -88,73 +85,8 @@ static int bu21013_devices; #define PRCMU_CLOCK_OCR 0x1CC #define TSC_EXT_CLOCK_9_6MHZ 0x840000 -/** - * bu21013_gpio_board_init : configures the touch panel. - * @reset_pin: reset pin number - * This function can be used to configures - * the voltage and reset the touch panel controller. - */ -static int bu21013_gpio_board_init(int reset_pin) -{ - int retval = 0; - - bu21013_devices++; - if (bu21013_devices == 1) { - retval = gpio_request(reset_pin, "touchp_reset"); - if (retval) { - printk(KERN_ERR "Unable to request gpio reset_pin"); - return retval; - } - retval = gpio_direction_output(reset_pin, 1); - if (retval < 0) { - printk(KERN_ERR "%s: gpio direction failed\n", - __func__); - return retval; - } - } - - return retval; -} - -/** - * bu21013_gpio_board_exit : deconfigures the touch panel controller - * @reset_pin: reset pin number - * This function can be used to deconfigures the chip selection - * for touch panel controller. - */ -static int bu21013_gpio_board_exit(int reset_pin) -{ - int retval = 0; - - if (bu21013_devices == 1) { - retval = gpio_direction_output(reset_pin, 0); - if (retval < 0) { - printk(KERN_ERR "%s: gpio direction failed\n", - __func__); - return retval; - } - gpio_set_value(reset_pin, 0); - } - bu21013_devices--; - - return retval; -} - -/** - * bu21013_read_pin_val : get the interrupt pin value - * This function can be used to get the interrupt pin value for touch panel - * controller. - */ -static int bu21013_read_pin_val(void) -{ - return gpio_get_value(TOUCH_GPIO_PIN); -} - static struct bu21013_platform_device tsc_plat_device = { - .cs_en = bu21013_gpio_board_init, - .cs_dis = bu21013_gpio_board_exit, - .irq_read_val = bu21013_read_pin_val, - .irq = NOMADIK_GPIO_TO_IRQ(TOUCH_GPIO_PIN), + .touch_pin = TOUCH_GPIO_PIN, .touch_x_max = TOUCH_XMAX, .touch_y_max = TOUCH_YMAX, .ext_clk = false, @@ -171,7 +103,6 @@ static struct i2c_board_info __initdata u8500_i2c3_devices_stuib[] = { I2C_BOARD_INFO("bu21013_tp", 0x5D), .platform_data = &tsc_plat_device, }, - }; void __init mop500_stuib_init(void) diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index 1e8cddd..c6f6a04 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -14,6 +14,7 @@ #include #include #include +#include #define PEN_DOWN_INTR 0 #define MAX_FINGERS 2 @@ -148,11 +149,12 @@ struct bu21013_ts_data { struct i2c_client *client; wait_queue_head_t wait; - bool touch_stopped; const struct bu21013_platform_device *chip; struct input_dev *in_dev; - unsigned int intr_pin; struct regulator *regulator; + unsigned int irq; + unsigned int intr_pin; + bool touch_stopped; }; /** @@ -262,7 +264,7 @@ static irqreturn_t bu21013_gpio_irq(int irq, void *device_data) return IRQ_NONE; } - data->intr_pin = data->chip->irq_read_val(); + data->intr_pin = gpio_get_value(data->chip->touch_pin); if (data->intr_pin == PEN_DOWN_INTR) wait_event_timeout(data->wait, data->touch_stopped, msecs_to_jiffies(2)); @@ -418,10 +420,33 @@ static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data) { bu21013_data->touch_stopped = true; wake_up(&bu21013_data->wait); - free_irq(bu21013_data->chip->irq, bu21013_data); + free_irq(bu21013_data->irq, bu21013_data); } /** + * bu21013_cs_disable() - deconfigures the touch panel controller + * @bu21013_data: device structure pointer + * + * This function is used to deconfigure the chip selection + * for touch panel controller. + */ +static void bu21013_cs_disable(struct bu21013_ts_data *bu21013_data) +{ + int error; + + error = gpio_direction_output(bu21013_data->chip->cs_pin, 0); + if (error < 0) + dev_warn(&bu21013_data->client->dev, + "%s: gpio direction failed, error: %d\n", + __func__, error); + else + gpio_set_value(bu21013_data->chip->cs_pin, 0); + + gpio_free(bu21013_data->chip->cs_pin); +} + + +/** * bu21013_probe() - initializes the i2c-client touchscreen driver * @client: i2c client structure pointer * @id: i2c device id pointer @@ -430,7 +455,7 @@ static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data) * driver and returns integer. */ static int bu21013_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct bu21013_ts_data *bu21013_data; struct input_dev *in_dev; @@ -449,6 +474,11 @@ static int bu21013_probe(struct i2c_client *client, return -EINVAL; } + if (!gpio_is_valid(pdata->touch_pin)) { + dev_err(&client->dev, "invalid touch_pin supplied\n"); + return -EINVAL; + } + bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL); in_dev = input_allocate_device(); if (!bu21013_data || !in_dev) { @@ -460,6 +490,7 @@ static int bu21013_probe(struct i2c_client *client, bu21013_data->in_dev = in_dev; bu21013_data->chip = pdata; bu21013_data->client = client; + bu21013_data->irq = gpio_to_irq(pdata->touch_pin); bu21013_data->regulator = regulator_get(&client->dev, "avdd"); if (IS_ERR(bu21013_data->regulator)) { @@ -478,12 +509,11 @@ static int bu21013_probe(struct i2c_client *client, init_waitqueue_head(&bu21013_data->wait); /* configure the gpio pins */ - if (pdata->cs_en) { - error = pdata->cs_en(pdata->cs_pin); - if (error < 0) { - dev_err(&client->dev, "chip init failed\n"); - goto err_disable_regulator; - } + error = gpio_request_one(pdata->cs_pin, GPIOF_OUT_INIT_HIGH, + "touchp_reset"); + if (error < 0) { + dev_err(&client->dev, "Unable to request gpio reset_pin\n"); + goto err_disable_regulator; } /* configure the touch panel controller */ @@ -508,12 +538,13 @@ static int bu21013_probe(struct i2c_client *client, pdata->touch_y_max, 0, 0); input_set_drvdata(in_dev, bu21013_data); - error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq, + error = request_threaded_irq(bu21013_data->irq, NULL, bu21013_gpio_irq, IRQF_TRIGGER_FALLING | IRQF_SHARED | IRQF_ONESHOT, DRIVER_TP, bu21013_data); if (error) { - dev_err(&client->dev, "request irq %d failed\n", pdata->irq); + dev_err(&client->dev, "request irq %d failed\n", + bu21013_data->irq); goto err_cs_disable; } @@ -531,7 +562,7 @@ static int bu21013_probe(struct i2c_client *client, err_free_irq: bu21013_free_irq(bu21013_data); err_cs_disable: - pdata->cs_dis(pdata->cs_pin); + bu21013_cs_disable(bu21013_data); err_disable_regulator: regulator_disable(bu21013_data->regulator); err_put_regulator: @@ -555,7 +586,7 @@ static int bu21013_remove(struct i2c_client *client) bu21013_free_irq(bu21013_data); - bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin); + bu21013_cs_disable(bu21013_data); input_unregister_device(bu21013_data->in_dev); @@ -584,9 +615,9 @@ static int bu21013_suspend(struct device *dev) bu21013_data->touch_stopped = true; if (device_may_wakeup(&client->dev)) - enable_irq_wake(bu21013_data->chip->irq); + enable_irq_wake(bu21013_data->irq); else - disable_irq(bu21013_data->chip->irq); + disable_irq(bu21013_data->irq); regulator_disable(bu21013_data->regulator); @@ -621,9 +652,9 @@ static int bu21013_resume(struct device *dev) bu21013_data->touch_stopped = false; if (device_may_wakeup(&client->dev)) - disable_irq_wake(bu21013_data->chip->irq); + disable_irq_wake(bu21013_data->irq); else - enable_irq(bu21013_data->chip->irq); + enable_irq(bu21013_data->irq); return 0; } diff --git a/include/linux/input/bu21013.h b/include/linux/input/bu21013.h index 05e0328..6230d76 100644 --- a/include/linux/input/bu21013.h +++ b/include/linux/input/bu21013.h @@ -9,13 +9,10 @@ /** * struct bu21013_platform_device - Handle the platform data - * @cs_en: pointer to the cs enable function - * @cs_dis: pointer to the cs disable function - * @irq_read_val: pointer to read the pen irq value function * @touch_x_max: touch x max * @touch_y_max: touch y max * @cs_pin: chip select pin - * @irq: irq pin + * @touch_pin: touch gpio pin * @ext_clk: external clock flag * @x_flip: x flip flag * @y_flip: y flip flag @@ -24,13 +21,10 @@ * This is used to handle the platform data */ struct bu21013_platform_device { - int (*cs_en)(int reset_pin); - int (*cs_dis)(int reset_pin); - int (*irq_read_val)(void); int touch_x_max; int touch_y_max; unsigned int cs_pin; - unsigned int irq; + unsigned int touch_pin; bool ext_clk; bool x_flip; bool y_flip; -- cgit v0.10.2 From 48fceb7d37cde11edf342c5095fa8815365c299f Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 28 Sep 2012 14:35:43 +0100 Subject: Input: bu21013_ts - add support for Device Tree booting Now we can register the BU21013_ts touch screen when booting with Device Tree enabled. Here we parse all the necessary components previously expected to be passed from platform data. Acked-by: Arnd Bergmann Acked-by: Linus Walleij Signed-off-by: Lee Jones Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index c6f6a04..b9b5dda 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #define PEN_DOWN_INTR 0 #define MAX_FINGERS 2 @@ -445,6 +447,45 @@ static void bu21013_cs_disable(struct bu21013_ts_data *bu21013_data) gpio_free(bu21013_data->chip->cs_pin); } +#ifdef CONFIG_OF +static const struct bu21013_platform_device * +bu21013_parse_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct bu21013_platform_device *pdata; + + if (!np) { + dev_err(dev, "no device tree or platform data\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->y_flip = pdata->x_flip = false; + + pdata->x_flip = of_property_read_bool(np, "rohm,flip-x"); + pdata->y_flip = of_property_read_bool(np, "rohm,flip-y"); + + of_property_read_u32(np, "rohm,touch-max-x", &pdata->touch_x_max); + of_property_read_u32(np, "rohm,touch-max-y", &pdata->touch_y_max); + + pdata->touch_pin = of_get_named_gpio(np, "touch-gpio", 0); + pdata->cs_pin = of_get_named_gpio(np, "reset-gpio", 0); + + pdata->ext_clk = false; + + return pdata; +} +#else +static inline const struct bu21013_platform_device * +bu21013_parse_dt(struct device *dev) +{ + dev_err(dev, "no platform data available\n"); + return ERR_PTR(-EINVAL); +} +#endif /** * bu21013_probe() - initializes the i2c-client touchscreen driver @@ -457,10 +498,10 @@ static void bu21013_cs_disable(struct bu21013_ts_data *bu21013_data) static int bu21013_probe(struct i2c_client *client, const struct i2c_device_id *id) { + const struct bu21013_platform_device *pdata = + dev_get_platdata(&client->dev); struct bu21013_ts_data *bu21013_data; struct input_dev *in_dev; - const struct bu21013_platform_device *pdata = - client->dev.platform_data; int error; if (!i2c_check_functionality(client->adapter, @@ -470,8 +511,9 @@ static int bu21013_probe(struct i2c_client *client, } if (!pdata) { - dev_err(&client->dev, "platform data not defined\n"); - return -EINVAL; + pdata = bu21013_parse_dt(&client->dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } if (!gpio_is_valid(pdata->touch_pin)) { -- cgit v0.10.2 From 852d20aed8a029ea8496e85052493b275f19d22b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 26 Nov 2012 00:06:36 -0800 Subject: Input: remove Compaq iPAQ H3600 (Bitsy) touchscreen driver The kernel does not contain the symbol SA1100_BITSY so the driver is never compiled and can be removed safely. Signed-off-by: Alexander Shiyan Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index f7668b2..b93b598 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -111,18 +111,6 @@ config TOUCHSCREEN_AUO_PIXCIR To compile this driver as a module, choose M here: the module will be called auo-pixcir-ts. -config TOUCHSCREEN_BITSY - tristate "Compaq iPAQ H3600 (Bitsy) touchscreen" - depends on SA1100_BITSY - select SERIO - help - Say Y here if you have the h3600 (Bitsy) touchscreen. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called h3600_ts_input. - config TOUCHSCREEN_BU21013 tristate "BU21013 based touch panel controllers" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 178eb12..5f949c0 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o -obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c deleted file mode 100644 index b9e8686..0000000 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com - * - * Sponsored by Transvirtual Technology. - * - * Derived from the code in h3600_ts.[ch] by Charles Flynn - */ - -/* - * Driver for the h3600 Touch Screen and other Atmel controlled devices. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so by - * e-mail - mail your message to . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* SA1100 serial defines */ -#include -#include - -#define DRIVER_DESC "H3600 touchscreen driver" - -MODULE_AUTHOR("James Simmons "); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -/* - * Definitions & global arrays. - */ - -/* The start and end of frame characters SOF and EOF */ -#define CHAR_SOF 0x02 -#define CHAR_EOF 0x03 -#define FRAME_OVERHEAD 3 /* CHAR_SOF,CHAR_EOF,LENGTH = 3 */ - -/* - Atmel events and response IDs contained in frame. - Programmer has no control over these numbers. - TODO there are holes - specifically 1,7,0x0a -*/ -#define VERSION_ID 0 /* Get Version (request/response) */ -#define KEYBD_ID 2 /* Keyboard (event) */ -#define TOUCHS_ID 3 /* Touch Screen (event)*/ -#define EEPROM_READ_ID 4 /* (request/response) */ -#define EEPROM_WRITE_ID 5 /* (request/response) */ -#define THERMAL_ID 6 /* (request/response) */ -#define NOTIFY_LED_ID 8 /* (request/response) */ -#define BATTERY_ID 9 /* (request/response) */ -#define SPI_READ_ID 0x0b /* ( request/response) */ -#define SPI_WRITE_ID 0x0c /* ( request/response) */ -#define FLITE_ID 0x0d /* backlight ( request/response) */ -#define STX_ID 0xa1 /* extension pack status (req/resp) */ - -#define MAX_ID 14 - -#define H3600_MAX_LENGTH 16 -#define H3600_KEY 0xf - -#define H3600_SCANCODE_RECORD 1 /* 1 -> record button */ -#define H3600_SCANCODE_CALENDAR 2 /* 2 -> calendar */ -#define H3600_SCANCODE_CONTACTS 3 /* 3 -> contact */ -#define H3600_SCANCODE_Q 4 /* 4 -> Q button */ -#define H3600_SCANCODE_START 5 /* 5 -> start menu */ -#define H3600_SCANCODE_UP 6 /* 6 -> up */ -#define H3600_SCANCODE_RIGHT 7 /* 7 -> right */ -#define H3600_SCANCODE_LEFT 8 /* 8 -> left */ -#define H3600_SCANCODE_DOWN 9 /* 9 -> down */ - -/* - * Per-touchscreen data. - */ -struct h3600_dev { - struct input_dev *dev; - struct serio *serio; - unsigned char event; /* event ID from packet */ - unsigned char chksum; - unsigned char len; - unsigned char idx; - unsigned char buf[H3600_MAX_LENGTH]; - char phys[32]; -}; - -static irqreturn_t action_button_handler(int irq, void *dev_id) -{ - int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1; - struct input_dev *dev = dev_id; - - input_report_key(dev, KEY_ENTER, down); - input_sync(dev); - - return IRQ_HANDLED; -} - -static irqreturn_t npower_button_handler(int irq, void *dev_id) -{ - int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1; - struct input_dev *dev = dev_id; - - /* - * This interrupt is only called when we release the key. So we have - * to fake a key press. - */ - input_report_key(dev, KEY_SUSPEND, 1); - input_report_key(dev, KEY_SUSPEND, down); - input_sync(dev); - - return IRQ_HANDLED; -} - -#ifdef CONFIG_PM - -static int flite_brightness = 25; - -enum flite_pwr { - FLITE_PWR_OFF = 0, - FLITE_PWR_ON = 1 -}; - -/* - * h3600_flite_power: enables or disables power to frontlight, using last bright */ -unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr) -{ - unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness; - struct h3600_dev *ts = input_get_drvdata(dev); - - /* Must be in this order */ - serio_write(ts->serio, 1); - serio_write(ts->serio, pwr); - serio_write(ts->serio, brightness); - - return 0; -} - -#endif - -/* - * This function translates the native event packets to linux input event - * packets. Some packets coming from serial are not touchscreen related. In - * this case we send them off to be processed elsewhere. - */ -static void h3600ts_process_packet(struct h3600_dev *ts) -{ - struct input_dev *dev = ts->dev; - static int touched = 0; - int key, down = 0; - - switch (ts->event) { - /* - Buttons - returned as a single byte - 7 6 5 4 3 2 1 0 - S x x x N N N N - - S switch state ( 0=pressed 1=released) - x Unused. - NNNN switch number 0-15 - - Note: This is true for non interrupt generated key events. - */ - case KEYBD_ID: - down = (ts->buf[0] & 0x80) ? 0 : 1; - - switch (ts->buf[0] & 0x7f) { - case H3600_SCANCODE_RECORD: - key = KEY_RECORD; - break; - case H3600_SCANCODE_CALENDAR: - key = KEY_PROG1; - break; - case H3600_SCANCODE_CONTACTS: - key = KEY_PROG2; - break; - case H3600_SCANCODE_Q: - key = KEY_Q; - break; - case H3600_SCANCODE_START: - key = KEY_PROG3; - break; - case H3600_SCANCODE_UP: - key = KEY_UP; - break; - case H3600_SCANCODE_RIGHT: - key = KEY_RIGHT; - break; - case H3600_SCANCODE_LEFT: - key = KEY_LEFT; - break; - case H3600_SCANCODE_DOWN: - key = KEY_DOWN; - break; - default: - key = 0; - } - if (key) - input_report_key(dev, key, down); - break; - /* - * Native touchscreen event data is formatted as shown below:- - * - * +-------+-------+-------+-------+ - * | Xmsb | Xlsb | Ymsb | Ylsb | - * +-------+-------+-------+-------+ - * byte 0 1 2 3 - */ - case TOUCHS_ID: - if (!touched) { - input_report_key(dev, BTN_TOUCH, 1); - touched = 1; - } - - if (ts->len) { - unsigned short x, y; - - x = ts->buf[0]; x <<= 8; x += ts->buf[1]; - y = ts->buf[2]; y <<= 8; y += ts->buf[3]; - - input_report_abs(dev, ABS_X, x); - input_report_abs(dev, ABS_Y, y); - } else { - input_report_key(dev, BTN_TOUCH, 0); - touched = 0; - } - break; - default: - /* Send a non input event elsewhere */ - break; - } - - input_sync(dev); -} - -/* - * h3600ts_event() handles events from the input module. - */ -static int h3600ts_event(struct input_dev *dev, unsigned int type, - unsigned int code, int value) -{ -#if 0 - struct h3600_dev *ts = input_get_drvdata(dev); - - switch (type) { - case EV_LED: { - // serio_write(ts->serio, SOME_CMD); - return 0; - } - } - return -1; -#endif - return 0; -} - -/* - Frame format - byte 1 2 3 len + 4 - +-------+---------------+---------------+--=------------+ - |SOF |id |len | len bytes | Chksum | - +-------+---------------+---------------+--=------------+ - bit 0 7 8 11 12 15 16 - - +-------+---------------+-------+ - |SOF |id |0 |Chksum | - Note Chksum does not include SOF - +-------+---------------+-------+ - bit 0 7 8 11 12 15 16 - -*/ - -static int state; - -/* decode States */ -#define STATE_SOF 0 /* start of FRAME */ -#define STATE_ID 1 /* state where we decode the ID & len */ -#define STATE_DATA 2 /* state where we decode data */ -#define STATE_EOF 3 /* state where we decode checksum or EOF */ - -static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data, - unsigned int flags) -{ - struct h3600_dev *ts = serio_get_drvdata(serio); - - /* - * We have a new frame coming in. - */ - switch (state) { - case STATE_SOF: - if (data == CHAR_SOF) - state = STATE_ID; - break; - case STATE_ID: - ts->event = (data & 0xf0) >> 4; - ts->len = (data & 0xf); - ts->idx = 0; - if (ts->event >= MAX_ID) { - state = STATE_SOF; - break; - } - ts->chksum = data; - state = (ts->len > 0) ? STATE_DATA : STATE_EOF; - break; - case STATE_DATA: - ts->chksum += data; - ts->buf[ts->idx]= data; - if (++ts->idx == ts->len) - state = STATE_EOF; - break; - case STATE_EOF: - state = STATE_SOF; - if (data == CHAR_EOF || data == ts->chksum) - h3600ts_process_packet(ts); - break; - default: - printk("Error3\n"); - break; - } - - return IRQ_HANDLED; -} - -/* - * h3600ts_connect() is the routine that is called when someone adds a - * new serio device that supports H3600 protocol and registers it as - * an input device. - */ -static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) -{ - struct h3600_dev *ts; - struct input_dev *input_dev; - int err; - - ts = kzalloc(sizeof(struct h3600_dev), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!ts || !input_dev) { - err = -ENOMEM; - goto fail1; - } - - ts->serio = serio; - ts->dev = input_dev; - snprintf(ts->phys, sizeof(ts->phys), "%s/input0", serio->phys); - - input_dev->name = "H3600 TouchScreen"; - input_dev->phys = ts->phys; - input_dev->id.bustype = BUS_RS232; - input_dev->id.vendor = SERIO_H3600; - input_dev->id.product = 0x0666; /* FIXME !!! We can ask the hardware */ - input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; - - input_set_drvdata(input_dev, ts); - - input_dev->event = h3600ts_event; - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | - BIT_MASK(EV_LED) | BIT_MASK(EV_PWR); - input_dev->ledbit[0] = BIT_MASK(LED_SLEEP); - input_set_abs_params(input_dev, ABS_X, 60, 985, 0, 0); - input_set_abs_params(input_dev, ABS_Y, 35, 1024, 0, 0); - - set_bit(KEY_RECORD, input_dev->keybit); - set_bit(KEY_Q, input_dev->keybit); - set_bit(KEY_PROG1, input_dev->keybit); - set_bit(KEY_PROG2, input_dev->keybit); - set_bit(KEY_PROG3, input_dev->keybit); - set_bit(KEY_UP, input_dev->keybit); - set_bit(KEY_RIGHT, input_dev->keybit); - set_bit(KEY_LEFT, input_dev->keybit); - set_bit(KEY_DOWN, input_dev->keybit); - set_bit(KEY_ENTER, input_dev->keybit); - set_bit(KEY_SUSPEND, input_dev->keybit); - set_bit(BTN_TOUCH, input_dev->keybit); - - /* Device specific stuff */ - set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES); - set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE); - - if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler, - IRQF_SHARED, "h3600_action", ts->dev)) { - printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n"); - err = -EBUSY; - goto fail1; - } - - if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler, - IRQF_SHARED, "h3600_suspend", ts->dev)) { - printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n"); - err = -EBUSY; - goto fail2; - } - - serio_set_drvdata(serio, ts); - - err = serio_open(serio, drv); - if (err) - goto fail3; - - //h3600_flite_control(1, 25); /* default brightness */ - err = input_register_device(ts->dev); - if (err) - goto fail4; - - return 0; - -fail4: serio_close(serio); -fail3: serio_set_drvdata(serio, NULL); - free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); -fail2: free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev); -fail1: input_free_device(input_dev); - kfree(ts); - return err; -} - -/* - * h3600ts_disconnect() is the opposite of h3600ts_connect() - */ - -static void h3600ts_disconnect(struct serio *serio) -{ - struct h3600_dev *ts = serio_get_drvdata(serio); - - free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev); - free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); - input_get_device(ts->dev); - input_unregister_device(ts->dev); - serio_close(serio); - serio_set_drvdata(serio, NULL); - input_put_device(ts->dev); - kfree(ts); -} - -/* - * The serio driver structure. - */ - -static struct serio_device_id h3600ts_serio_ids[] = { - { - .type = SERIO_RS232, - .proto = SERIO_H3600, - .id = SERIO_ANY, - .extra = SERIO_ANY, - }, - { 0 } -}; - -MODULE_DEVICE_TABLE(serio, h3600ts_serio_ids); - -static struct serio_driver h3600ts_drv = { - .driver = { - .name = "h3600ts", - }, - .description = DRIVER_DESC, - .id_table = h3600ts_serio_ids, - .interrupt = h3600ts_interrupt, - .connect = h3600ts_connect, - .disconnect = h3600ts_disconnect, -}; - -module_serio_driver(h3600ts_drv); -- cgit v0.10.2 From 972deb4f49b5b6703d9c6117ba0aeda2180d4447 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 26 Nov 2012 15:25:11 +0530 Subject: i2c: omap: Remove the OMAP_I2C_FLAG_RESET_REGS_POSTIDLE flag The OMAP_I2C_FLAG_RESET_REGS_POSTIDLE is not used anymore in the i2c driver. Remove the flag. Signed-off-by: Shubhrajyoti D Reviewed-by: Felipe Balbi Signed-off-by: Wolfram Sang diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c index 59d5c1c..c9a186b 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c @@ -1103,8 +1103,7 @@ static struct omap_hwmod_class i2c_class = { }; static struct omap_i2c_dev_attr i2c_dev_attr = { - .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE, }; /* i2c1 */ diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 943222c..36270bb 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -791,8 +791,7 @@ static struct omap_hwmod omap3xxx_dss_venc_hwmod = { /* I2C1 */ static struct omap_i2c_dev_attr i2c1_dev_attr = { .fifo_depth = 8, /* bytes */ - .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | - OMAP_I2C_FLAG_BUS_SHIFT_2, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, }; static struct omap_hwmod omap3xxx_i2c1_hwmod = { @@ -817,8 +816,7 @@ static struct omap_hwmod omap3xxx_i2c1_hwmod = { /* I2C2 */ static struct omap_i2c_dev_attr i2c2_dev_attr = { .fifo_depth = 8, /* bytes */ - .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | - OMAP_I2C_FLAG_BUS_SHIFT_2, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, }; static struct omap_hwmod omap3xxx_i2c2_hwmod = { @@ -843,8 +841,7 @@ static struct omap_hwmod omap3xxx_i2c2_hwmod = { /* I2C3 */ static struct omap_i2c_dev_attr i2c3_dev_attr = { .fifo_depth = 64, /* bytes */ - .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | - OMAP_I2C_FLAG_BUS_SHIFT_2, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, }; static struct omap_hwmod_irq_info i2c3_mpu_irqs[] = { diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 652d028..eb40dbc 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -1526,8 +1526,7 @@ static struct omap_hwmod_class omap44xx_i2c_hwmod_class = { }; static struct omap_i2c_dev_attr i2c_dev_attr = { - .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE | - OMAP_I2C_FLAG_RESET_REGS_POSTIDLE, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE, }; /* i2c1 */ diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 2482801..7a62acb 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1038,8 +1038,7 @@ static const struct i2c_algorithm omap_i2c_algo = { #ifdef CONFIG_OF static struct omap_i2c_bus_platform_data omap3_pdata = { .rev = OMAP_I2C_IP_VERSION_1, - .flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | - OMAP_I2C_FLAG_BUS_SHIFT_2, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, }; static struct omap_i2c_bus_platform_data omap4_pdata = { diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 1b25c04..babe0cf 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -20,7 +20,6 @@ #define OMAP_I2C_FLAG_NO_FIFO BIT(0) #define OMAP_I2C_FLAG_SIMPLE_CLOCK BIT(1) #define OMAP_I2C_FLAG_16BIT_DATA_REG BIT(2) -#define OMAP_I2C_FLAG_RESET_REGS_POSTIDLE BIT(3) #define OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK BIT(5) #define OMAP_I2C_FLAG_FORCE_19200_INT_CLK BIT(6) /* how the CPU address bus must be translated for I2C unit access */ -- cgit v0.10.2 From af0ba001d208e117b5f4e4f504672b42a664a7f7 Mon Sep 17 00:00:00 2001 From: "Philip, Avinash" Date: Tue, 27 Nov 2012 14:18:06 +0530 Subject: pwm: Add TI PWM subsystem driver In some platforms (like am33xx), PWM sub modules (ECAP, EHRPWM, EQEP) are integrated to PWM subsystem. These PWM submodules has resources shared and only one register bit-field is provided to control module/clock enable/disable, makes it difficult to handle common resources from independent PWMSS submodule drivers. So the solution here implemented in this patch is, to create driver for PWMSS and take the role of parent driver for PWM submodules. PWMSS parent driver enumerates all the child nodes under PWMSS module. Also symbol "pwmss_submodule_state_change" exported to enable clock gating for individual PWMSS submodules, and submodule drivers has to enable clock gating from their drivers. As this is only supported during DT boot, the parent/child relationship is created and populated in DT execution flow. The only required change is inside DTS file, making EHRPWM & ECAP as a child to PWMSS node. Signed-off-by: Philip, Avinash Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt b/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt new file mode 100644 index 0000000..f7eae77 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt @@ -0,0 +1,31 @@ +TI SOC based PWM Subsystem + +Required properties: +- compatible: Must be "ti,am33xx-pwmss"; +- reg: physical base address and size of the registers map. +- address-cells: Specify the number of u32 entries needed in child nodes. + Should set to 1. +- size-cells: specify number of u32 entries needed to specify child nodes size + in reg property. Should set to 1. +- ranges: describes the address mapping of a memory-mapped bus. Should set to + physical address map of child's base address, physical address within + parent's address space and length of the address map. For am33xx, + 3 set of child register maps present, ECAP register space, EQEP + register space, EHRPWM register space. + +Also child nodes should also populated under PWMSS DT node. + +Example: +pwmss0: pwmss@48300000 { + compatible = "ti,am33xx-pwmss"; + reg = <0x48300000 0x10>; + ti,hwmods = "epwmss0"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + ranges = <0x48300100 0x48300100 0x80 /* ECAP */ + 0x48300180 0x48300180 0x80 /* EQEP */ + 0x48300200 0x48300200 0x80>; /* EHRPWM */ + + /* child nodes go here */ +}; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 6e556c7..3dcb76d 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -136,6 +136,7 @@ config PWM_TEGRA config PWM_TIECAP tristate "ECAP PWM support" depends on SOC_AM33XX + select PWM_TIPWMSS help PWM driver support for the ECAP APWM controller found on AM33XX TI SOC @@ -146,6 +147,7 @@ config PWM_TIECAP config PWM_TIEHRPWM tristate "EHRPWM PWM support" depends on SOC_AM33XX + select PWM_TIPWMSS help PWM driver support for the EHRPWM controller found on AM33XX TI SOC @@ -153,6 +155,15 @@ config PWM_TIEHRPWM To compile this driver as a module, choose M here: the module will be called pwm-tiehrpwm. +config PWM_TIPWMSS + bool + depends on SOC_AM33XX && (PWM_TIEHRPWM || PWM_TIECAP) + help + PWM Subsystem driver support for AM33xx SOC. + + PWM submodules require PWM config space access from submodule + drivers and require common parent driver support. + config PWM_TWL6030 tristate "TWL6030 PWM support" depends on TWL4030_CORE diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 3b3f4c9a..4fb39f8 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -12,5 +12,6 @@ obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o +obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/pwm/pwm-tipwmss.c new file mode 100644 index 0000000..3448a1c --- /dev/null +++ b/drivers/pwm/pwm-tipwmss.c @@ -0,0 +1,139 @@ +/* + * TI PWM Subsystem driver + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "pwm-tipwmss.h" + +#define PWMSS_CLKCONFIG 0x8 /* Clock gating reg */ +#define PWMSS_CLKSTATUS 0xc /* Clock gating status reg */ + +struct pwmss_info { + void __iomem *mmio_base; + struct mutex pwmss_lock; + u16 pwmss_clkconfig; +}; + +u16 pwmss_submodule_state_change(struct device *dev, int set) +{ + struct pwmss_info *info = dev_get_drvdata(dev); + u16 val; + + mutex_lock(&info->pwmss_lock); + val = readw(info->mmio_base + PWMSS_CLKCONFIG); + val |= set; + writew(val , info->mmio_base + PWMSS_CLKCONFIG); + mutex_unlock(&info->pwmss_lock); + + return readw(info->mmio_base + PWMSS_CLKSTATUS); +} +EXPORT_SYMBOL(pwmss_submodule_state_change); + +static const struct of_device_id pwmss_of_match[] = { + { .compatible = "ti,am33xx-pwmss" }, + {}, +}; +MODULE_DEVICE_TABLE(of, pwmss_of_match); + +static int pwmss_probe(struct platform_device *pdev) +{ + int ret; + struct resource *r; + struct pwmss_info *info; + struct device_node *node = pdev->dev.of_node; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + mutex_init(&info->pwmss_lock); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "no memory resource defined\n"); + return -ENODEV; + } + + info->mmio_base = devm_request_and_ioremap(&pdev->dev, r); + if (!info->mmio_base) + return -EADDRNOTAVAIL; + + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + platform_set_drvdata(pdev, info); + + /* Populate all the child nodes here... */ + ret = of_platform_populate(node, NULL, NULL, &pdev->dev); + if (ret) + dev_err(&pdev->dev, "no child node found\n"); + + return ret; +} + +static int pwmss_remove(struct platform_device *pdev) +{ + struct pwmss_info *info = platform_get_drvdata(pdev); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + mutex_destroy(&info->pwmss_lock); + return 0; +} + +static int pwmss_suspend(struct device *dev) +{ + struct pwmss_info *info = dev_get_drvdata(dev); + + info->pwmss_clkconfig = readw(info->mmio_base + PWMSS_CLKCONFIG); + pm_runtime_put_sync(dev); + return 0; +} + +static int pwmss_resume(struct device *dev) +{ + struct pwmss_info *info = dev_get_drvdata(dev); + + pm_runtime_get_sync(dev); + writew(info->pwmss_clkconfig, info->mmio_base + PWMSS_CLKCONFIG); + return 0; +} + +static SIMPLE_DEV_PM_OPS(pwmss_pm_ops, pwmss_suspend, pwmss_resume); + +static struct platform_driver pwmss_driver = { + .driver = { + .name = "pwmss", + .owner = THIS_MODULE, + .pm = &pwmss_pm_ops, + .of_match_table = pwmss_of_match, + }, + .probe = pwmss_probe, + .remove = pwmss_remove, +}; + +module_platform_driver(pwmss_driver); + +MODULE_DESCRIPTION("PWM Subsystem driver"); +MODULE_AUTHOR("Texas Instruments"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pwm/pwm-tipwmss.h b/drivers/pwm/pwm-tipwmss.h new file mode 100644 index 0000000..11f76a1 --- /dev/null +++ b/drivers/pwm/pwm-tipwmss.h @@ -0,0 +1,39 @@ +/* + * TI PWM Subsystem driver + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __TIPWMSS_H +#define __TIPWMSS_H + +#ifdef CONFIG_PWM_TIPWMSS +/* PWM substem clock gating */ +#define PWMSS_ECAPCLK_EN BIT(0) +#define PWMSS_ECAPCLK_STOP_REQ BIT(1) +#define PWMSS_EPWMCLK_EN BIT(8) +#define PWMSS_EPWMCLK_STOP_REQ BIT(9) + +#define PWMSS_ECAPCLK_EN_ACK BIT(0) +#define PWMSS_EPWMCLK_EN_ACK BIT(8) + +extern u16 pwmss_submodule_state_change(struct device *dev, int set); +#else +static inline u16 pwmss_submodule_state_change(struct device *dev, int set) +{ + /* return success status value */ + return 0xFFFF; +} +#endif +#endif /* __TIPWMSS_H */ -- cgit v0.10.2 From 333b08ee8c6e120d67118e4eb71c45f5c369c8a4 Mon Sep 17 00:00:00 2001 From: "Philip, Avinash" Date: Tue, 27 Nov 2012 14:18:09 +0530 Subject: pwm: tiecap: Add device-tree binding This patch 1. Add support for device-tree binding for ECAP APWM driver. 2. Set size of pwm-cells set to 3 to support PWM channel number, PWM period & polarity configuration from device tree. 3. Add enable/disable clock gating in PWM subsystem common config space. 4. When here set .owner member in platform_driver structure to THIS_MODULE. Signed-off-by: Philip, Avinash Cc: Grant Likely Cc: Rob Herring Cc: Rob Landley Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt new file mode 100644 index 0000000..131e8c1 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt @@ -0,0 +1,23 @@ +TI SOC ECAP based APWM controller + +Required properties: +- compatible: Must be "ti,am33xx-ecap" +- #pwm-cells: Should be 3. Number of cells being used to specify PWM property. + First cell specifies the per-chip index of the PWM to use, the second + cell is the period in nanoseconds and bit 0 in the third cell is used to + encode the polarity of PWM output. Set bit 0 of the third in PWM specifier + to 1 for inverse polarity & set to 0 for normal polarity. +- reg: physical base address and size of the registers map. + +Optional properties: +- ti,hwmods: Name of the hwmod associated to the ECAP: + "ecap", being the 0-based instance number from the HW spec + +Example: + +ecap0: ecap@0 { + compatible = "ti,am33xx-ecap"; + #pwm-cells = <3>; + reg = <0x48300100 0x80>; + ti,hwmods = "ecap0"; +}; diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index d6d4cf0..0f541c5 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -25,6 +25,9 @@ #include #include #include +#include + +#include "pwm-tipwmss.h" /* ECAP registers and bits definitions */ #define CAP1 0x08 @@ -184,12 +187,19 @@ static const struct pwm_ops ecap_pwm_ops = { .owner = THIS_MODULE, }; +static const struct of_device_id ecap_of_match[] = { + { .compatible = "ti,am33xx-ecap" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ecap_of_match); + static int __devinit ecap_pwm_probe(struct platform_device *pdev) { int ret; struct resource *r; struct clk *clk; struct ecap_pwm_chip *pc; + u16 status; pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); if (!pc) { @@ -211,6 +221,8 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev) pc->chip.dev = &pdev->dev; pc->chip.ops = &ecap_pwm_ops; + pc->chip.of_xlate = of_pwm_xlate_with_flags; + pc->chip.of_pwm_n_cells = 3; pc->chip.base = -1; pc->chip.npwm = 1; @@ -231,14 +243,40 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev) } pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + status = pwmss_submodule_state_change(pdev->dev.parent, + PWMSS_ECAPCLK_EN); + if (!(status & PWMSS_ECAPCLK_EN_ACK)) { + dev_err(&pdev->dev, "PWMSS config space clock enable failed\n"); + ret = -EINVAL; + goto pwmss_clk_failure; + } + + pm_runtime_put_sync(&pdev->dev); + platform_set_drvdata(pdev, pc); return 0; + +pwmss_clk_failure: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pwmchip_remove(&pc->chip); + return ret; } static int __devexit ecap_pwm_remove(struct platform_device *pdev) { struct ecap_pwm_chip *pc = platform_get_drvdata(pdev); + pm_runtime_get_sync(&pdev->dev); + /* + * Due to hardware misbehaviour, acknowledge of the stop_req + * is missing. Hence checking of the status bit skipped. + */ + pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return pwmchip_remove(&pc->chip); @@ -246,7 +284,9 @@ static int __devexit ecap_pwm_remove(struct platform_device *pdev) static struct platform_driver ecap_pwm_driver = { .driver = { - .name = "ecap", + .name = "ecap", + .owner = THIS_MODULE, + .of_match_table = ecap_of_match, }, .probe = ecap_pwm_probe, .remove = __devexit_p(ecap_pwm_remove), -- cgit v0.10.2 From 3db9b76d7b6aa6eee1f9be83cf807e531e74bf4f Mon Sep 17 00:00:00 2001 From: "Philip, Avinash" Date: Tue, 27 Nov 2012 14:18:10 +0530 Subject: pwm: pwm-tiecap: pinctrl support Enable pinctrl for pwm-tiecap if pinctrl driver available, else bail out with warning message. Signed-off-by: Philip, Avinash Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 0f541c5..b4f9d47 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "pwm-tipwmss.h" @@ -200,6 +201,11 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev) struct clk *clk; struct ecap_pwm_chip *pc; u16 status; + struct pinctrl *pinctrl; + + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, "unable to select pin group\n"); pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); if (!pc) { -- cgit v0.10.2 From d91861dafda44d808272f55758ca91d962feda6e Mon Sep 17 00:00:00 2001 From: "Philip, Avinash" Date: Tue, 27 Nov 2012 14:18:12 +0530 Subject: pwm: pwm-tiehrpwm: Adding TBCLK gating support. Some platforms (like AM33XX) requires clock gating from control module explicitly for TBCLK. Enabling of this clock required for the functioning of the time base sub module in EHRPWM module. Adding support for handling by enabling the clock on PWM device enable & disable on PWM device disable. Platforms don't have explicit TBCLK gating has to add dummy TBCLK node. Signed-off-by: Philip, Avinash Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index d3c1dff..565f96a 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -115,6 +115,7 @@ struct ehrpwm_pwm_chip { void __iomem *mmio_base; unsigned long period_cycles[NUM_PWM_CHANNEL]; enum pwm_polarity polarity[NUM_PWM_CHANNEL]; + struct clk *tbclk; }; static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip) @@ -335,6 +336,9 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) /* Channels polarity can be configured from action qualifier module */ configure_polarity(pc, pwm->hwpwm); + /* Enable TBCLK before enabling PWM device */ + clk_enable(pc->tbclk); + /* Enable time counter for free_run */ ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); return 0; @@ -363,6 +367,9 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); + /* Disabling TBCLK on PWM disable */ + clk_disable(pc->tbclk); + /* Stop Time base counter */ ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT); @@ -432,6 +439,13 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev) if (!pc->mmio_base) return -EADDRNOTAVAIL; + /* Acquire tbclk for Time Base EHRPWM submodule */ + pc->tbclk = devm_clk_get(&pdev->dev, "tbclk"); + if (IS_ERR(pc->tbclk)) { + dev_err(&pdev->dev, "Failed to get tbclk\n"); + return PTR_ERR(pc->tbclk); + } + ret = pwmchip_add(&pc->chip); if (ret < 0) { dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); -- cgit v0.10.2 From 53ad9e8d37031397ee141f9bf701c0fba4257b0f Mon Sep 17 00:00:00 2001 From: "Philip, Avinash" Date: Tue, 27 Nov 2012 14:18:13 +0530 Subject: pwm: tiehrpwm: Add device-tree binding This patch 1. Add support for device-tree binding for EHRWPM driver. 2. Set size of pwm-cells set to 3 to support PWM channel number, PWM period & polarity configuration from device tree. 3. Add enable/disable clock gating in PWM subsystem common config space. 4. When here set .owner member in platform_driver structure to THIS_MODULE. Signed-off-by: Philip, Avinash Cc: Grant Likely Cc: Rob Herring Cc: Rob Landley Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt new file mode 100644 index 0000000..4fc7079 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt @@ -0,0 +1,23 @@ +TI SOC EHRPWM based PWM controller + +Required properties: +- compatible : Must be "ti,am33xx-ehrpwm" +- #pwm-cells: Should be 3. Number of cells being used to specify PWM property. + First cell specifies the per-chip index of the PWM to use, the second + cell is the period in nanoseconds and bit 0 in the third cell is used to + encode the polarity of PWM output. Set bit 0 of the third in PWM specifier + to 1 for inverse polarity & set to 0 for normal polarity. +- reg: physical base address and size of the registers map. + +Optional properties: +- ti,hwmods: Name of the hwmod associated to the EHRPWM: + "ehrpwm", being the 0-based instance number from the HW spec + +Example: + +ehrpwm0: ehrpwm@0 { + compatible = "ti,am33xx-ehrpwm"; + #pwm-cells = <3>; + reg = <0x48300200 0x100>; + ti,hwmods = "ehrpwm0"; +}; diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 565f96a..ee7a8b3 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -25,6 +25,9 @@ #include #include #include +#include + +#include "pwm-tipwmss.h" /* EHRPWM registers and bits definitions */ @@ -399,12 +402,19 @@ static const struct pwm_ops ehrpwm_pwm_ops = { .owner = THIS_MODULE, }; +static const struct of_device_id ehrpwm_of_match[] = { + { .compatible = "ti,am33xx-ehrpwm" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ehrpwm_of_match); + static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev) { int ret; struct resource *r; struct clk *clk; struct ehrpwm_pwm_chip *pc; + u16 status; pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); if (!pc) { @@ -426,6 +436,8 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev) pc->chip.dev = &pdev->dev; pc->chip.ops = &ehrpwm_pwm_ops; + pc->chip.of_xlate = of_pwm_xlate_with_flags; + pc->chip.of_pwm_n_cells = 3; pc->chip.base = -1; pc->chip.npwm = NUM_PWM_CHANNEL; @@ -453,14 +465,40 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev) } pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + status = pwmss_submodule_state_change(pdev->dev.parent, + PWMSS_EPWMCLK_EN); + if (!(status & PWMSS_EPWMCLK_EN_ACK)) { + dev_err(&pdev->dev, "PWMSS config space clock enable failed\n"); + ret = -EINVAL; + goto pwmss_clk_failure; + } + + pm_runtime_put_sync(&pdev->dev); + platform_set_drvdata(pdev, pc); return 0; + +pwmss_clk_failure: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pwmchip_remove(&pc->chip); + return ret; } static int __devexit ehrpwm_pwm_remove(struct platform_device *pdev) { struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev); + pm_runtime_get_sync(&pdev->dev); + /* + * Due to hardware misbehaviour, acknowledge of the stop_req + * is missing. Hence checking of the status bit skipped. + */ + pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EPWMCLK_STOP_REQ); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return pwmchip_remove(&pc->chip); @@ -468,7 +506,9 @@ static int __devexit ehrpwm_pwm_remove(struct platform_device *pdev) static struct platform_driver ehrpwm_pwm_driver = { .driver = { - .name = "ehrpwm", + .name = "ehrpwm", + .owner = THIS_MODULE, + .of_match_table = ehrpwm_of_match, }, .probe = ehrpwm_pwm_probe, .remove = __devexit_p(ehrpwm_pwm_remove), -- cgit v0.10.2 From 98ccf49daf3bd626196814e38ec8d2460e0d4517 Mon Sep 17 00:00:00 2001 From: "Philip, Avinash" Date: Tue, 27 Nov 2012 14:18:14 +0530 Subject: pwm: pwm-tiehrpwm: pinctrl support Enable pinctrl for pwm-tiehrpwm if pinctrl driver available, else bail out with warning message. Signed-off-by: Philip, Avinash Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index ee7a8b3..542d5f3 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "pwm-tipwmss.h" @@ -415,6 +416,11 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev) struct clk *clk; struct ehrpwm_pwm_chip *pc; u16 status; + struct pinctrl *pinctrl; + + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, "unable to select pin group\n"); pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); if (!pc) { -- cgit v0.10.2 From 3744c26386971db1c7ecf5aa5900882deae60492 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 27 Nov 2012 11:09:57 +0100 Subject: pwm: New driver to support PWMs on TWL4030/6030 series of PMICs The driver supports the following PWM outputs: TWL4030 PWM0 and PWM1 TWL6030 PWM1 and PWM2 On TWL4030 the PWM signals are muxed. Upon requesting the PWM the driver will select the correct mux so the PWM can be used. When the PWM has been freed the original configuration is going to be restored. Signed-off-by: Peter Ujfalusi Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt b/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt new file mode 100644 index 0000000..2943ee5 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt @@ -0,0 +1,17 @@ +Texas Instruments TWL series PWM drivers + +Supported PWMs: +On TWL4030 series: PWM1 and PWM2 +On TWL6030 series: PWM0 and PWM1 + +Required properties: +- compatible: "ti,twl4030-pwm" or "ti,twl6030-pwm" +- #pwm-cells: should be 2. The first cell specifies the per-chip index + of the PWM to use and the second cell is the period in nanoseconds. + +Example: + +twl_pwm: pwm { + compatible = "ti,twl6030-pwm"; + #pwm-cells = <2>; +}; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 3dcb76d..e1792d5 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -173,6 +173,15 @@ config PWM_TWL6030 To compile this driver as a module, choose M here: the module will be called pwm-twl6030. +config PWM_TWL + tristate "TWL4030/6030 PWM support" + depends on TWL4030_CORE + help + Generic PWM framework driver for TWL4030/6030. + + To compile this driver as a module, choose M here: the module + will be called pwm-twl. + config PWM_VT8500 tristate "vt8500 pwm support" depends on ARCH_VT8500 diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 4fb39f8..3b7efa7 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -14,4 +14,5 @@ obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o +obj-$(CONFIG_PWM_TWL) += pwm-twl.o obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c new file mode 100644 index 0000000..e65db95 --- /dev/null +++ b/drivers/pwm/pwm-twl.c @@ -0,0 +1,359 @@ +/* + * Driver for TWL4030/6030 Generic Pulse Width Modulator + * + * Copyright (C) 2012 Texas Instruments + * Author: Peter Ujfalusi + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include + +/* + * This driver handles the PWMs of TWL4030 and TWL6030. + * The TRM names for the PWMs on TWL4030 are: PWM0, PWM1 + * TWL6030 also have two PWMs named in the TRM as PWM1, PWM2 + */ + +#define TWL_PWM_MAX 0x7f + +/* Registers, bits and macro for TWL4030 */ +#define TWL4030_GPBR1_REG 0x0c +#define TWL4030_PMBR1_REG 0x0d + +/* GPBR1 register bits */ +#define TWL4030_PWMXCLK_ENABLE (1 << 0) +#define TWL4030_PWMX_ENABLE (1 << 2) +#define TWL4030_PWMX_BITS (TWL4030_PWMX_ENABLE | TWL4030_PWMXCLK_ENABLE) +#define TWL4030_PWM_TOGGLE(pwm, x) ((x) << (pwm)) + +/* PMBR1 register bits */ +#define TWL4030_GPIO6_PWM0_MUTE_MASK (0x03 << 2) +#define TWL4030_GPIO6_PWM0_MUTE_PWM0 (0x01 << 2) +#define TWL4030_GPIO7_VIBRASYNC_PWM1_MASK (0x03 << 4) +#define TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1 (0x03 << 4) + +/* Register, bits and macro for TWL6030 */ +#define TWL6030_TOGGLE3_REG 0x92 + +#define TWL6030_PWMXR (1 << 0) +#define TWL6030_PWMXS (1 << 1) +#define TWL6030_PWMXEN (1 << 2) +#define TWL6030_PWM_TOGGLE(pwm, x) ((x) << (pwm * 3)) + +struct twl_pwm_chip { + struct pwm_chip chip; + struct mutex mutex; + u8 twl6030_toggle3; + u8 twl4030_pwm_mux; +}; + +static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip) +{ + return container_of(chip, struct twl_pwm_chip, chip); +} + +static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + int duty_cycle = DIV_ROUND_UP(duty_ns * TWL_PWM_MAX, period_ns) + 1; + u8 pwm_config[2] = { 1, 0 }; + int base, ret; + + /* + * To configure the duty period: + * On-cycle is set to 1 (the minimum allowed value) + * The off time of 0 is not configurable, so the mapping is: + * 0 -> off cycle = 2, + * 1 -> off cycle = 2, + * 2 -> off cycle = 3, + * 126 - > off cycle 127, + * 127 - > off cycle 1 + * When on cycle == off cycle the PWM will be always on + */ + if (duty_cycle == 1) + duty_cycle = 2; + else if (duty_cycle > TWL_PWM_MAX) + duty_cycle = 1; + + base = pwm->hwpwm * 3; + + pwm_config[1] = duty_cycle; + + ret = twl_i2c_write(TWL_MODULE_PWM, pwm_config, base, 2); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label); + + return ret; +} + +static int twl4030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct twl_pwm_chip *twl = to_twl(chip); + int ret; + u8 val; + + mutex_lock(&twl->mutex); + ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label); + goto out; + } + + val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE); + + ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label); + + val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE); + + ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label); + +out: + mutex_unlock(&twl->mutex); + return ret; +} + +static void twl4030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct twl_pwm_chip *twl = to_twl(chip); + int ret; + u8 val; + + mutex_lock(&twl->mutex); + ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label); + goto out; + } + + val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE); + + ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); + + val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE); + + ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); + +out: + mutex_unlock(&twl->mutex); +} + +static int twl4030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct twl_pwm_chip *twl = to_twl(chip); + int ret; + u8 val, mask, bits; + + if (pwm->hwpwm == 1) { + mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK; + bits = TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1; + } else { + mask = TWL4030_GPIO6_PWM0_MUTE_MASK; + bits = TWL4030_GPIO6_PWM0_MUTE_PWM0; + } + + mutex_lock(&twl->mutex); + ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label); + goto out; + } + + /* Save the current MUX configuration for the PWM */ + twl->twl4030_pwm_mux &= ~mask; + twl->twl4030_pwm_mux |= (val & mask); + + /* Select PWM functionality */ + val &= ~mask; + val |= bits; + + ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label); + +out: + mutex_unlock(&twl->mutex); + return ret; +} + +static void twl4030_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip, + chip); + int ret; + u8 val, mask; + + if (pwm->hwpwm == 1) + mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK; + else + mask = TWL4030_GPIO6_PWM0_MUTE_MASK; + + mutex_lock(&twl->mutex); + ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label); + goto out; + } + + /* Restore the MUX configuration for the PWM */ + val &= ~mask; + val |= (twl->twl4030_pwm_mux & mask); + + ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label); + +out: + mutex_unlock(&twl->mutex); +} + +static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip, + chip); + int ret; + u8 val; + + mutex_lock(&twl->mutex); + val = twl->twl6030_toggle3; + val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN); + val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR); + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label); + goto out; + } + + twl->twl6030_toggle3 = val; +out: + mutex_unlock(&twl->mutex); + return 0; +} + +static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip, + chip); + int ret; + u8 val; + + mutex_lock(&twl->mutex); + val = twl->twl6030_toggle3; + val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR); + val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN); + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read TOGGLE3\n", pwm->label); + goto out; + } + + val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN); + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); + goto out; + } + + twl->twl6030_toggle3 = val; +out: + mutex_unlock(&twl->mutex); +} + +static const struct pwm_ops twl4030_pwm_ops = { + .config = twl_pwm_config, + .enable = twl4030_pwm_enable, + .disable = twl4030_pwm_disable, + .request = twl4030_pwm_request, + .free = twl4030_pwm_free, +}; + +static const struct pwm_ops twl6030_pwm_ops = { + .config = twl_pwm_config, + .enable = twl6030_pwm_enable, + .disable = twl6030_pwm_disable, +}; + +static int twl_pwm_probe(struct platform_device *pdev) +{ + struct twl_pwm_chip *twl; + int ret; + + twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL); + if (!twl) + return -ENOMEM; + + if (twl_class_is_4030()) + twl->chip.ops = &twl4030_pwm_ops; + else + twl->chip.ops = &twl6030_pwm_ops; + + twl->chip.dev = &pdev->dev; + twl->chip.base = -1; + twl->chip.npwm = 2; + + mutex_init(&twl->mutex); + + ret = pwmchip_add(&twl->chip); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, twl); + + return 0; +} + +static int twl_pwm_remove(struct platform_device *pdev) +{ + struct twl_pwm_chip *twl = platform_get_drvdata(pdev); + + return pwmchip_remove(&twl->chip); +} + +#ifdef CONFIG_OF +static struct of_device_id twl_pwm_of_match[] = { + { .compatible = "ti,twl4030-pwm" }, + { .compatible = "ti,twl6030-pwm" }, + { }, +}; +MODULE_DEVICE_TABLE(of, twl_pwm_of_match); +#endif + +static struct platform_driver twl_pwm_driver = { + .driver = { + .name = "twl-pwm", + .of_match_table = of_match_ptr(twl_pwm_of_match), + }, + .probe = twl_pwm_probe, + .remove = twl_pwm_remove, +}; +module_platform_driver(twl_pwm_driver); + +MODULE_AUTHOR("Peter Ujfalusi "); +MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030"); +MODULE_ALIAS("platform:twl-pwm"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From aa7656471df6cad1a4ed82ba888a40e9bc46aa19 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 27 Nov 2012 11:09:58 +0100 Subject: pwm: New driver to support PWM driven LEDs on TWL4030/6030 series of PMICs The driver supports the following LED outputs as generic PWM driver: TWL4030 LEDA and LEDB (PWMA and PWMB) TWL6030 Charging indicator LED (PWM LED) On TWL6030 when the PWM requested LED is configured to be controlled by SW. In this case the user can enable/disable and set the duty period freely. When the PWM has been freed, the LED driver is put back to HW control. Signed-off-by: Peter Ujfalusi Signed-off-by: Thierry Reding diff --git a/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt b/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt new file mode 100644 index 0000000..cb64f3a --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt @@ -0,0 +1,17 @@ +Texas Instruments TWL series PWM drivers connected to LED terminals + +Supported PWMs: +On TWL4030 series: PWMA and PWMB (connected to LEDA and LEDB terminals) +On TWL6030 series: LED PWM (mainly used as charging indicator LED) + +Required properties: +- compatible: "ti,twl4030-pwmled" or "ti,twl6030-pwmled" +- #pwm-cells: should be 2. The first cell specifies the per-chip index + of the PWM to use and the second cell is the period in nanoseconds. + +Example: + +twl_pwmled: pwmled { + compatible = "ti,twl6030-pwmled"; + #pwm-cells = <2>; +}; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index e1792d5..fe788a7 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -182,6 +182,15 @@ config PWM_TWL To compile this driver as a module, choose M here: the module will be called pwm-twl. +config PWM_TWL_LED + tristate "TWL4030/6030 PWM support for LED drivers" + depends on TWL4030_CORE + help + Generic PWM framework driver for TWL4030/6030 LED terminals. + + To compile this driver as a module, choose M here: the module + will be called pwm-twl-led. + config PWM_VT8500 tristate "vt8500 pwm support" depends on ARCH_VT8500 diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 3b7efa7..4b10133 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -15,4 +15,5 @@ obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o obj-$(CONFIG_PWM_TWL) += pwm-twl.o +obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c new file mode 100644 index 0000000..9dfa0f3 --- /dev/null +++ b/drivers/pwm/pwm-twl-led.c @@ -0,0 +1,344 @@ +/* + * Driver for TWL4030/6030 Pulse Width Modulator used as LED driver + * + * Copyright (C) 2012 Texas Instruments + * Author: Peter Ujfalusi + * + * This driver is a complete rewrite of the former pwm-twl6030.c authorded by: + * Hemanth V + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include + +/* + * This driver handles the PWM driven LED terminals of TWL4030 and TWL6030. + * To generate the signal on TWL4030: + * - LEDA uses PWMA + * - LEDB uses PWMB + * TWL6030 has one LED pin with dedicated LEDPWM + */ + +#define TWL4030_LED_MAX 0x7f +#define TWL6030_LED_MAX 0xff + +/* Registers, bits and macro for TWL4030 */ +#define TWL4030_LEDEN_REG 0x00 +#define TWL4030_PWMA_REG 0x01 + +#define TWL4030_LEDXON (1 << 0) +#define TWL4030_LEDXPWM (1 << 4) +#define TWL4030_LED_PINS (TWL4030_LEDXON | TWL4030_LEDXPWM) +#define TWL4030_LED_TOGGLE(led, x) ((x) << (led)) + +/* Register, bits and macro for TWL6030 */ +#define TWL6030_LED_PWM_CTRL1 0xf4 +#define TWL6030_LED_PWM_CTRL2 0xf5 + +#define TWL6040_LED_MODE_HW 0x00 +#define TWL6040_LED_MODE_ON 0x01 +#define TWL6040_LED_MODE_OFF 0x02 +#define TWL6040_LED_MODE_MASK 0x03 + +struct twl_pwmled_chip { + struct pwm_chip chip; + struct mutex mutex; +}; + +static inline struct twl_pwmled_chip *to_twl(struct pwm_chip *chip) +{ + return container_of(chip, struct twl_pwmled_chip, chip); +} + +static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + int duty_cycle = DIV_ROUND_UP(duty_ns * TWL4030_LED_MAX, period_ns) + 1; + u8 pwm_config[2] = { 1, 0 }; + int base, ret; + + /* + * To configure the duty period: + * On-cycle is set to 1 (the minimum allowed value) + * The off time of 0 is not configurable, so the mapping is: + * 0 -> off cycle = 2, + * 1 -> off cycle = 2, + * 2 -> off cycle = 3, + * 126 - > off cycle 127, + * 127 - > off cycle 1 + * When on cycle == off cycle the PWM will be always on + */ + if (duty_cycle == 1) + duty_cycle = 2; + else if (duty_cycle > TWL4030_LED_MAX) + duty_cycle = 1; + + base = pwm->hwpwm * 2 + TWL4030_PWMA_REG; + + pwm_config[1] = duty_cycle; + + ret = twl_i2c_write(TWL4030_MODULE_LED, pwm_config, base, 2); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label); + + return ret; +} + +static int twl4030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct twl_pwmled_chip *twl = to_twl(chip); + int ret; + u8 val; + + mutex_lock(&twl->mutex); + ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label); + goto out; + } + + val |= TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS); + + ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label); + +out: + mutex_unlock(&twl->mutex); + return ret; +} + +static void twl4030_pwmled_disable(struct pwm_chip *chip, + struct pwm_device *pwm) +{ + struct twl_pwmled_chip *twl = to_twl(chip); + int ret; + u8 val; + + mutex_lock(&twl->mutex); + ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label); + goto out; + } + + val &= ~TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS); + + ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); + +out: + mutex_unlock(&twl->mutex); +} + +static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + int duty_cycle = (duty_ns * TWL6030_LED_MAX) / period_ns; + u8 on_time; + int ret; + + on_time = duty_cycle & 0xff; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, on_time, + TWL6030_LED_PWM_CTRL1); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label); + + return ret; +} + +static int twl6030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct twl_pwmled_chip *twl = to_twl(chip); + int ret; + u8 val; + + mutex_lock(&twl->mutex); + ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n", + pwm->label); + goto out; + } + + val &= ~TWL6040_LED_MODE_MASK; + val |= TWL6040_LED_MODE_ON; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label); + +out: + mutex_unlock(&twl->mutex); + return ret; +} + +static void twl6030_pwmled_disable(struct pwm_chip *chip, + struct pwm_device *pwm) +{ + struct twl_pwmled_chip *twl = to_twl(chip); + int ret; + u8 val; + + mutex_lock(&twl->mutex); + ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n", + pwm->label); + goto out; + } + + val &= ~TWL6040_LED_MODE_MASK; + val |= TWL6040_LED_MODE_OFF; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label); + +out: + mutex_unlock(&twl->mutex); +} + +static int twl6030_pwmled_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct twl_pwmled_chip *twl = to_twl(chip); + int ret; + u8 val; + + mutex_lock(&twl->mutex); + ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n", + pwm->label); + goto out; + } + + val &= ~TWL6040_LED_MODE_MASK; + val |= TWL6040_LED_MODE_OFF; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label); + +out: + mutex_unlock(&twl->mutex); + return ret; +} + +static void twl6030_pwmled_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct twl_pwmled_chip *twl = to_twl(chip); + int ret; + u8 val; + + mutex_lock(&twl->mutex); + ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n", + pwm->label); + goto out; + } + + val &= ~TWL6040_LED_MODE_MASK; + val |= TWL6040_LED_MODE_HW; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2); + if (ret < 0) + dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label); + +out: + mutex_unlock(&twl->mutex); +} + +static const struct pwm_ops twl4030_pwmled_ops = { + .enable = twl4030_pwmled_enable, + .disable = twl4030_pwmled_disable, + .config = twl4030_pwmled_config, +}; + +static const struct pwm_ops twl6030_pwmled_ops = { + .enable = twl6030_pwmled_enable, + .disable = twl6030_pwmled_disable, + .config = twl6030_pwmled_config, + .request = twl6030_pwmled_request, + .free = twl6030_pwmled_free, +}; + +static int twl_pwmled_probe(struct platform_device *pdev) +{ + struct twl_pwmled_chip *twl; + int ret; + + twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL); + if (!twl) + return -ENOMEM; + + if (twl_class_is_4030()) { + twl->chip.ops = &twl4030_pwmled_ops; + twl->chip.npwm = 2; + } else { + twl->chip.ops = &twl6030_pwmled_ops; + twl->chip.npwm = 1; + } + + twl->chip.dev = &pdev->dev; + twl->chip.base = -1; + + mutex_init(&twl->mutex); + + ret = pwmchip_add(&twl->chip); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, twl); + + return 0; +} + +static int twl_pwmled_remove(struct platform_device *pdev) +{ + struct twl_pwmled_chip *twl = platform_get_drvdata(pdev); + + return pwmchip_remove(&twl->chip); +} + +#ifdef CONFIG_OF +static struct of_device_id twl_pwmled_of_match[] = { + { .compatible = "ti,twl4030-pwmled" }, + { .compatible = "ti,twl6030-pwmled" }, + { }, +}; +MODULE_DEVICE_TABLE(of, twl_pwmled_of_match); +#endif + +static struct platform_driver twl_pwmled_driver = { + .driver = { + .name = "twl-pwmled", + .of_match_table = of_match_ptr(twl_pwmled_of_match), + }, + .probe = twl_pwmled_probe, + .remove = twl_pwmled_remove, +}; +module_platform_driver(twl_pwmled_driver); + +MODULE_AUTHOR("Peter Ujfalusi "); +MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030 LED outputs"); +MODULE_ALIAS("platform:twl-pwmled"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 6179a58ec7e26dad1bc262762e322dffb875152b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 27 Nov 2012 11:09:59 +0100 Subject: pwm: Remove pwm-twl6030 driver This driver only supported the Charging indicator LED. New set of drivers going to provide support for both PWMs and LEDs for twl4030 and twl6030 series of PMICs. Signed-off-by: Peter Ujfalusi Signed-off-by: Thierry Reding diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index fe788a7..e513cd9 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -164,15 +164,6 @@ config PWM_TIPWMSS PWM submodules require PWM config space access from submodule drivers and require common parent driver support. -config PWM_TWL6030 - tristate "TWL6030 PWM support" - depends on TWL4030_CORE - help - Generic PWM framework driver for TWL6030. - - To compile this driver as a module, choose M here: the module - will be called pwm-twl6030. - config PWM_TWL tristate "TWL4030/6030 PWM support" depends on TWL4030_CORE diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 4b10133..62a2963 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o -obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o obj-$(CONFIG_PWM_TWL) += pwm-twl.o obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o diff --git a/drivers/pwm/pwm-twl6030.c b/drivers/pwm/pwm-twl6030.c deleted file mode 100644 index 8e63878..0000000 --- a/drivers/pwm/pwm-twl6030.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * twl6030_pwm.c - * Driver for PHOENIX (TWL6030) Pulse Width Modulator - * - * Copyright (C) 2010 Texas Instruments - * Author: Hemanth V - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -#include -#include -#include -#include -#include - -#define LED_PWM_CTRL1 0xF4 -#define LED_PWM_CTRL2 0xF5 - -/* Max value for CTRL1 register */ -#define PWM_CTRL1_MAX 255 - -/* Pull down disable */ -#define PWM_CTRL2_DIS_PD (1 << 6) - -/* Current control 2.5 milli Amps */ -#define PWM_CTRL2_CURR_02 (2 << 4) - -/* LED supply source */ -#define PWM_CTRL2_SRC_VAC (1 << 2) - -/* LED modes */ -#define PWM_CTRL2_MODE_HW (0 << 0) -#define PWM_CTRL2_MODE_SW (1 << 0) -#define PWM_CTRL2_MODE_DIS (2 << 0) - -#define PWM_CTRL2_MODE_MASK 0x3 - -struct twl6030_pwm_chip { - struct pwm_chip chip; -}; - -static int twl6030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) -{ - int ret; - u8 val; - - /* Configure PWM */ - val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC | - PWM_CTRL2_MODE_HW; - - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); - if (ret < 0) { - dev_err(chip->dev, "%s: Failed to configure PWM, Error %d\n", - pwm->label, ret); - return ret; - } - - return 0; -} - -static int twl6030_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) -{ - u8 duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns; - int ret; - - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1); - if (ret < 0) { - pr_err("%s: Failed to configure PWM, Error %d\n", - pwm->label, ret); - return ret; - } - - return 0; -} - -static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - int ret; - u8 val; - - ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); - if (ret < 0) { - dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n", - pwm->label, ret); - return ret; - } - - /* Change mode to software control */ - val &= ~PWM_CTRL2_MODE_MASK; - val |= PWM_CTRL2_MODE_SW; - - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); - if (ret < 0) { - dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n", - pwm->label, ret); - return ret; - } - - twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); - return 0; -} - -static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - int ret; - u8 val; - - ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); - if (ret < 0) { - dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", - pwm->label, ret); - return; - } - - val &= ~PWM_CTRL2_MODE_MASK; - val |= PWM_CTRL2_MODE_HW; - - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); - if (ret < 0) { - dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", - pwm->label, ret); - } -} - -static const struct pwm_ops twl6030_pwm_ops = { - .request = twl6030_pwm_request, - .config = twl6030_pwm_config, - .enable = twl6030_pwm_enable, - .disable = twl6030_pwm_disable, -}; - -static int twl6030_pwm_probe(struct platform_device *pdev) -{ - struct twl6030_pwm_chip *twl6030; - int ret; - - twl6030 = devm_kzalloc(&pdev->dev, sizeof(*twl6030), GFP_KERNEL); - if (!twl6030) - return -ENOMEM; - - twl6030->chip.dev = &pdev->dev; - twl6030->chip.ops = &twl6030_pwm_ops; - twl6030->chip.base = -1; - twl6030->chip.npwm = 1; - - ret = pwmchip_add(&twl6030->chip); - if (ret < 0) - return ret; - - platform_set_drvdata(pdev, twl6030); - - return 0; -} - -static int twl6030_pwm_remove(struct platform_device *pdev) -{ - struct twl6030_pwm_chip *twl6030 = platform_get_drvdata(pdev); - - return pwmchip_remove(&twl6030->chip); -} - -static struct platform_driver twl6030_pwm_driver = { - .driver = { - .name = "twl6030-pwm", - }, - .probe = twl6030_pwm_probe, - .remove = __devexit_p(twl6030_pwm_remove), -}; -module_platform_driver(twl6030_pwm_driver); - -MODULE_ALIAS("platform:twl6030-pwm"); -MODULE_LICENSE("GPL"); -- cgit v0.10.2 From bb7c4deb82c2f0b278cdf45a392a3ed9479cdbbe Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 23 Nov 2012 14:31:09 -0700 Subject: ARM64: dma_debug: add debug_dma_mapping_error support Add dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. Signed-off-by: Shuah Khan Acked-by: Catalin Marinas Signed-off-by: Joerg Roedel diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index 538f4b4..9947768 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -50,6 +50,7 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) static inline int dma_mapping_error(struct device *dev, dma_addr_t dev_addr) { struct dma_map_ops *ops = get_dma_ops(dev); + debug_dma_mapping_error(dev, dev_addr); return ops->mapping_error(dev, dev_addr); } -- cgit v0.10.2 From ad154880c03daf1f776e502e2c18775eda4280d2 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 23 Nov 2012 14:32:06 -0700 Subject: c6x: dma_debug: add debug_dma_mapping_error support Add dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. Signed-off-by: Shuah Khan Acked-by: Mark Salter Signed-off-by: Joerg Roedel diff --git a/arch/c6x/include/asm/dma-mapping.h b/arch/c6x/include/asm/dma-mapping.h index 03579fd..3c69406 100644 --- a/arch/c6x/include/asm/dma-mapping.h +++ b/arch/c6x/include/asm/dma-mapping.h @@ -32,6 +32,7 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask) */ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { + debug_dma_mapping_error(dev, dma_addr); return dma_addr == ~0; } -- cgit v0.10.2 From 27fa0ab66f17e49a59fbca272f8c1cfab7c5fe81 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 23 Nov 2012 14:32:55 -0700 Subject: ia64: dma_debug: add debug_dma_mapping_error support Add dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index 4f5e814..cf3ab7e 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -58,6 +58,7 @@ static inline void dma_free_attrs(struct device *dev, size_t size, static inline int dma_mapping_error(struct device *dev, dma_addr_t daddr) { struct dma_map_ops *ops = platform_dma_get_ops(dev); + debug_dma_mapping_error(dev, daddr); return ops->mapping_error(dev, daddr); } -- cgit v0.10.2 From e728fa18eba8bcbf1f2c4aeb21b6304a16f2f9e4 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 23 Nov 2012 14:33:42 -0700 Subject: microblaze: dma-mapping: support debug_dma_mapping_error Add support for debug_dma_mapping_error() call to avoid warning from debug_dma_unmap() interface when it checks for mapping error checked status. Without this patch, device driver failed to check map error warning is generated. Signed-off-by: Shuah Khan Acked-by: Michal Simek Signed-off-by: Joerg Roedel diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h index 01d2282..46460f1 100644 --- a/arch/microblaze/include/asm/dma-mapping.h +++ b/arch/microblaze/include/asm/dma-mapping.h @@ -114,6 +114,8 @@ static inline void __dma_sync(unsigned long paddr, static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *ops = get_dma_ops(dev); + + debug_dma_mapping_error(dev, dma_addr); if (ops->mapping_error) return ops->mapping_error(dev, dma_addr); -- cgit v0.10.2 From 9c83b07c042361c429883b3205cbc96fd19598bd Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 23 Nov 2012 14:34:56 -0700 Subject: mips: dma_debug: add debug_dma_mapping_error support Add dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index be39a12..006b43e 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -40,6 +40,8 @@ static inline int dma_supported(struct device *dev, u64 mask) static inline int dma_mapping_error(struct device *dev, u64 mask) { struct dma_map_ops *ops = get_dma_ops(dev); + + debug_dma_mapping_error(dev, mask); return ops->mapping_error(dev, mask); } -- cgit v0.10.2 From 34daa88efd7ad46237fd1ac7e162611cc3f88acb Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 23 Nov 2012 14:35:36 -0700 Subject: powerpc: dma_debug: add debug_dma_mapping_error support Add dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index 7816087..e27e9ad 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -172,6 +172,7 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *dma_ops = get_dma_ops(dev); + debug_dma_mapping_error(dev, dma_addr); if (dma_ops->mapping_error) return dma_ops->mapping_error(dev, dma_addr); -- cgit v0.10.2 From 50af1e9df2194991280463541bc89c55ca45164a Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 23 Nov 2012 14:36:33 -0700 Subject: sh: dma_debug: add debug_dma_mapping_error support Add dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 8bd965e..b437f2c 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -46,6 +46,7 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *ops = get_dma_ops(dev); + debug_dma_mapping_error(dev, dma_addr); if (ops->mapping_error) return ops->mapping_error(dev, dma_addr); -- cgit v0.10.2 From fd78a95ac662a18e94509b7314c327475cbeafb4 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 23 Nov 2012 14:37:54 -0700 Subject: tile: dma_debug: add debug_dma_mapping_error support Add dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. Signed-off-by: Shuah Khan Signed-off-by: Joerg Roedel diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h index 4b6247d..f2ff191 100644 --- a/arch/tile/include/asm/dma-mapping.h +++ b/arch/tile/include/asm/dma-mapping.h @@ -72,6 +72,7 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { + debug_dma_mapping_error(dev, dma_addr); return get_dma_ops(dev)->mapping_error(dev, dma_addr); } -- cgit v0.10.2 From 37683e45623a0ccd34761c71aad618cc129fe35c Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Wed, 28 Nov 2012 15:52:53 +0200 Subject: iommu/tegra: smmu: Remove unnecessary PTC/TLB flush all smmu_flush_regs() does TLB/PTC flush all when freeing a second level page table. This isn't necessay at all since each pte entry has been already maintained by address in the above flush_ptc_and_tlb(). Signed-off-by: Hiroshi Doyu Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index c0f7a42..48538a6 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -696,10 +696,8 @@ static void __smmu_iommu_unmap(struct smmu_as *as, dma_addr_t iova) *pte = _PTE_VACANT(iova); FLUSH_CPU_DCACHE(pte, page, sizeof(*pte)); flush_ptc_and_tlb(as->smmu, as, iova, pte, page, 0); - if (!--(*count)) { + if (!--(*count)) free_ptbl(as, iova); - smmu_flush_regs(as->smmu, 0); - } } static void __smmu_iommu_map_pfn(struct smmu_as *as, dma_addr_t iova, -- cgit v0.10.2 From b7d4bec11199df6ef3267c5249e2676d0531eae5 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Wed, 28 Nov 2012 15:52:54 +0200 Subject: iommu/tegra: gart: Move bus_set_iommu after probe for multi arch For a single image to support multiple SoCs(GART/SMMU). Reported-by: Arto Merilainen Signed-off-by: Hiroshi Doyu Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index c16e8fc..4c9db62 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -398,6 +398,7 @@ static int tegra_gart_probe(struct platform_device *pdev) do_gart_setup(gart, NULL); gart_handle = gart; + bus_set_iommu(&platform_bus_type, &gart_iommu_ops); return 0; fail: @@ -450,7 +451,6 @@ static struct platform_driver tegra_gart_driver = { static int __devinit tegra_gart_init(void) { - bus_set_iommu(&platform_bus_type, &gart_iommu_ops); return platform_driver_register(&tegra_gart_driver); } -- cgit v0.10.2 From f1bda29c2bfa84c2c022e1f443528e21607bf360 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Wed, 28 Nov 2012 15:52:55 +0200 Subject: iommu/tegra: smmu: Move bus_set_iommu after probe for multi arch For a single image to support multiple SoCs(GART/SMMU). Reported-by: Arto Merilainen Signed-off-by: Hiroshi Doyu Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 48538a6..843123a 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -1232,6 +1232,7 @@ static int tegra_smmu_probe(struct platform_device *pdev) smmu_debugfs_create(smmu); smmu_handle = smmu; + bus_set_iommu(&platform_bus_type, &smmu_iommu_ops); return 0; } @@ -1276,7 +1277,6 @@ static struct platform_driver tegra_smmu_driver = { static int __devinit tegra_smmu_init(void) { - bus_set_iommu(&platform_bus_type, &smmu_iommu_ops); return platform_driver_register(&tegra_smmu_driver); } -- cgit v0.10.2 From dba88ba55a06ff8bef467f2ca3f7904aeab8762a Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 16 Nov 2012 11:45:12 -0500 Subject: nfsd4: remove state lock from nfsd4_load_reboot_recovery_data That function is only called under nfsd_mutex: we know that because the only caller is nfsd_svc, via nfsd_svc nfsd_startup nfs4_state_start nfsd4_client_tracking_init client_tracking_ops->init == nfsd4_load_reboot_recovery_data The shared state accessed here includes: - user_recovery_dirname: used here, modified only by nfs4_reset_recoverydir, which can be verified to only be called under nfsd_mutex. - filesystem state, protected by i_mutex (handwaving slightly here) - rec_file, reclaim_str_hashtbl, reclaim_str_hashtbl_size: other than here, used only from code called from nfsd or laundromat threads, both of which should be started only after this runs (see nfsd_svc) and stopped before this could run again (see nfsd_shutdown, called from nfsd_last_thread). Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index b657b62..651d513 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -509,11 +509,9 @@ nfsd4_load_reboot_recovery_data(struct net *net) { int status; - nfs4_lock_state(); status = nfsd4_init_recdir(); if (!status) status = nfsd4_recdir_load(net); - nfs4_unlock_state(); if (status) printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n"); return status; -- cgit v0.10.2 From ec28e02ca5f2a4287c19c585f8be2d9b3ba123ea Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Wed, 21 Nov 2012 18:07:38 +0300 Subject: nfsd4: remove state lock from nfs4_state_shutdown Protection of __nfs4_state_shutdown() with nfs4_lock_state() looks redundant. This function is called by the last NFSd thread on it's exit and state lock protects actually two functions (del_recall_lru is protected by recall_lock): 1) nfsd4_client_tracking_exit 2) __nfs4_state_shutdown_net "nfsd4_client_tracking_exit" doesn't require state lock protection, because it's state can be modified only by tracker callbacks. Here a re they: 1) create: is called only from nfsd4_proc_compound. 2) remove: is called from either nfsd4_proc_compound or nfs4_laundromat. 3) check: is called only from nfsd4_proc_compound. 4) grace_done; called only from nfs4_laundromat. nfsd4_proc_compound is called onll by NFSd kthread, which is exiting right now. nfs4_laundromat is called by laundry_wq. But laundromat_work was canceled already. "__nfs4_state_shutdown_net" also doesn't require state lock protection, because all NFSd kthreads are dead, and no race can happen with NFSd start, because "nfsd_up" flag is still set. Moreover, all Nfsd shutdown is protected with global nfsd_mutex. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 41d2aed..ffec73c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4930,9 +4930,7 @@ nfs4_state_shutdown(void) cancel_delayed_work_sync(&nn->laundromat_work); destroy_workqueue(laundry_wq); locks_end_grace(&nn->nfsd4_manager); - nfs4_lock_state(); __nfs4_state_shutdown(net); - nfs4_unlock_state(); nfsd4_destroy_callback_queue(); } -- cgit v0.10.2 From c9a4962881929df7f1ef6e63e1b9da304faca4dd Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Nov 2012 15:21:58 +0300 Subject: nfsd: make client_lock per net This lock protects the client lru list and session hash table, which are allocated per network namespace already. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 227b93e..08d5fa1 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -81,6 +81,9 @@ struct nfsd_net { struct list_head close_lru; struct delayed_work laundromat_work; + + /* client_lock protects the client lru list and session hash table */ + spinlock_t client_lock; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ffec73c..0e7e174 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -388,9 +388,6 @@ unhash_delegation(struct nfs4_delegation *dp) * SETCLIENTID state */ -/* client_lock protects the client lru list and session hash table */ -static DEFINE_SPINLOCK(client_lock); - static unsigned int clientid_hashval(u32 id) { return id & CLIENT_HASH_MASK; @@ -872,18 +869,23 @@ static void __free_session(struct nfsd4_session *ses) static void free_session(struct kref *kref) { struct nfsd4_session *ses; + struct nfsd_net *nn; - lockdep_assert_held(&client_lock); ses = container_of(kref, struct nfsd4_session, se_ref); + nn = net_generic(ses->se_client->net, nfsd_net_id); + + lockdep_assert_held(&nn->client_lock); nfsd4_del_conns(ses); __free_session(ses); } void nfsd4_put_session(struct nfsd4_session *ses) { - spin_lock(&client_lock); + struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id); + + spin_lock(&nn->client_lock); nfsd4_put_session_locked(ses); - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); } static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) @@ -927,12 +929,12 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru new->se_cb_sec = cses->cb_sec; kref_init(&new->se_ref); idx = hash_sessionid(&new->se_sessionid); - spin_lock(&client_lock); + spin_lock(&nn->client_lock); list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); spin_lock(&clp->cl_lock); list_add(&new->se_perclnt, &clp->cl_sessions); spin_unlock(&clp->cl_lock); - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); if (cses->flags & SESSION4_BACK_CHAN) { struct sockaddr *sa = svc_addr(rqstp); @@ -1005,9 +1007,11 @@ renew_client_locked(struct nfs4_client *clp) static inline void renew_client(struct nfs4_client *clp) { - spin_lock(&client_lock); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + + spin_lock(&nn->client_lock); renew_client_locked(clp); - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); } /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ @@ -1045,7 +1049,9 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) static inline void free_client(struct nfs4_client *clp) { - lockdep_assert_held(&client_lock); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + + lockdep_assert_held(&nn->client_lock); while (!list_empty(&clp->cl_sessions)) { struct nfsd4_session *ses; ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, @@ -1062,15 +1068,16 @@ void release_session_client(struct nfsd4_session *session) { struct nfs4_client *clp = session->se_client; + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); - if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock)) + if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock)) return; if (is_client_expired(clp)) { free_client(clp); session->se_client = NULL; } else renew_client_locked(clp); - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); } /* must be called under the client_lock */ @@ -1119,11 +1126,11 @@ destroy_client(struct nfs4_client *clp) rb_erase(&clp->cl_namenode, &nn->conf_name_tree); else rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); - spin_lock(&client_lock); + spin_lock(&nn->client_lock); unhash_client_locked(clp); if (atomic_read(&clp->cl_refcount) == 0) free_client(clp); - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); } static void expire_client(struct nfs4_client *clp) @@ -1274,6 +1281,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, struct sockaddr *sa = svc_addr(rqstp); int ret; struct net *net = SVC_NET(rqstp); + struct nfsd_net *nn = net_generic(net, nfsd_net_id); clp = alloc_client(name); if (clp == NULL) @@ -1282,9 +1290,9 @@ static struct nfs4_client *create_client(struct xdr_netobj name, INIT_LIST_HEAD(&clp->cl_sessions); ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); if (ret) { - spin_lock(&client_lock); + spin_lock(&nn->client_lock); free_client(clp); - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); return NULL; } idr_init(&clp->cl_stateids); @@ -1873,11 +1881,12 @@ static __be32 nfsd4_map_bcts_dir(u32 *dir) __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) { struct nfsd4_session *session = cstate->session; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); - spin_lock(&client_lock); + spin_lock(&nn->client_lock); session->se_cb_prog = bc->bc_cb_program; session->se_cb_sec = bc->bc_cb_sec; - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); nfsd4_probe_callback(session->se_client); @@ -1890,10 +1899,11 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, { __be32 status; struct nfsd4_conn *conn; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); if (!nfsd4_last_compound_op(rqstp)) return nfserr_not_only_op; - spin_lock(&client_lock); + spin_lock(&nn->client_lock); cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp)); /* Sorta weird: we only need the refcnt'ing because new_conn acquires * client_lock iself: */ @@ -1901,7 +1911,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, nfsd4_get_session(cstate->session); atomic_inc(&cstate->session->se_client->cl_refcount); } - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); if (!cstate->session) return nfserr_badsession; @@ -1929,6 +1939,7 @@ nfsd4_destroy_session(struct svc_rqst *r, { struct nfsd4_session *ses; __be32 status = nfserr_badsession; + struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); /* Notes: * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid @@ -1942,24 +1953,24 @@ nfsd4_destroy_session(struct svc_rqst *r, return nfserr_not_only_op; } dump_sessionid(__func__, &sessionid->sessionid); - spin_lock(&client_lock); + spin_lock(&nn->client_lock); ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r)); if (!ses) { - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); goto out; } unhash_session(ses); - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); nfs4_lock_state(); nfsd4_probe_callback_sync(ses->se_client); nfs4_unlock_state(); - spin_lock(&client_lock); + spin_lock(&nn->client_lock); nfsd4_del_conns(ses); nfsd4_put_session_locked(ses); - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); status = nfs_ok; out: dprintk("%s returns %d\n", __func__, ntohl(status)); @@ -2025,6 +2036,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_slot *slot; struct nfsd4_conn *conn; __be32 status; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); if (resp->opcnt != 1) return nfserr_sequence_pos; @@ -2037,7 +2049,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, if (!conn) return nfserr_jukebox; - spin_lock(&client_lock); + spin_lock(&nn->client_lock); status = nfserr_badsession; session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp)); if (!session) @@ -2113,7 +2125,7 @@ out: } } kfree(conn); - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); dprintk("%s: return %d\n", __func__, ntohl(status)); return status; } @@ -3191,7 +3203,7 @@ nfs4_laundromat(struct nfsd_net *nn) dprintk("NFSD: laundromat service - starting\n"); nfsd4_end_grace(nn); INIT_LIST_HEAD(&reaplist); - spin_lock(&client_lock); + spin_lock(&nn->client_lock); list_for_each_safe(pos, next, &nn->client_lru) { clp = list_entry(pos, struct nfs4_client, cl_lru); if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { @@ -3208,7 +3220,7 @@ nfs4_laundromat(struct nfsd_net *nn) unhash_client_locked(clp); list_add(&clp->cl_lru, &reaplist); } - spin_unlock(&client_lock); + spin_unlock(&nn->client_lock); list_for_each_safe(pos, next, &reaplist) { clp = list_entry(pos, struct nfs4_client, cl_lru); dprintk("NFSD: purging unused client (clientid %08x)\n", @@ -4796,6 +4808,7 @@ static int nfs4_state_start_net(struct net *net) nn->unconf_name_tree = RB_ROOT; INIT_LIST_HEAD(&nn->client_lru); INIT_LIST_HEAD(&nn->close_lru); + spin_lock_init(&nn->client_lock); INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); -- cgit v0.10.2 From 4e37a7c2075baa2a15a2ab90fcc44173888016ed Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Nov 2012 15:22:03 +0300 Subject: nfsd: make delegations shutdown network namespace aware NFSv4 delegations are stored in global list. But they are nfs4_client dependent, which is network namespace aware already. State shutdown and laundromat are done per network namespace as well. So, delegations unhash have to be done in network namespace context. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0e7e174..bc2fc9f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3230,6 +3230,8 @@ nfs4_laundromat(struct nfsd_net *nn) spin_lock(&recall_lock); list_for_each_safe(pos, next, &del_recall_lru) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); + if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn) + continue; if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { u = dp->dl_time - cutoff; if (test_val > u) @@ -4922,6 +4924,8 @@ __nfs4_state_shutdown(struct net *net) spin_lock(&recall_lock); list_for_each_safe(pos, next, &del_recall_lru) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); + if (dp->dl_stid.sc_client->net != net) + continue; list_move(&dp->dl_recall_lru, &reaplist); } spin_unlock(&recall_lock); -- cgit v0.10.2 From 4dce0ac9069bbebfd34f890f599ccdb92fa76e9f Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Nov 2012 15:22:08 +0300 Subject: nfsd: cleanup NFSd state shutdown a bit This patch renames __nfs4_state_shutdown_net() into nfs4_state_shutdown_net(), __nfs4_state_shutdown() into nfs4_state_shutdown_net() and moves all network related shutdown operations to nfs4_state_shutdown_net(). Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index bc2fc9f..84a27a2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4829,7 +4829,7 @@ err: } static void -__nfs4_state_shutdown_net(struct net *net) +nfs4_state_destroy_net(struct net *net) { int i; struct nfs4_client *clp = NULL; @@ -4857,6 +4857,7 @@ __nfs4_state_shutdown_net(struct net *net) kfree(nn->ownerstr_hashtbl); kfree(nn->unconf_id_hashtbl); kfree(nn->conf_id_hashtbl); + put_net(net); } /* initialization to perform when the nfsd service is started: */ @@ -4906,19 +4907,20 @@ out_free_laundry: destroy_workqueue(laundry_wq); out_recovery: nfsd4_client_tracking_exit(net); - __nfs4_state_shutdown_net(net); - put_net(net); + nfs4_state_destroy_net(net); return ret; } /* should be called with the state lock held */ static void -__nfs4_state_shutdown(struct net *net) +nfs4_state_shutdown_net(struct net *net) { struct nfs4_delegation *dp = NULL; struct list_head *pos, *next, reaplist; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); - __nfs4_state_shutdown_net(net); + cancel_delayed_work_sync(&nn->laundromat_work); + locks_end_grace(&nn->nfsd4_manager); INIT_LIST_HEAD(&reaplist); spin_lock(&recall_lock); @@ -4935,19 +4937,16 @@ __nfs4_state_shutdown(struct net *net) } nfsd4_client_tracking_exit(net); - put_net(net); + nfs4_state_destroy_net(net); } void nfs4_state_shutdown(void) { struct net *net = &init_net; - struct nfsd_net *nn = net_generic(net, nfsd_net_id); - cancel_delayed_work_sync(&nn->laundromat_work); + nfs4_state_shutdown_net(net); destroy_workqueue(laundry_wq); - locks_end_grace(&nn->nfsd4_manager); - __nfs4_state_shutdown(net); nfsd4_destroy_callback_queue(); } -- cgit v0.10.2 From d85ed443052570b25ea4b5f5fa70c57e0129fbc4 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Nov 2012 15:22:13 +0300 Subject: nfsd: cleanup NFSd state start a bit This patch renames nfs4_state_start_net() into nfs4_state_create_net(), where get_net() now performed. Also it introduces new nfs4_state_start_net(), which is now responsible for state creation and initializing all per-net data and which is now called from nfs4_state_start(). Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 84a27a2..6f57986 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4770,7 +4770,7 @@ set_max_delegations(void) max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); } -static int nfs4_state_start_net(struct net *net) +static int nfs4_state_create_net(struct net *net) { struct nfsd_net *nn = net_generic(net, nfsd_net_id); int i; @@ -4813,6 +4813,7 @@ static int nfs4_state_start_net(struct net *net) spin_lock_init(&nn->client_lock); INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); + get_net(net); return 0; @@ -4860,37 +4861,35 @@ nfs4_state_destroy_net(struct net *net) put_net(net); } -/* initialization to perform when the nfsd service is started: */ - -int -nfs4_state_start(void) +static int +nfs4_state_start_net(struct net *net) { - struct net *net = &init_net; struct nfsd_net *nn = net_generic(net, nfsd_net_id); int ret; - /* - * FIXME: For now, we hang most of the pernet global stuff off of - * init_net until nfsd is fully containerized. Eventually, we'll - * need to pass a net pointer into this function, take a reference - * to that instead and then do most of the rest of this on a per-net - * basis. - */ - get_net(net); - ret = nfs4_state_start_net(net); + ret = nfs4_state_create_net(net); if (ret) return ret; nfsd4_client_tracking_init(net); nn->boot_time = get_seconds(); locks_start_grace(net, &nn->nfsd4_manager); nn->grace_ended = false; - printk(KERN_INFO "NFSD: starting %ld-second grace period\n", - nfsd4_grace); + printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", + nfsd4_grace, net); + queue_delayed_work(laundry_wq, &nn->laundromat_work, nfsd4_grace * HZ); + return 0; +} + +/* initialization to perform when the nfsd service is started: */ + +int +nfs4_state_start(void) +{ + int ret; + ret = set_callback_cred(); - if (ret) { - ret = -ENOMEM; - goto out_recovery; - } + if (ret) + return -ENOMEM; laundry_wq = create_singlethread_workqueue("nfsd4"); if (laundry_wq == NULL) { ret = -ENOMEM; @@ -4900,14 +4899,26 @@ nfs4_state_start(void) if (ret) goto out_free_laundry; - queue_delayed_work(laundry_wq, &nn->laundromat_work, nfsd4_grace * HZ); set_max_delegations(); + + /* + * FIXME: For now, we hang most of the pernet global stuff off of + * init_net until nfsd is fully containerized. Eventually, we'll + * need to pass a net pointer into this function, take a reference + * to that instead and then do most of the rest of this on a per-net + * basis. + */ + ret = nfs4_state_start_net(&init_net); + if (ret) + goto out_free_callback; + return 0; + +out_free_callback: + nfsd4_destroy_callback_queue(); out_free_laundry: destroy_workqueue(laundry_wq); out_recovery: - nfsd4_client_tracking_exit(net); - nfs4_state_destroy_net(net); return ret; } -- cgit v0.10.2 From f252bc6806a9428f2e3a429e4cdffbd012de9839 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Nov 2012 15:22:18 +0300 Subject: nfsd: call state init and shutdown twice Split NFSv4 state init and shutdown into two different calls: per-net one and generic one. Per-net cwinit/shutdown pair have to be called for any namespace, generic pair - only once on NSFd kthreads start and shutdown respectively. Refresh of diff-nfsd-call-state-init-twice Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6f57986..fb98f29 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4861,12 +4861,22 @@ nfs4_state_destroy_net(struct net *net) put_net(net); } -static int +int nfs4_state_start_net(struct net *net) { struct nfsd_net *nn = net_generic(net, nfsd_net_id); int ret; + /* + * FIXME: For now, we hang most of the pernet global stuff off of + * init_net until nfsd is fully containerized. Eventually, we'll + * need to pass a net pointer into this function, take a reference + * to that instead and then do most of the rest of this on a per-net + * basis. + */ + if (net != &init_net) + return -EINVAL; + ret = nfs4_state_create_net(net); if (ret) return ret; @@ -4901,21 +4911,8 @@ nfs4_state_start(void) set_max_delegations(); - /* - * FIXME: For now, we hang most of the pernet global stuff off of - * init_net until nfsd is fully containerized. Eventually, we'll - * need to pass a net pointer into this function, take a reference - * to that instead and then do most of the rest of this on a per-net - * basis. - */ - ret = nfs4_state_start_net(&init_net); - if (ret) - goto out_free_callback; - return 0; -out_free_callback: - nfsd4_destroy_callback_queue(); out_free_laundry: destroy_workqueue(laundry_wq); out_recovery: @@ -4923,7 +4920,7 @@ out_recovery: } /* should be called with the state lock held */ -static void +void nfs4_state_shutdown_net(struct net *net) { struct nfs4_delegation *dp = NULL; @@ -4954,9 +4951,6 @@ nfs4_state_shutdown_net(struct net *net) void nfs4_state_shutdown(void) { - struct net *net = &init_net; - - nfs4_state_shutdown_net(net); destroy_workqueue(laundry_wq); nfsd4_destroy_callback_queue(); } diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 80d5ce4..d7b210b 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -121,7 +121,9 @@ void nfs4_state_init(void); int nfsd4_init_slabs(void); void nfsd4_free_slabs(void); int nfs4_state_start(void); +int nfs4_state_start_net(struct net *net); void nfs4_state_shutdown(void); +void nfs4_state_shutdown_net(struct net *net); void nfs4_reset_lease(time_t leasetime); int nfs4_reset_recoverydir(char *recdir); char * nfs4_recoverydir(void); @@ -130,7 +132,9 @@ static inline void nfs4_state_init(void) { } static inline int nfsd4_init_slabs(void) { return 0; } static inline void nfsd4_free_slabs(void) { } static inline int nfs4_state_start(void) { return 0; } +static inline int nfs4_state_start_net(struct net *net) { return 0; } static inline void nfs4_state_shutdown(void) { } +static inline void nfs4_state_shutdown_net(struct net *net) { } static inline void nfs4_reset_lease(time_t leasetime) { } static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } static inline char * nfs4_recoverydir(void) {return NULL; } diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 30d3784..b34a67d8 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -207,6 +207,7 @@ static bool nfsd_up = false; static int nfsd_startup(int nrservs) { int ret; + struct net *net = &init_net; if (nfsd_up) return 0; @@ -221,14 +222,21 @@ static int nfsd_startup(int nrservs) ret = nfsd_init_socks(); if (ret) goto out_racache; - ret = lockd_up(&init_net); + ret = lockd_up(net); if (ret) goto out_racache; ret = nfs4_state_start(); if (ret) goto out_lockd; + + ret = nfs4_state_start_net(net); + if (ret) + goto out_net_state; + nfsd_up = true; return 0; +out_net_state: + nfs4_state_shutdown(); out_lockd: lockd_down(&init_net); out_racache: @@ -238,6 +246,8 @@ out_racache: static void nfsd_shutdown(void) { + struct net *net = &init_net; + /* * write_ports can create the server without actually starting * any threads--if we get shut down before any threads are @@ -246,8 +256,9 @@ static void nfsd_shutdown(void) */ if (!nfsd_up) return; + nfs4_state_shutdown_net(net); nfs4_state_shutdown(); - lockd_down(&init_net); + lockd_down(net); nfsd_racache_shutdown(); nfsd_up = false; } -- cgit v0.10.2 From 3a0733692f6665a28c50ebadb6d9db2b183bcb91 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Nov 2012 16:16:25 +0300 Subject: nfsd: recovery - make rec_file per net Opening and closing of this file is done in client tracking init and exit operations. Client tracking is done in network namespace context already. So let's make this file opened and closed per network context - this will simlify it's management. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 08d5fa1..1305632 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -84,6 +84,8 @@ struct nfsd_net { /* client_lock protects the client lru list and session hash table */ spinlock_t client_lock; + + struct file *rec_file; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 651d513..3e76d28 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -62,7 +62,6 @@ struct nfsd4_client_tracking_ops { }; /* Globals */ -static struct file *rec_file; static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; static struct nfsd4_client_tracking_ops *client_tracking_ops; static bool in_grace; @@ -182,7 +181,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) return; - if (!rec_file) + if (!nn->rec_file) return; status = nfs4_make_rec_clidname(dname, &clp->cl_name); @@ -193,11 +192,11 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) if (status < 0) return; - status = mnt_want_write_file(rec_file); + status = mnt_want_write_file(nn->rec_file); if (status) return; - dir = rec_file->f_path.dentry; + dir = nn->rec_file->f_path.dentry; /* lock the parent */ mutex_lock(&dir->d_inode->i_mutex); @@ -227,14 +226,14 @@ out_unlock: if (crp) crp->cr_clp = clp; } - vfs_fsync(rec_file, 0); + vfs_fsync(nn->rec_file, 0); } else { printk(KERN_ERR "NFSD: failed to write recovery record" " (err %d); please check that %s exists" " and is writeable", status, user_recovery_dirname); } - mnt_drop_write_file(rec_file); + mnt_drop_write_file(nn->rec_file); nfs4_reset_creds(original_cred); } @@ -267,7 +266,7 @@ static int nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) { const struct cred *original_cred; - struct dentry *dir = rec_file->f_path.dentry; + struct dentry *dir = nn->rec_file->f_path.dentry; LIST_HEAD(names); int status; @@ -275,13 +274,13 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) if (status < 0) return status; - status = vfs_llseek(rec_file, 0, SEEK_SET); + status = vfs_llseek(nn->rec_file, 0, SEEK_SET); if (status < 0) { nfs4_reset_creds(original_cred); return status; } - status = vfs_readdir(rec_file, nfsd4_build_namelist, &names); + status = vfs_readdir(nn->rec_file, nfsd4_build_namelist, &names); mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); while (!list_empty(&names)) { struct name_list *entry; @@ -305,14 +304,14 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) } static int -nfsd4_unlink_clid_dir(char *name, int namlen) +nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn) { struct dentry *dir, *dentry; int status; dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); - dir = rec_file->f_path.dentry; + dir = nn->rec_file->f_path.dentry; mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(name, dir, namlen); if (IS_ERR(dentry)) { @@ -339,14 +338,14 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) int status; struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); - if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) + if (!nn->rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) return; status = nfs4_make_rec_clidname(dname, &clp->cl_name); if (status) return legacy_recdir_name_error(status); - status = mnt_want_write_file(rec_file); + status = mnt_want_write_file(nn->rec_file); if (status) goto out; clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); @@ -355,10 +354,10 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) if (status < 0) goto out_drop_write; - status = nfsd4_unlink_clid_dir(dname, HEXDIR_LEN-1); + status = nfsd4_unlink_clid_dir(dname, HEXDIR_LEN-1, nn); nfs4_reset_creds(original_cred); if (status == 0) { - vfs_fsync(rec_file, 0); + vfs_fsync(nn->rec_file, 0); if (in_grace) { /* remove reclaim record */ crp = nfsd4_find_reclaim_client(dname, nn); @@ -367,7 +366,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) } } out_drop_write: - mnt_drop_write_file(rec_file); + mnt_drop_write_file(nn->rec_file); out: if (status) printk("NFSD: Failed to remove expired client state directory" @@ -396,20 +395,20 @@ nfsd4_recdir_purge_old(struct nfsd_net *nn, time_t boot_time) int status; in_grace = false; - if (!rec_file) + if (!nn->rec_file) return; - status = mnt_want_write_file(rec_file); + status = mnt_want_write_file(nn->rec_file); if (status) goto out; status = nfsd4_list_rec_dir(purge_old, nn); if (status == 0) - vfs_fsync(rec_file, 0); - mnt_drop_write_file(rec_file); + vfs_fsync(nn->rec_file, 0); + mnt_drop_write_file(nn->rec_file); out: nfs4_release_reclaim(nn); if (status) printk("nfsd4: failed to purge old clients from recovery" - " directory %s\n", rec_file->f_path.dentry->d_name.name); + " directory %s\n", nn->rec_file->f_path.dentry->d_name.name); } static int @@ -430,13 +429,13 @@ nfsd4_recdir_load(struct net *net) { int status; struct nfsd_net *nn = net_generic(net, nfsd_net_id); - if (!rec_file) + if (!nn->rec_file) return 0; status = nfsd4_list_rec_dir(load_recdir, nn); if (status) printk("nfsd4: failed loading clients from recovery" - " directory %s\n", rec_file->f_path.dentry->d_name.name); + " directory %s\n", nn->rec_file->f_path.dentry->d_name.name); return status; } @@ -445,15 +444,16 @@ nfsd4_recdir_load(struct net *net) { */ static int -nfsd4_init_recdir(void) +nfsd4_init_recdir(struct net *net) { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); const struct cred *original_cred; int status; printk("NFSD: Using %s as the NFSv4 state recovery directory\n", user_recovery_dirname); - BUG_ON(rec_file); + BUG_ON(nn->rec_file); status = nfs4_save_creds(&original_cred); if (status < 0) { @@ -463,12 +463,12 @@ nfsd4_init_recdir(void) return status; } - rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); - if (IS_ERR(rec_file)) { + nn->rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); + if (IS_ERR(nn->rec_file)) { printk("NFSD: unable to find recovery directory %s\n", user_recovery_dirname); - status = PTR_ERR(rec_file); - rec_file = NULL; + status = PTR_ERR(nn->rec_file); + nn->rec_file = NULL; } nfs4_reset_creds(original_cred); @@ -509,7 +509,7 @@ nfsd4_load_reboot_recovery_data(struct net *net) { int status; - status = nfsd4_init_recdir(); + status = nfsd4_init_recdir(net); if (!status) status = nfsd4_recdir_load(net); if (status) @@ -544,12 +544,12 @@ err: } static void -nfsd4_shutdown_recdir(void) +nfsd4_shutdown_recdir(struct nfsd_net *nn) { - if (!rec_file) + if (!nn->rec_file) return; - fput(rec_file); - rec_file = NULL; + fput(nn->rec_file); + nn->rec_file = NULL; } static void @@ -558,7 +558,7 @@ nfsd4_legacy_tracking_exit(struct net *net) struct nfsd_net *nn = net_generic(net, nfsd_net_id); nfs4_release_reclaim(nn); - nfsd4_shutdown_recdir(); + nfsd4_shutdown_recdir(nn); nfs4_legacy_state_shutdown(net); } -- cgit v0.10.2 From f141f79d709de447c8c92ba54821740ae53a5d07 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 26 Nov 2012 16:16:30 +0300 Subject: nfsd: recovery - make in_grace per net Flag in_grace is a part of client tracking state, which is network namesapce aware. So let'a replace global static variable with per-net one. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 1305632..9047706 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -86,6 +86,7 @@ struct nfsd_net { spinlock_t client_lock; struct file *rec_file; + bool in_grace; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 3e76d28..359793f 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -64,7 +64,6 @@ struct nfsd4_client_tracking_ops { /* Globals */ static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; static struct nfsd4_client_tracking_ops *client_tracking_ops; -static bool in_grace; static int nfs4_save_creds(const struct cred **original_creds) @@ -221,7 +220,7 @@ out_put: out_unlock: mutex_unlock(&dir->d_inode->i_mutex); if (status == 0) { - if (in_grace) { + if (nn->in_grace) { crp = nfs4_client_to_reclaim(dname, nn); if (crp) crp->cr_clp = clp; @@ -358,7 +357,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) nfs4_reset_creds(original_cred); if (status == 0) { vfs_fsync(nn->rec_file, 0); - if (in_grace) { + if (nn->in_grace) { /* remove reclaim record */ crp = nfsd4_find_reclaim_client(dname, nn); if (crp) @@ -394,7 +393,7 @@ nfsd4_recdir_purge_old(struct nfsd_net *nn, time_t boot_time) { int status; - in_grace = false; + nn->in_grace = false; if (!nn->rec_file) return; status = mnt_want_write_file(nn->rec_file); @@ -473,7 +472,7 @@ nfsd4_init_recdir(struct net *net) nfs4_reset_creds(original_cred); if (!status) - in_grace = true; + nn->in_grace = true; return status; } -- cgit v0.10.2 From 864aee5c6f90533984c356494e6b0a8070e5d5f2 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 27 Nov 2012 14:42:20 +0300 Subject: nfsd: remove redundant declarations This is a cleanup patch. Functions nfsd_pool_stats_open() and nfsd_pool_stats_release() are declared in fs/nfsd/nfsd.h. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index dab350d..f5ab74a 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -186,9 +186,6 @@ static struct file_operations supported_enctypes_ops = { }; #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ -extern int nfsd_pool_stats_open(struct inode *inode, struct file *file); -extern int nfsd_pool_stats_release(struct inode *inode, struct file *file); - static const struct file_operations pool_stats_operations = { .open = nfsd_pool_stats_open, .read = seq_read, -- cgit v0.10.2 From 3d7337115d06f21970e23684f4d2e62e3a44c572 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 27 Nov 2012 14:11:44 +0300 Subject: nfsd: make NFSv4 lease time per net Lease time is a part of NFSv4 state engine, which is constructed per network namespace. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 9047706..0c20be8 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -87,6 +87,8 @@ struct nfsd_net { struct file *rec_file; bool in_grace; + + time_t nfsd4_lease; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 826cc26..99bc85f 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -36,6 +36,7 @@ #include #include "nfsd.h" #include "state.h" +#include "netns.h" #define NFSDDBG_FACILITY NFSDDBG_PROC @@ -625,9 +626,10 @@ static const struct rpc_program cb_program = { .pipe_dir_name = "nfsd4_cb", }; -static int max_cb_time(void) +static int max_cb_time(struct net *net) { - return max(nfsd4_lease/10, (time_t)1) * HZ; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + return max(nn->nfsd4_lease/10, (time_t)1) * HZ; } static struct rpc_cred *callback_cred; @@ -659,7 +661,7 @@ static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) { struct rpc_timeout timeparms = { - .to_initval = max_cb_time(), + .to_initval = max_cb_time(clp->net), .to_retries = 0, }; struct rpc_create_args args = { diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index fb98f29..932b2ca 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -51,7 +51,6 @@ #define NFSDDBG_FACILITY NFSDDBG_PROC /* Globals */ -time_t nfsd4_lease = 90; /* default lease time */ time_t nfsd4_grace = 90; #define all_ones {{~0,~0},~0} @@ -3184,7 +3183,7 @@ nfsd4_end_grace(struct nfsd_net *nn) * to see the (possibly new, possibly shorter) lease time, we * can safely set the next grace time to the current lease time: */ - nfsd4_grace = nfsd4_lease; + nfsd4_grace = nn->nfsd4_lease; } static time_t @@ -3194,9 +3193,9 @@ nfs4_laundromat(struct nfsd_net *nn) struct nfs4_openowner *oo; struct nfs4_delegation *dp; struct list_head *pos, *next, reaplist; - time_t cutoff = get_seconds() - nfsd4_lease; - time_t t, clientid_val = nfsd4_lease; - time_t u, test_val = nfsd4_lease; + time_t cutoff = get_seconds() - nn->nfsd4_lease; + time_t t, clientid_val = nn->nfsd4_lease; + time_t u, test_val = nn->nfsd4_lease; nfs4_lock_state(); @@ -3245,7 +3244,7 @@ nfs4_laundromat(struct nfsd_net *nn) dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); unhash_delegation(dp); } - test_val = nfsd4_lease; + test_val = nn->nfsd4_lease; list_for_each_safe(pos, next, &nn->close_lru) { oo = container_of(pos, struct nfs4_openowner, oo_close_lru); if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 250171c..b775366 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -53,6 +53,7 @@ #include "vfs.h" #include "state.h" #include "cache.h" +#include "netns.h" #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -2052,6 +2053,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, .mnt = exp->ex_path.mnt, .dentry = dentry, }; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); @@ -2212,7 +2214,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, if (bmval0 & FATTR4_WORD0_LEASE_TIME) { if ((buflen -= 4) < 0) goto out_resource; - WRITE32(nfsd4_lease); + WRITE32(nn->nfsd4_lease); } if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) { if ((buflen -= 4) < 0) diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index f5ab74a..09d909a 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -909,7 +909,8 @@ static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_ */ static ssize_t write_leasetime(struct file *file, char *buf, size_t size) { - return nfsd4_write_time(file, buf, size, &nfsd4_lease); + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease); } /** @@ -1060,6 +1061,7 @@ int nfsd_net_id; static __net_init int nfsd_init_net(struct net *net) { int retval; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); retval = nfsd_export_init(net); if (retval) @@ -1067,6 +1069,7 @@ static __net_init int nfsd_init_net(struct net *net) retval = nfsd_idmap_init(net); if (retval) goto out_idmap_error; + nn->nfsd4_lease = 90; /* default lease time */ return 0; out_idmap_error: diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index d7b210b..a8f7325 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -276,7 +276,6 @@ extern struct timeval nfssvc_boot; #ifdef CONFIG_NFSD_V4 -extern time_t nfsd4_lease; extern time_t nfsd4_grace; /* before processing a COMPOUND operation, we have to check that there -- cgit v0.10.2 From 5284b44e438580a50e8cc5189297a73a48a45ecb Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 27 Nov 2012 14:11:49 +0300 Subject: nfsd: make NFSv4 grace time per net Grace time is a part of NFSv4 state engine, which is constructed per network namespace. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 0c20be8..2c4b2e2 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -89,6 +89,7 @@ struct nfsd_net { bool in_grace; time_t nfsd4_lease; + time_t nfsd4_grace; }; extern int nfsd_net_id; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 932b2ca..3db7617 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -50,9 +50,6 @@ #define NFSDDBG_FACILITY NFSDDBG_PROC -/* Globals */ -time_t nfsd4_grace = 90; - #define all_ones {{~0,~0},~0} static const stateid_t one_stateid = { .si_generation = ~0, @@ -3183,7 +3180,7 @@ nfsd4_end_grace(struct nfsd_net *nn) * to see the (possibly new, possibly shorter) lease time, we * can safely set the next grace time to the current lease time: */ - nfsd4_grace = nn->nfsd4_lease; + nn->nfsd4_grace = nn->nfsd4_lease; } static time_t @@ -4884,8 +4881,8 @@ nfs4_state_start_net(struct net *net) locks_start_grace(net, &nn->nfsd4_manager); nn->grace_ended = false; printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", - nfsd4_grace, net); - queue_delayed_work(laundry_wq, &nn->laundromat_work, nfsd4_grace * HZ); + nn->nfsd4_grace, net); + queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); return 0; } diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 09d909a..d902f83 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -925,7 +925,8 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size) */ static ssize_t write_gracetime(struct file *file, char *buf, size_t size) { - return nfsd4_write_time(file, buf, size, &nfsd4_grace); + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); + return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace); } static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) @@ -1070,6 +1071,7 @@ static __net_init int nfsd_init_net(struct net *net) if (retval) goto out_idmap_error; nn->nfsd4_lease = 90; /* default lease time */ + nn->nfsd4_grace = 90; return 0; out_idmap_error: diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index a8f7325..5eea0f5 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -276,8 +276,6 @@ extern struct timeval nfssvc_boot; #ifdef CONFIG_NFSD_V4 -extern time_t nfsd4_grace; - /* before processing a COMPOUND operation, we have to check that there * is enough space in the buffer for XDR encode to succeed. otherwise, * we might process an operation with side effects, and be unable to -- cgit v0.10.2 From f3c7521fe53a7892d8c8c4715f7c0f4add7b2e19 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Tue, 27 Nov 2012 09:35:10 -0500 Subject: NFSD: Fold fault_inject.h into state.h There were only a small number of functions in this file and since they all affect stored state I think it makes sense to put them in state.h instead. I also dropped most static inline declarations since there are no callers when fault injection is not enabled. Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index e6c3815..0278112 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -10,7 +10,6 @@ #include #include "state.h" -#include "fault_inject.h" struct nfsd_fault_inject_op { char *file; diff --git a/fs/nfsd/fault_inject.h b/fs/nfsd/fault_inject.h deleted file mode 100644 index 90bd057..0000000 --- a/fs/nfsd/fault_inject.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2011 Bryan Schumaker - * - * Function definitions for fault injection - */ - -#ifndef LINUX_NFSD_FAULT_INJECT_H -#define LINUX_NFSD_FAULT_INJECT_H - -#ifdef CONFIG_NFSD_FAULT_INJECTION -int nfsd_fault_inject_init(void); -void nfsd_fault_inject_cleanup(void); -void nfsd_forget_clients(u64); -void nfsd_forget_locks(u64); -void nfsd_forget_openowners(u64); -void nfsd_forget_delegations(u64); -void nfsd_recall_delegations(u64); -#else /* CONFIG_NFSD_FAULT_INJECTION */ -static inline int nfsd_fault_inject_init(void) { return 0; } -static inline void nfsd_fault_inject_cleanup(void) {} -static inline void nfsd_forget_clients(u64 num) {} -static inline void nfsd_forget_locks(u64 num) {} -static inline void nfsd_forget_openowners(u64 num) {} -static inline void nfsd_forget_delegations(u64 num) {} -static inline void nfsd_recall_delegations(u64 num) {} -#endif /* CONFIG_NFSD_FAULT_INJECTION */ - -#endif /* LINUX_NFSD_FAULT_INJECT_H */ diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3db7617..b1aa577 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -44,7 +44,6 @@ #include "xdr4.h" #include "vfs.h" #include "current_stateid.h" -#include "fault_inject.h" #include "netns.h" diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index d902f83..e13cbdd 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -19,7 +19,7 @@ #include "idmap.h" #include "nfsd.h" #include "cache.h" -#include "fault_inject.h" +#include "state.h" #include "netns.h" /* diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 2deb6a8..b542bf2 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -496,4 +496,19 @@ extern void nfsd4_client_record_create(struct nfs4_client *clp); extern void nfsd4_client_record_remove(struct nfs4_client *clp); extern int nfsd4_client_record_check(struct nfs4_client *clp); extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time); + +/* nfs fault injection functions */ +#ifdef CONFIG_NFSD_FAULT_INJECTION +int nfsd_fault_inject_init(void); +void nfsd_fault_inject_cleanup(void); +void nfsd_forget_clients(u64); +void nfsd_forget_locks(u64); +void nfsd_forget_openowners(u64); +void nfsd_forget_delegations(u64); +void nfsd_recall_delegations(u64); +#else /* CONFIG_NFSD_FAULT_INJECTION */ +static inline int nfsd_fault_inject_init(void) { return 0; } +static inline void nfsd_fault_inject_cleanup(void) {} +#endif /* CONFIG_NFSD_FAULT_INJECTION */ + #endif /* NFSD4_STATE_H */ -- cgit v0.10.2 From 1a9bd45412665e73c72612b6f744378d860e02a8 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Wed, 28 Nov 2012 09:42:26 +0000 Subject: powerpc+of: Export of_reconfig_notifier_[register,unregister] The of reconfiguration notification chains should be exported for use by modules. Signed-off-by:Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/of/base.c b/drivers/of/base.c index 02d94c4..fa40402 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1197,11 +1197,13 @@ int of_reconfig_notifier_register(struct notifier_block *nb) { return blocking_notifier_chain_register(&of_reconfig_chain, nb); } +EXPORT_SYMBOL_GPL(of_reconfig_notifier_register); int of_reconfig_notifier_unregister(struct notifier_block *nb) { return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); } +EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); int of_reconfig_notify(unsigned long action, void *p) { -- cgit v0.10.2 From e89e29b8585379c844b03fb3aa2cca73e2bc5b26 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Mon, 5 Nov 2012 10:55:25 -0800 Subject: Input: tca8418_keypad - add support for device tree bindings Signed-off-by: Alban Bedel Signed-off-by: Dmitry Torokhov diff --git a/Documentation/devicetree/bindings/input/tca8418_keypad.txt b/Documentation/devicetree/bindings/input/tca8418_keypad.txt new file mode 100644 index 0000000..2a1538f --- /dev/null +++ b/Documentation/devicetree/bindings/input/tca8418_keypad.txt @@ -0,0 +1,8 @@ + +Required properties: +- compatible: "ti,tca8418" +- reg: the I2C address +- interrupts: IRQ line number, should trigger on falling edge +- keypad,num-rows: The number of rows +- keypad,num-columns: The number of columns +- linux,keymap: Keys definitions, see keypad-matrix. diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index f1e966b..1a2894d 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -35,6 +35,7 @@ #include #include #include +#include /* TCA8418 hardware limits */ #define TCA8418_MAX_ROWS 8 @@ -116,10 +117,15 @@ static const struct i2c_device_id tca8418_id[] = { }; MODULE_DEVICE_TABLE(i2c, tca8418_id); +#ifdef CONFIG_OF +static const struct of_device_id tca8418_dt_ids[] __devinitconst = { + { .compatible = "ti,tca8418", }, + { } +}; +MODULE_DEVICE_TABLE(of, tca8418_dt_ids); +#endif + struct tca8418_keypad { - unsigned int rows; - unsigned int cols; - unsigned int keypad_mask; /* Mask for keypad col/rol regs */ unsigned int irq; unsigned int row_shift; @@ -241,7 +247,8 @@ exit: /* * Configure the TCA8418 for keypad operation */ -static int tca8418_configure(struct tca8418_keypad *keypad_data) +static int tca8418_configure(struct tca8418_keypad *keypad_data, + u32 rows, u32 cols) { int reg, error; @@ -253,9 +260,8 @@ static int tca8418_configure(struct tca8418_keypad *keypad_data) /* Assemble a mask for row and column registers */ - reg = ~(~0 << keypad_data->rows); - reg += (~(~0 << keypad_data->cols)) << 8; - keypad_data->keypad_mask = reg; + reg = ~(~0 << rows); + reg += (~(~0 << cols)) << 8; /* Set registers to keypad mode */ error |= tca8418_write_byte(keypad_data, REG_KP_GPIO1, reg); @@ -277,25 +283,36 @@ static int tca8418_keypad_probe(struct i2c_client *client, client->dev.platform_data; struct tca8418_keypad *keypad_data; struct input_dev *input; + const struct matrix_keymap_data *keymap_data = NULL; + u32 rows = 0, cols = 0; + bool rep = false; + bool irq_is_gpio = false; int error, row_shift, max_keys; /* Copy the platform data */ - if (!pdata) { - dev_dbg(&client->dev, "no platform data\n"); - return -EINVAL; + if (pdata) { + if (!pdata->keymap_data) { + dev_err(&client->dev, "no keymap data defined\n"); + return -EINVAL; + } + keymap_data = pdata->keymap_data; + rows = pdata->rows; + cols = pdata->cols; + rep = pdata->rep; + irq_is_gpio = pdata->irq_is_gpio; + } else { + struct device_node *np = client->dev.of_node; + of_property_read_u32(np, "keypad,num-rows", &rows); + of_property_read_u32(np, "keypad,num-columns", &cols); + rep = of_property_read_bool(np, "keypad,autorepeat"); } - if (!pdata->keymap_data) { - dev_err(&client->dev, "no keymap data defined\n"); - return -EINVAL; - } - - if (!pdata->rows || pdata->rows > TCA8418_MAX_ROWS) { + if (!rows || rows > TCA8418_MAX_ROWS) { dev_err(&client->dev, "invalid rows\n"); return -EINVAL; } - if (!pdata->cols || pdata->cols > TCA8418_MAX_COLS) { + if (!cols || cols > TCA8418_MAX_COLS) { dev_err(&client->dev, "invalid columns\n"); return -EINVAL; } @@ -307,8 +324,8 @@ static int tca8418_keypad_probe(struct i2c_client *client, return -ENODEV; } - row_shift = get_count_order(pdata->cols); - max_keys = pdata->rows << row_shift; + row_shift = get_count_order(cols); + max_keys = rows << row_shift; /* Allocate memory for keypad_data, keymap and input device */ keypad_data = kzalloc(sizeof(*keypad_data) + @@ -316,13 +333,11 @@ static int tca8418_keypad_probe(struct i2c_client *client, if (!keypad_data) return -ENOMEM; - keypad_data->rows = pdata->rows; - keypad_data->cols = pdata->cols; keypad_data->client = client; keypad_data->row_shift = row_shift; /* Initialize the chip or fail if chip isn't present */ - error = tca8418_configure(keypad_data); + error = tca8418_configure(keypad_data, rows, cols); if (error < 0) goto fail1; @@ -342,21 +357,20 @@ static int tca8418_keypad_probe(struct i2c_client *client, input->id.product = 0x001; input->id.version = 0x0001; - error = matrix_keypad_build_keymap(pdata->keymap_data, NULL, - pdata->rows, pdata->cols, + error = matrix_keypad_build_keymap(keymap_data, NULL, rows, cols, keypad_data->keymap, input); if (error) { dev_dbg(&client->dev, "Failed to build keymap\n"); goto fail2; } - if (pdata->rep) + if (rep) __set_bit(EV_REP, input->evbit); input_set_capability(input, EV_MSC, MSC_SCAN); input_set_drvdata(input, keypad_data); - if (pdata->irq_is_gpio) + if (irq_is_gpio) client->irq = gpio_to_irq(client->irq); error = request_threaded_irq(client->irq, NULL, tca8418_irq_handler, @@ -401,11 +415,11 @@ static int tca8418_keypad_remove(struct i2c_client *client) return 0; } - static struct i2c_driver tca8418_keypad_driver = { .driver = { .name = TCA8418_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tca8418_dt_ids), }, .probe = tca8418_keypad_probe, .remove = tca8418_keypad_remove, -- cgit v0.10.2 From bf7f5316cbacbcb7d3c337eba36322cab255dec0 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Thu, 8 Nov 2012 08:57:55 -0800 Subject: Input: tca8418_keypad - add support for shared interrupt Signed-off-by: Alban Bedel Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 1a2894d..ac4ff13 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -224,16 +224,18 @@ static irqreturn_t tca8418_irq_handler(int irq, void *dev_id) if (error) { dev_err(&keypad_data->client->dev, "unable to read REG_INT_STAT\n"); - goto exit; + return IRQ_NONE; } + if (!reg) + return IRQ_NONE; + if (reg & INT_STAT_OVR_FLOW_INT) dev_warn(&keypad_data->client->dev, "overflow occurred\n"); if (reg & INT_STAT_K_INT) tca8418_read_keypad(keypad_data); -exit: /* Clear all interrupts, even IRQs we didn't check (GPI, CAD, LCK) */ reg = 0xff; error = tca8418_write_byte(keypad_data, REG_INT_STAT, reg); @@ -374,7 +376,9 @@ static int tca8418_keypad_probe(struct i2c_client *client, client->irq = gpio_to_irq(client->irq); error = request_threaded_irq(client->irq, NULL, tca8418_irq_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + IRQF_TRIGGER_FALLING | + IRQF_SHARED | + IRQF_ONESHOT, client->name, keypad_data); if (error) { dev_dbg(&client->dev, -- cgit v0.10.2 From efce8a412161b0555254bd6ac1dcdfb7886bfd8c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 14 Nov 2012 08:06:44 -0800 Subject: Input: tca8418_keypad - use a temporary variable for parent device Use a temporary variable for our parent device (coming from I2C client structure); we'll be also using it during conversion to managed resources. Reviewed-by: Alban Bedel Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index ac4ff13..3bb981a 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -281,6 +281,7 @@ static int tca8418_configure(struct tca8418_keypad *keypad_data, static int tca8418_keypad_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; const struct tca8418_keypad_platform_data *pdata = client->dev.platform_data; struct tca8418_keypad *keypad_data; @@ -294,7 +295,7 @@ static int tca8418_keypad_probe(struct i2c_client *client, /* Copy the platform data */ if (pdata) { if (!pdata->keymap_data) { - dev_err(&client->dev, "no keymap data defined\n"); + dev_err(dev, "no keymap data defined\n"); return -EINVAL; } keymap_data = pdata->keymap_data; @@ -303,25 +304,25 @@ static int tca8418_keypad_probe(struct i2c_client *client, rep = pdata->rep; irq_is_gpio = pdata->irq_is_gpio; } else { - struct device_node *np = client->dev.of_node; + struct device_node *np = dev->of_node; of_property_read_u32(np, "keypad,num-rows", &rows); of_property_read_u32(np, "keypad,num-columns", &cols); rep = of_property_read_bool(np, "keypad,autorepeat"); } if (!rows || rows > TCA8418_MAX_ROWS) { - dev_err(&client->dev, "invalid rows\n"); + dev_err(dev, "invalid rows\n"); return -EINVAL; } if (!cols || cols > TCA8418_MAX_COLS) { - dev_err(&client->dev, "invalid columns\n"); + dev_err(dev, "invalid columns\n"); return -EINVAL; } /* Check i2c driver capabilities */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { - dev_err(&client->dev, "%s adapter not supported\n", + dev_err(dev, "%s adapter not supported\n", dev_driver_string(&client->adapter->dev)); return -ENODEV; } @@ -362,7 +363,7 @@ static int tca8418_keypad_probe(struct i2c_client *client, error = matrix_keypad_build_keymap(keymap_data, NULL, rows, cols, keypad_data->keymap, input); if (error) { - dev_dbg(&client->dev, "Failed to build keymap\n"); + dev_dbg(dev, "Failed to build keymap\n"); goto fail2; } @@ -381,16 +382,15 @@ static int tca8418_keypad_probe(struct i2c_client *client, IRQF_ONESHOT, client->name, keypad_data); if (error) { - dev_dbg(&client->dev, - "Unable to claim irq %d; error %d\n", + dev_dbg(dev, "Unable to claim irq %d; error %d\n", client->irq, error); goto fail2; } error = input_register_device(input); if (error) { - dev_dbg(&client->dev, - "Unable to register input device, error: %d\n", error); + dev_dbg(dev, "Unable to register input device, error: %d\n", + error); goto fail3; } -- cgit v0.10.2 From cdbe8a86379b9002598a4d14791dc8e790b1f5f5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 14 Nov 2012 08:12:05 -0800 Subject: Input: tca8418_keypad - use dev_get_platdata() to retrieve platform data We need to use proper accessor functions instead of directly poking into various structures. Reviewed-by: Alban Bedel Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 3bb981a..ab41a2e 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -283,7 +283,7 @@ static int tca8418_keypad_probe(struct i2c_client *client, { struct device *dev = &client->dev; const struct tca8418_keypad_platform_data *pdata = - client->dev.platform_data; + dev_get_platdata(dev); struct tca8418_keypad *keypad_data; struct input_dev *input; const struct matrix_keymap_data *keymap_data = NULL; -- cgit v0.10.2 From 5cc0dfe043f84a777bf9d66dc48cc2b83709c9ef Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 14 Nov 2012 08:16:15 -0800 Subject: Input: tca8418_keypad - move device ID tables closer to where they are used This matches structure of most other input drivers. Reviewed-by: Alban Bedel Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index ab41a2e..9084327 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -110,21 +110,6 @@ #define KEY_EVENT_CODE 0x7f #define KEY_EVENT_VALUE 0x80 - -static const struct i2c_device_id tca8418_id[] = { - { TCA8418_NAME, 8418, }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tca8418_id); - -#ifdef CONFIG_OF -static const struct of_device_id tca8418_dt_ids[] __devinitconst = { - { .compatible = "ti,tca8418", }, - { } -}; -MODULE_DEVICE_TABLE(of, tca8418_dt_ids); -#endif - struct tca8418_keypad { unsigned int irq; unsigned int row_shift; @@ -419,6 +404,20 @@ static int tca8418_keypad_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id tca8418_id[] = { + { TCA8418_NAME, 8418, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tca8418_id); + +#ifdef CONFIG_OF +static const struct of_device_id tca8418_dt_ids[] __devinitconst = { + { .compatible = "ti,tca8418", }, + { } +}; +MODULE_DEVICE_TABLE(of, tca8418_dt_ids); +#endif + static struct i2c_driver tca8418_keypad_driver = { .driver = { .name = TCA8418_NAME, -- cgit v0.10.2 From 91c5d67f17784078169bdcce4c21df82ac6c234c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 14 Nov 2012 08:20:21 -0800 Subject: Input: tca8418_keypad - increase severity of failures in probe() Failures to build a keymap, request an IRQ, or register input device are fatal for the driver, therefore the messages should have "error" severity instead of "debug". Reviewed-by: Alban Bedel Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 9084327..8fcce37 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -348,7 +348,7 @@ static int tca8418_keypad_probe(struct i2c_client *client, error = matrix_keypad_build_keymap(keymap_data, NULL, rows, cols, keypad_data->keymap, input); if (error) { - dev_dbg(dev, "Failed to build keymap\n"); + dev_err(dev, "Failed to build keymap\n"); goto fail2; } @@ -367,14 +367,14 @@ static int tca8418_keypad_probe(struct i2c_client *client, IRQF_ONESHOT, client->name, keypad_data); if (error) { - dev_dbg(dev, "Unable to claim irq %d; error %d\n", + dev_err(dev, "Unable to claim irq %d; error %d\n", client->irq, error); goto fail2; } error = input_register_device(input); if (error) { - dev_dbg(dev, "Unable to register input device, error: %d\n", + dev_err(dev, "Unable to register input device, error: %d\n", error); goto fail3; } -- cgit v0.10.2 From 16ff7cb1848a8898ff19f77b4a9632a73ff98457 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 5 Nov 2012 11:13:11 -0800 Subject: Input: tca8418-keypad - switch to using managed resources Let's switch to using devm_*() interfaces to manage our resources, thus will simplify error unwinding a bit. Reviewed-by: Alban Bedel Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 8fcce37..50e9c5e 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -111,14 +111,10 @@ #define KEY_EVENT_VALUE 0x80 struct tca8418_keypad { - unsigned int irq; - unsigned int row_shift; - struct i2c_client *client; struct input_dev *input; - /* Flexible array member, must be at end of struct */ - unsigned short keymap[]; + unsigned int row_shift; }; /* @@ -163,6 +159,8 @@ static int tca8418_read_byte(struct tca8418_keypad *keypad_data, static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) { + struct input_dev *input = keypad_data->input; + unsigned short *keymap = input->keycode; int error, col, row; u8 reg, state, code; @@ -181,9 +179,8 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) col = (col) ? col - 1 : TCA8418_MAX_COLS - 1; code = MATRIX_SCAN_CODE(row, col, keypad_data->row_shift); - input_event(keypad_data->input, EV_MSC, MSC_SCAN, code); - input_report_key(keypad_data->input, - keypad_data->keymap[code], state); + input_event(input, EV_MSC, MSC_SCAN, code); + input_report_key(input, keymap[code], state); /* Read for next loop */ error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); @@ -193,7 +190,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) dev_err(&keypad_data->client->dev, "unable to read REG_KEY_EVENT_A\n"); - input_sync(keypad_data->input); + input_sync(input); } /* @@ -275,6 +272,7 @@ static int tca8418_keypad_probe(struct i2c_client *client, u32 rows = 0, cols = 0; bool rep = false; bool irq_is_gpio = false; + int irq; int error, row_shift, max_keys; /* Copy the platform data */ @@ -315,9 +313,8 @@ static int tca8418_keypad_probe(struct i2c_client *client, row_shift = get_count_order(cols); max_keys = rows << row_shift; - /* Allocate memory for keypad_data, keymap and input device */ - keypad_data = kzalloc(sizeof(*keypad_data) + - max_keys * sizeof(keypad_data->keymap[0]), GFP_KERNEL); + /* Allocate memory for keypad_data and input device */ + keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL); if (!keypad_data) return -ENOMEM; @@ -327,29 +324,26 @@ static int tca8418_keypad_probe(struct i2c_client *client, /* Initialize the chip or fail if chip isn't present */ error = tca8418_configure(keypad_data, rows, cols); if (error < 0) - goto fail1; + return error; /* Configure input device */ - input = input_allocate_device(); - if (!input) { - error = -ENOMEM; - goto fail1; - } + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + keypad_data->input = input; input->name = client->name; - input->dev.parent = &client->dev; - input->id.bustype = BUS_I2C; input->id.vendor = 0x0001; input->id.product = 0x001; input->id.version = 0x0001; error = matrix_keypad_build_keymap(keymap_data, NULL, rows, cols, - keypad_data->keymap, input); + NULL, input); if (error) { dev_err(dev, "Failed to build keymap\n"); - goto fail2; + return error; } if (rep) @@ -358,49 +352,28 @@ static int tca8418_keypad_probe(struct i2c_client *client, input_set_drvdata(input, keypad_data); + irq = client->irq; if (irq_is_gpio) - client->irq = gpio_to_irq(client->irq); + irq = gpio_to_irq(irq); - error = request_threaded_irq(client->irq, NULL, tca8418_irq_handler, - IRQF_TRIGGER_FALLING | - IRQF_SHARED | - IRQF_ONESHOT, - client->name, keypad_data); + error = devm_request_threaded_irq(dev, irq, NULL, tca8418_irq_handler, + IRQF_TRIGGER_FALLING | + IRQF_SHARED | + IRQF_ONESHOT, + client->name, keypad_data); if (error) { dev_err(dev, "Unable to claim irq %d; error %d\n", client->irq, error); - goto fail2; + return error; } error = input_register_device(input); if (error) { dev_err(dev, "Unable to register input device, error: %d\n", error); - goto fail3; + return error; } - i2c_set_clientdata(client, keypad_data); - return 0; - -fail3: - free_irq(client->irq, keypad_data); -fail2: - input_free_device(input); -fail1: - kfree(keypad_data); - return error; -} - -static int tca8418_keypad_remove(struct i2c_client *client) -{ - struct tca8418_keypad *keypad_data = i2c_get_clientdata(client); - - free_irq(keypad_data->client->irq, keypad_data); - - input_unregister_device(keypad_data->input); - - kfree(keypad_data); - return 0; } @@ -425,7 +398,6 @@ static struct i2c_driver tca8418_keypad_driver = { .of_match_table = of_match_ptr(tca8418_dt_ids), }, .probe = tca8418_keypad_probe, - .remove = tca8418_keypad_remove, .id_table = tca8418_id, }; -- cgit v0.10.2 From 1a22e16fc3d6abc8d6323cc0973435439932fe5f Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 29 Nov 2012 08:57:17 -0800 Subject: Input: gpio-keys-polled - honor 'autorepeat' setting in platform data Signed-off-by: Alexander Shiyan Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 32e5087..d72d0e5 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -245,7 +245,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) input = poll_dev->input; - input->evbit[0] = BIT(EV_KEY); input->name = pdev->name; input->phys = DRV_NAME"/input0"; input->dev.parent = &pdev->dev; @@ -255,6 +254,10 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) input->id.product = 0x0001; input->id.version = 0x0100; + __set_bit(EV_KEY, input->evbit); + if (pdata->rep) + __set_bit(EV_REP, input->evbit); + for (i = 0; i < pdata->nbuttons; i++) { struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_keys_button_data *bdata = &bdev->data[i]; -- cgit v0.10.2 From ddac0d6872b15fc5311d44021b8898ec6720bdec Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 30 Nov 2012 01:01:40 -0500 Subject: tools/power turbostat: fix output buffering issue In periodic mode, turbostat writes to stdout, but users were un-able to re-direct stdout, eg. turbostat > outputfile would result in an empty outputfile. Signed-off-by: Len Brown diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 77e76b1..cb03147 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -423,6 +423,7 @@ done: void flush_stdout() { fputs(output_buffer, stdout); + fflush(stdout); outp = output_buffer; } void flush_stderr() -- cgit v0.10.2 From 889facbee3e67dbc8eb29d8ee7fd66d33a647bfc Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 8 Nov 2012 00:48:57 -0500 Subject: tools/power turbostat: v3.0: monitor Watts and Temperature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show power in Watts and temperature in Celsius when hardware support is present. Intel's Sandy Bridge and Ivy Bridge processor generations support RAPL (Run-Time-Average-Power-Limiting). Per the Intel SDM (Intel® 64 and IA-32 Architectures Software Developer Manual) RAPL provides hardware energy counters and power control MSRs (Model Specific Registers). RAPL MSRs are designed primarily as a method to implement power capping. However, they are useful for monitoring system power whether or not power capping is used. In addition, Turbostat now shows temperature from DTS (Digital Thermal Sensor) and PTM (Package Thermal Monitor) hardware, if present. As before, turbostat reads MSRs, and never writes MSRs. New columns are present in turbostat output: The Pkg_W column shows Watts for each package (socket) in the system. On multi-socket systems, the system summary on the 1st row shows the sum for all sockets together. The Cor_W column shows Watts due to processors cores. Note that Core_W is included in Pkg_W. The optional GFX_W column shows Watts due to the graphics "un-core". Note that GFX_W is included in Pkg_W. The optional RAM_W column on server processors shows Watts due to DRAM DIMMS. As DRAM DIMMs are outside the processor package, RAM_W is not included in Pkg_W. The optional PKG_% and RAM_% columns on server processors shows the % of time in the measurement interval that RAPL power limiting is in effect on the package and on DRAM. Note that the RAPL energy counters have some limitations. First, hardware updates the counters about once every milli-second. This is fine for typical turbostat measurement intervals > 1 sec. However, when turbostat is used to measure events that approach 1ms, the counters are less useful. Second, the 32-bit energy counters are subject to wrapping. For example, a counter incrementing 15 micro-Joule units on a 130 Watt TDP server processor could (in theory) roll over in about 9 minutes. Turbostat detects and handles up to 1 counter overflow per measurement interval. But when the measurement interval exceeds the guaranteed counter range, we can't detect if more than 1 overflow occured. So in this case turbostat indicates that the results are in question by replacing the fractional part of the Watts in the output with "**": Pkg_W Cor_W GFX_W 3** 0** 0** Third, the RAPL counters are energy (Joule) counters -- they sum up weighted events in the package to estimate energy consumed. They are not analong power (Watt) meters. In practice, they tend to under-count because they don't cover every possible use of energy in the package. The accuracy of the RAPL counters will vary between product generations, and between SKU's in the same product generation, and with temperature. turbostat's -v (verbose) option now displays more power and thermal configuration information -- as shown on the turbostat.8 manual page. For example, it now displays the Package and DRAM Thermal Design Power (TDP): cpu0: MSR_PKG_POWER_INFO: 0x2f064001980410 (130 W TDP, RAPL 51 - 200 W, 0.045898 sec.) cpu0: MSR_DRAM_POWER_INFO,: 0x28025800780118 (35 W TDP, RAPL 15 - 75 W, 0.039062 sec.) cpu8: MSR_PKG_POWER_INFO: 0x2f064001980410 (130 W TDP, RAPL 51 - 200 W, 0.045898 sec.) cpu8: MSR_DRAM_POWER_INFO,: 0x28025800780118 (35 W TDP, RAPL 15 - 75 W, 0.039062 sec.) Signed-off-by: Len Brown diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index e4d0690..0d7dc2c 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -11,16 +11,16 @@ turbostat \- Report processor frequency and idle statistics .RB [ Options ] .RB [ "\-i interval_sec" ] .SH DESCRIPTION -\fBturbostat \fP reports processor topology, frequency -and idle power state statistics on modern X86 processors. +\fBturbostat \fP reports processor topology, frequency, +idle power-state statistics, temperature and power on modern X86 processors. Either \fBcommand\fP is forked and statistics are printed upon its completion, or statistics are printed periodically. \fBturbostat \fP -requires that the processor +must be run on root, and +minimally requires that the processor supports an "invariant" TSC, plus the APERF and MPERF MSRs. -\fBturbostat \fP will report idle cpu power state residency -on processors that additionally support C-state residency counters. +Additional information is reported depending on hardware counter support. .SS Options The \fB-p\fP option limits output to the 1st thread in 1st core of each package. @@ -57,7 +57,15 @@ Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading T \fBGHz\fP average clock rate while the CPU was in c0 state. \fBTSC\fP average GHz that the TSC ran during the entire interval. \fB%c1, %c3, %c6, %c7\fP show the percentage residency in hardware core idle states. +\fBCTMP\fP Degrees Celsius reported by the per-core Digital Thermal Sensor. +\fBPTMP\fP Degrees Celsius reported by the per-package Package Thermal Monitor. \fB%pc2, %pc3, %pc6, %pc7\fP percentage residency in hardware package idle states. +\fBPkg_W\fP Watts consumed by the whole package. +\fBCor_W\fP Watts consumed by the core part of the package. +\fBGFX_W\fP Watts consumed by the Graphics part of the package -- available only on client processors. +\fBRAM_W\fP Watts consumed by the DRAM DIMMS -- available only on server processors. +\fBPKG_%\fP percent of the interval that RAPL throttling was active on the Package. +\fBRAM_%\fP percent of the interval that RAPL throttling was active on DRAM. .fi .PP .SH EXAMPLE @@ -66,50 +74,73 @@ Without any parameters, turbostat prints out counters ever 5 seconds. for turbostat to fork). The first row of statistics is a summary for the entire system. -Note that the summary is a weighted average. +For residency % columns, the summary is a weighted average. +For Temperature columns, the summary is the column maximum. +For Watts columns, the summary is a system total. Subsequent rows show per-CPU statistics. .nf -[root@x980]# ./turbostat -cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 - 0.09 1.62 3.38 1.83 0.32 97.76 1.26 83.61 - 0 0 0.15 1.62 3.38 10.23 0.05 89.56 1.26 83.61 - 0 6 0.05 1.62 3.38 10.34 - 1 2 0.03 1.62 3.38 0.07 0.05 99.86 - 1 8 0.03 1.62 3.38 0.06 - 2 4 0.21 1.62 3.38 0.10 1.49 98.21 - 2 10 0.02 1.62 3.38 0.29 - 8 1 0.04 1.62 3.38 0.04 0.08 99.84 - 8 7 0.01 1.62 3.38 0.06 - 9 3 0.53 1.62 3.38 0.10 0.20 99.17 - 9 9 0.02 1.62 3.38 0.60 - 10 5 0.01 1.62 3.38 0.02 0.04 99.92 - 10 11 0.02 1.62 3.38 0.02 +[root@sandy]# ./turbostat +cor CPU %c0 GHz TSC %c1 %c3 %c6 %c7 CTMP PTMP %pc2 %pc3 %pc6 %pc7 Pkg_W Cor_W GFX_W + 0.06 0.80 2.29 0.11 0.00 0.00 99.83 47 40 0.26 0.01 0.44 98.78 3.49 0.12 0.14 + 0 0 0.07 0.80 2.29 0.07 0.00 0.00 99.86 40 40 0.26 0.01 0.44 98.78 3.49 0.12 0.14 + 0 4 0.03 0.80 2.29 0.12 + 1 1 0.04 0.80 2.29 0.25 0.01 0.00 99.71 40 + 1 5 0.16 0.80 2.29 0.13 + 2 2 0.05 0.80 2.29 0.06 0.01 0.00 99.88 40 + 2 6 0.03 0.80 2.29 0.08 + 3 3 0.05 0.80 2.29 0.08 0.00 0.00 99.87 47 + 3 7 0.04 0.84 2.29 0.09 .fi .SH SUMMARY EXAMPLE The "-s" option prints the column headers just once, and then the one line system summary for each sample interval. .nf -[root@x980]# ./turbostat -s - %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 - 0.23 1.67 3.38 2.00 0.30 97.47 1.07 82.12 - 0.10 1.62 3.38 1.87 2.25 95.77 12.02 72.60 - 0.20 1.64 3.38 1.98 0.11 97.72 0.30 83.36 - 0.11 1.70 3.38 1.86 1.81 96.22 9.71 74.90 +[root@wsm]# turbostat -S + %c0 GHz TSC %c1 %c3 %c6 CTMP %pc3 %pc6 + 1.40 2.81 3.38 10.78 43.47 44.35 42 13.67 2.09 + 1.34 2.90 3.38 11.48 58.96 28.23 41 19.89 0.15 + 1.55 2.72 3.38 26.73 37.66 34.07 42 2.53 2.80 + 1.37 2.83 3.38 16.95 60.05 21.63 42 5.76 0.20 .fi .SH VERBOSE EXAMPLE The "-v" option adds verbosity to the output: .nf -GenuineIntel 11 CPUID levels; family:model:stepping 0x6:2c:2 (6:44:2) -12 * 133 = 1600 MHz max efficiency -25 * 133 = 3333 MHz TSC frequency -26 * 133 = 3467 MHz max turbo 4 active cores -26 * 133 = 3467 MHz max turbo 3 active cores -27 * 133 = 3600 MHz max turbo 2 active cores -27 * 133 = 3600 MHz max turbo 1 active cores - +[root@ivy]# turbostat -v +turbostat v3.0 November 23, 2012 - Len Brown +CPUID(0): GenuineIntel 13 CPUID levels; family:model:stepping 0x6:3a:9 (6:58:9) +CPUID(6): APERF, DTS, PTM, EPB +RAPL: 851 sec. Joule Counter Range +cpu0: MSR_NHM_PLATFORM_INFO: 0x81010f0012300 +16 * 100 = 1600 MHz max efficiency +35 * 100 = 3500 MHz TSC frequency +cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x1e008402 (UNdemote-C3, UNdemote-C1, demote-C3, demote-C1, locked: pkg-cstate-limit=2: pc6-noret) +cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x25262727 +37 * 100 = 3700 MHz max turbo 4 active cores +38 * 100 = 3800 MHz max turbo 3 active cores +39 * 100 = 3900 MHz max turbo 2 active cores +39 * 100 = 3900 MHz max turbo 1 active cores +cpu0: MSR_IA32_ENERGY_PERF_BIAS: 0x00000006 (balanced) +cpu0: MSR_RAPL_POWER_UNIT: 0x000a1003 (0.125000 Watts, 0.000015 Joules, 0.000977 sec.) +cpu0: MSR_PKG_POWER_INFO: 0x01e00268 (77 W TDP, RAPL 60 - 0 W, 0.000000 sec.) +cpu0: MSR_PKG_POWER_LIMIT: 0x830000148268 (UNlocked) +cpu0: PKG Limit #1: ENabled (77.000000 Watts, 1.000000 sec, clamp DISabled) +cpu0: PKG Limit #2: ENabled (96.000000 Watts, 0.000977* sec, clamp DISabled) +cpu0: MSR_PP0_POLICY: 0 +cpu0: MSR_PP0_POWER_LIMIT: 0x00000000 (UNlocked) +cpu0: Cores Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled) +cpu0: MSR_PP1_POLICY: 0 +cpu0: MSR_PP1_POWER_LIMIT: 0x00000000 (UNlocked) +cpu0: GFX Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled) +cpu0: MSR_IA32_TEMPERATURE_TARGET: 0x00691400 (105 C) +cpu0: MSR_IA32_PACKAGE_THERM_STATUS: 0x884e0000 (27 C) +cpu0: MSR_IA32_THERM_STATUS: 0x88560000 (19 C +/- 1) +cpu1: MSR_IA32_THERM_STATUS: 0x88560000 (19 C +/- 1) +cpu2: MSR_IA32_THERM_STATUS: 0x88540000 (21 C +/- 1) +cpu3: MSR_IA32_THERM_STATUS: 0x884e0000 (27 C +/- 1) + ... .fi The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency available at the minimum package voltage. The \fBTSC frequency\fP is the nominal @@ -142,7 +173,7 @@ cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 10 5 1.42 3.43 3.38 2.14 30.99 65.44 10 11 0.16 2.88 3.38 3.40 .fi -Above the cycle soaker drives cpu7 up its 3.6 Ghz turbo limit +Above the cycle soaker drives cpu7 up its 3.6 GHz turbo limit while the other processors are generally in various states of idle. Note that cpu1 and cpu7 are HT siblings within core8. diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index cb03147..ce6d460 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -39,12 +39,15 @@ char *proc_stat = "/proc/stat"; unsigned int interval_sec = 5; /* set with -i interval_sec */ unsigned int verbose; /* set with -v */ +unsigned int rapl_verbose; /* set with -R */ +unsigned int thermal_verbose; /* set with -T */ unsigned int summary_only; /* set with -s */ unsigned int skip_c0; unsigned int skip_c1; unsigned int do_nhm_cstates; unsigned int do_snb_cstates; unsigned int has_aperf; +unsigned int has_epb; unsigned int units = 1000000000; /* Ghz etc */ unsigned int genuine_intel; unsigned int has_invariant_tsc; @@ -62,6 +65,23 @@ unsigned int show_cpu; unsigned int show_pkg_only; unsigned int show_core_only; char *output_buffer, *outp; +unsigned int do_rapl; +unsigned int do_dts; +unsigned int do_ptm; +unsigned int tcc_activation_temp; +unsigned int tcc_activation_temp_override; +double rapl_power_units, rapl_energy_units, rapl_time_units; +double rapl_joule_counter_range; + +#define RAPL_PKG (1 << 0) +#define RAPL_CORES (1 << 1) +#define RAPL_GFX (1 << 2) +#define RAPL_DRAM (1 << 3) +#define RAPL_PKG_PERF_STATUS (1 << 4) +#define RAPL_DRAM_PERF_STATUS (1 << 5) +#define TJMAX_DEFAULT 100 + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) int aperf_mperf_unstable; int backwards_count; @@ -89,6 +109,7 @@ struct core_data { unsigned long long c3; unsigned long long c6; unsigned long long c7; + unsigned int core_temp_c; unsigned int core_id; } *core_even, *core_odd; @@ -98,6 +119,14 @@ struct pkg_data { unsigned long long pc6; unsigned long long pc7; unsigned int package_id; + unsigned int energy_pkg; /* MSR_PKG_ENERGY_STATUS */ + unsigned int energy_dram; /* MSR_DRAM_ENERGY_STATUS */ + unsigned int energy_cores; /* MSR_PP0_ENERGY_STATUS */ + unsigned int energy_gfx; /* MSR_PP1_ENERGY_STATUS */ + unsigned int rapl_pkg_perf_status; /* MSR_PKG_PERF_STATUS */ + unsigned int rapl_dram_perf_status; /* MSR_DRAM_PERF_STATUS */ + unsigned int pkg_temp_c; + } *package_even, *package_odd; #define ODD_COUNTERS thread_odd, core_odd, package_odd @@ -235,6 +264,12 @@ void print_header(void) outp += sprintf(outp, " %%c6"); if (do_snb_cstates) outp += sprintf(outp, " %%c7"); + + if (do_dts) + outp += sprintf(outp, " CTMP"); + if (do_ptm) + outp += sprintf(outp, " PTMP"); + if (do_snb_cstates) outp += sprintf(outp, " %%pc2"); if (do_nhm_cstates) @@ -244,6 +279,19 @@ void print_header(void) if (do_snb_cstates) outp += sprintf(outp, " %%pc7"); + if (do_rapl & RAPL_PKG) + outp += sprintf(outp, " Pkg_W"); + if (do_rapl & RAPL_CORES) + outp += sprintf(outp, " Cor_W"); + if (do_rapl & RAPL_GFX) + outp += sprintf(outp, " GFX_W"); + if (do_rapl & RAPL_DRAM) + outp += sprintf(outp, " RAM_W"); + if (do_rapl & RAPL_PKG_PERF_STATUS) + outp += sprintf(outp, " PKG_%%"); + if (do_rapl & RAPL_DRAM_PERF_STATUS) + outp += sprintf(outp, " RAM_%%"); + outp += sprintf(outp, "\n"); } @@ -273,6 +321,7 @@ int dump_counters(struct thread_data *t, struct core_data *c, fprintf(stderr, "c3: %016llX\n", c->c3); fprintf(stderr, "c6: %016llX\n", c->c6); fprintf(stderr, "c7: %016llX\n", c->c7); + fprintf(stderr, "DTS: %dC\n", c->core_temp_c); } if (p) { @@ -281,6 +330,13 @@ int dump_counters(struct thread_data *t, struct core_data *c, fprintf(stderr, "pc3: %016llX\n", p->pc3); fprintf(stderr, "pc6: %016llX\n", p->pc6); fprintf(stderr, "pc7: %016llX\n", p->pc7); + fprintf(stderr, "Joules PKG: %0X\n", p->energy_pkg); + fprintf(stderr, "Joules COR: %0X\n", p->energy_cores); + fprintf(stderr, "Joules GFX: %0X\n", p->energy_gfx); + fprintf(stderr, "Joules RAM: %0X\n", p->energy_dram); + fprintf(stderr, "Throttle PKG: %0X\n", p->rapl_pkg_perf_status); + fprintf(stderr, "Throttle RAM: %0X\n", p->rapl_dram_perf_status); + fprintf(stderr, "PTM: %dC\n", p->pkg_temp_c); } return 0; } @@ -290,14 +346,21 @@ int dump_counters(struct thread_data *t, struct core_data *c, * package: "pk" 2 columns %2d * core: "cor" 3 columns %3d * CPU: "CPU" 3 columns %3d + * Pkg_W: %6.2 + * Cor_W: %6.2 + * GFX_W: %5.2 + * RAM_W: %5.2 * GHz: "GHz" 3 columns %3.2 * TSC: "TSC" 3 columns %3.2 * percentage " %pc3" %6.2 + * Perf Status percentage: %5.2 + * "CTMP" 4 columns %4d */ int format_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) { double interval_float; + char *fmt5, *fmt6; /* if showing only 1st thread in core and this isn't one, bail out */ if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) @@ -337,7 +400,6 @@ int format_counters(struct thread_data *t, struct core_data *c, if (show_cpu) outp += sprintf(outp, " %3d", t->cpu_id); } - /* %c0 */ if (do_nhm_cstates) { if (show_pkg || show_core || show_cpu) @@ -402,10 +464,16 @@ int format_counters(struct thread_data *t, struct core_data *c, if (do_snb_cstates) outp += sprintf(outp, " %6.2f", 100.0 * c->c7/t->tsc); + if (do_dts) + outp += sprintf(outp, " %4d", c->core_temp_c); + /* print per-package data only for 1st core in package */ if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) goto done; + if (do_ptm) + outp += sprintf(outp, " %4d", p->pkg_temp_c); + if (do_snb_cstates) outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc); if (do_nhm_cstates) @@ -414,6 +482,32 @@ int format_counters(struct thread_data *t, struct core_data *c, outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc); if (do_snb_cstates) outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc); + + /* + * If measurement interval exceeds minimum RAPL Joule Counter range, + * indicate that results are suspect by printing "**" in fraction place. + */ + if (interval_float < rapl_joule_counter_range) { + fmt5 = " %5.2f"; + fmt6 = " %6.2f"; + } else { + fmt5 = " %3.0f**"; + fmt6 = " %4.0f**"; + } + + if (do_rapl & RAPL_PKG) + outp += sprintf(outp, fmt6, p->energy_pkg * rapl_energy_units / interval_float); + if (do_rapl & RAPL_CORES) + outp += sprintf(outp, fmt6, p->energy_cores * rapl_energy_units / interval_float); + if (do_rapl & RAPL_GFX) + outp += sprintf(outp, fmt5, p->energy_gfx * rapl_energy_units / interval_float); + if (do_rapl & RAPL_DRAM) + outp += sprintf(outp, fmt5, p->energy_dram * rapl_energy_units / interval_float); + if (do_rapl & RAPL_PKG_PERF_STATUS ) + outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); + if (do_rapl & RAPL_DRAM_PERF_STATUS ) + outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); + done: outp += sprintf(outp, "\n"); @@ -450,6 +544,13 @@ void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_ for_all_cpus(format_counters, t, c, p); } +#define DELTA_WRAP32(new, old) \ + if (new > old) { \ + old = new - old; \ + } else { \ + old = 0x100000000 + new - old; \ + } + void delta_package(struct pkg_data *new, struct pkg_data *old) { @@ -457,6 +558,14 @@ delta_package(struct pkg_data *new, struct pkg_data *old) old->pc3 = new->pc3 - old->pc3; old->pc6 = new->pc6 - old->pc6; old->pc7 = new->pc7 - old->pc7; + old->pkg_temp_c = new->pkg_temp_c; + + DELTA_WRAP32(new->energy_pkg, old->energy_pkg); + DELTA_WRAP32(new->energy_cores, old->energy_cores); + DELTA_WRAP32(new->energy_gfx, old->energy_gfx); + DELTA_WRAP32(new->energy_dram, old->energy_dram); + DELTA_WRAP32(new->rapl_pkg_perf_status, old->rapl_pkg_perf_status); + DELTA_WRAP32(new->rapl_dram_perf_status, old->rapl_dram_perf_status); } void @@ -465,6 +574,7 @@ delta_core(struct core_data *new, struct core_data *old) old->c3 = new->c3 - old->c3; old->c6 = new->c6 - old->c6; old->c7 = new->c7 - old->c7; + old->core_temp_c = new->core_temp_c; } /* @@ -571,11 +681,20 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data c->c3 = 0; c->c6 = 0; c->c7 = 0; + c->core_temp_c = 0; p->pc2 = 0; p->pc3 = 0; p->pc6 = 0; p->pc7 = 0; + + p->energy_pkg = 0; + p->energy_dram = 0; + p->energy_cores = 0; + p->energy_gfx = 0; + p->rapl_pkg_perf_status = 0; + p->rapl_dram_perf_status = 0; + p->pkg_temp_c = 0; } int sum_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) @@ -596,6 +715,8 @@ int sum_counters(struct thread_data *t, struct core_data *c, average.cores.c6 += c->c6; average.cores.c7 += c->c7; + average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c); + /* sum per-pkg values only for 1st core in pkg */ if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) return 0; @@ -605,6 +726,15 @@ int sum_counters(struct thread_data *t, struct core_data *c, average.packages.pc6 += p->pc6; average.packages.pc7 += p->pc7; + average.packages.energy_pkg += p->energy_pkg; + average.packages.energy_dram += p->energy_dram; + average.packages.energy_cores += p->energy_cores; + average.packages.energy_gfx += p->energy_gfx; + + average.packages.pkg_temp_c = MAX(average.packages.pkg_temp_c, p->pkg_temp_c); + + average.packages.rapl_pkg_perf_status += p->rapl_pkg_perf_status; + average.packages.rapl_dram_perf_status += p->rapl_dram_perf_status; return 0; } /* @@ -656,6 +786,7 @@ static unsigned long long rdtsc(void) int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) { int cpu = t->cpu_id; + unsigned long long msr; if (cpu_migrate(cpu)) { fprintf(stderr, "Could not migrate to CPU %d\n", cpu); @@ -672,9 +803,9 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) } if (extra_delta_offset32) { - if (get_msr(cpu, extra_delta_offset32, &t->extra_delta32)) + if (get_msr(cpu, extra_delta_offset32, &msr)) return -5; - t->extra_delta32 &= 0xFFFFFFFF; + t->extra_delta32 = msr & 0xFFFFFFFF; } if (extra_delta_offset64) @@ -682,9 +813,9 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) return -5; if (extra_msr_offset32) { - if (get_msr(cpu, extra_msr_offset32, &t->extra_msr32)) + if (get_msr(cpu, extra_msr_offset32, &msr)) return -5; - t->extra_msr32 &= 0xFFFFFFFF; + t->extra_msr32 = msr & 0xFFFFFFFF; } if (extra_msr_offset64) @@ -706,6 +837,13 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7)) return -8; + if (do_dts) { + if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr)) + return -9; + c->core_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F); + } + + /* collect package counters only for 1st core in package */ if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) return 0; @@ -722,6 +860,41 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7)) return -12; } + if (do_rapl & RAPL_PKG) { + if (get_msr(cpu, MSR_PKG_ENERGY_STATUS, &msr)) + return -13; + p->energy_pkg = msr & 0xFFFFFFFF; + } + if (do_rapl & RAPL_CORES) { + if (get_msr(cpu, MSR_PP0_ENERGY_STATUS, &msr)) + return -14; + p->energy_cores = msr & 0xFFFFFFFF; + } + if (do_rapl & RAPL_DRAM) { + if (get_msr(cpu, MSR_DRAM_ENERGY_STATUS, &msr)) + return -15; + p->energy_dram = msr & 0xFFFFFFFF; + } + if (do_rapl & RAPL_GFX) { + if (get_msr(cpu, MSR_PP1_ENERGY_STATUS, &msr)) + return -16; + p->energy_gfx = msr & 0xFFFFFFFF; + } + if (do_rapl & RAPL_PKG_PERF_STATUS) { + if (get_msr(cpu, MSR_PKG_PERF_STATUS, &msr)) + return -16; + p->rapl_pkg_perf_status = msr & 0xFFFFFFFF; + } + if (do_rapl & RAPL_DRAM_PERF_STATUS) { + if (get_msr(cpu, MSR_DRAM_PERF_STATUS, &msr)) + return -16; + p->rapl_dram_perf_status = msr & 0xFFFFFFFF; + } + if (do_ptm) { + if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr)) + return -17; + p->pkg_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F); + } return 0; } @@ -735,8 +908,8 @@ void print_verbose_header(void) get_msr(0, MSR_NHM_PLATFORM_INFO, &msr); - if (verbose > 1) - fprintf(stderr, "MSR_NHM_PLATFORM_INFO: 0x%llx\n", msr); + if (verbose) + fprintf(stderr, "cpu0: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", msr); ratio = (msr >> 40) & 0xFF; fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", @@ -751,8 +924,8 @@ void print_verbose_header(void) get_msr(0, MSR_IVT_TURBO_RATIO_LIMIT, &msr); - if (verbose > 1) - fprintf(stderr, "MSR_IVT_TURBO_RATIO_LIMIT: 0x%llx\n", msr); + if (verbose) + fprintf(stderr, "cpu0: MSR_IVT_TURBO_RATIO_LIMIT: 0x%08llx\n", msr); ratio = (msr >> 56) & 0xFF; if (ratio) @@ -795,14 +968,56 @@ void print_verbose_header(void) ratio, bclk, ratio * bclk); print_nhm_turbo_ratio_limits: + get_msr(0, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr); + +#define SNB_C1_AUTO_UNDEMOTE (1UL << 27) +#define SNB_C3_AUTO_UNDEMOTE (1UL << 28) + + fprintf(stderr, "cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x%08llx", msr); + + fprintf(stderr, " (%s%s%s%s%slocked: pkg-cstate-limit=%d: ", + (msr & SNB_C3_AUTO_UNDEMOTE) ? "UNdemote-C3, " : "", + (msr & SNB_C1_AUTO_UNDEMOTE) ? "UNdemote-C1, " : "", + (msr & NHM_C3_AUTO_DEMOTE) ? "demote-C3, " : "", + (msr & NHM_C1_AUTO_DEMOTE) ? "demote-C1, " : "", + (msr & (1 << 15)) ? "" : "UN", + (unsigned int)msr & 7); + + + switch(msr & 0x7) { + case 0: + fprintf(stderr, "pc0"); + break; + case 1: + fprintf(stderr, do_snb_cstates ? "pc2" : "pc0"); + break; + case 2: + fprintf(stderr, do_snb_cstates ? "pc6-noret" : "pc3"); + break; + case 3: + fprintf(stderr, "pc6"); + break; + case 4: + fprintf(stderr, "pc7"); + break; + case 5: + fprintf(stderr, do_snb_cstates ? "pc7s" : "invalid"); + break; + case 7: + fprintf(stderr, "unlimited"); + break; + default: + fprintf(stderr, "invalid"); + } + fprintf(stderr, ")\n"); if (!do_nehalem_turbo_ratio_limit) return; get_msr(0, MSR_NHM_TURBO_RATIO_LIMIT, &msr); - if (verbose > 1) - fprintf(stderr, "MSR_NHM_TURBO_RATIO_LIMIT: 0x%llx\n", msr); + if (verbose) + fprintf(stderr, "cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x%08llx\n", msr); ratio = (msr >> 56) & 0xFF; if (ratio) @@ -1205,6 +1420,299 @@ int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model) } } +/* + * print_epb() + * Decode the ENERGY_PERF_BIAS MSR + */ +int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ + unsigned long long msr; + char *epb_string; + int cpu; + + if (!has_epb) + return 0; + + cpu = t->cpu_id; + + /* EPB is per-package */ + if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) + return 0; + + if (cpu_migrate(cpu)) { + fprintf(stderr, "Could not migrate to CPU %d\n", cpu); + return -1; + } + + if (get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr)) + return 0; + + switch (msr & 0x7) { + case ENERGY_PERF_BIAS_PERFORMANCE: + epb_string = "performance"; + break; + case ENERGY_PERF_BIAS_NORMAL: + epb_string = "balanced"; + break; + case ENERGY_PERF_BIAS_POWERSAVE: + epb_string = "powersave"; + break; + default: + epb_string = "custom"; + break; + } + fprintf(stderr, "cpu%d: MSR_IA32_ENERGY_PERF_BIAS: 0x%08llx (%s)\n", cpu, msr, epb_string); + + return 0; +} + +#define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */ +#define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */ + +/* + * rapl_probe() + * + * sets do_rapl + */ +void rapl_probe(unsigned int family, unsigned int model) +{ + unsigned long long msr; + double tdp; + + if (!genuine_intel) + return; + + if (family != 6) + return; + + switch (model) { + case 0x2A: + case 0x3A: + do_rapl = RAPL_PKG | RAPL_CORES | RAPL_GFX; + break; + case 0x2D: + case 0x3E: + do_rapl = RAPL_PKG | RAPL_CORES | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS; + break; + default: + return; + } + + /* units on package 0, verify later other packages match */ + if (get_msr(0, MSR_RAPL_POWER_UNIT, &msr)) + return; + + rapl_power_units = 1.0 / (1 << (msr & 0xF)); + rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F)); + rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF)); + + /* get TDP to determine energy counter range */ + if (get_msr(0, MSR_PKG_POWER_INFO, &msr)) + return; + + tdp = ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units; + + rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp; + + if (verbose) + fprintf(stderr, "RAPL: %.0f sec. Joule Counter Range\n", rapl_joule_counter_range); + + return; +} + +int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ + unsigned long long msr; + unsigned int dts; + int cpu; + + if (!(do_dts || do_ptm)) + return 0; + + cpu = t->cpu_id; + + /* DTS is per-core, no need to print for each thread */ + if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) + return 0; + + if (cpu_migrate(cpu)) { + fprintf(stderr, "Could not migrate to CPU %d\n", cpu); + return -1; + } + + if (do_ptm && (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) { + if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr)) + return 0; + + dts = (msr >> 16) & 0x7F; + fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n", + cpu, msr, tcc_activation_temp - dts); + +#ifdef THERM_DEBUG + if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &msr)) + return 0; + + dts = (msr >> 16) & 0x7F; + dts2 = (msr >> 8) & 0x7F; + fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n", + cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2); +#endif + } + + + if (do_dts) { + unsigned int resolution; + + if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr)) + return 0; + + dts = (msr >> 16) & 0x7F; + resolution = (msr >> 27) & 0xF; + fprintf(stderr, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n", + cpu, msr, tcc_activation_temp - dts, resolution); + +#ifdef THERM_DEBUG + if (get_msr(cpu, MSR_IA32_THERM_INTERRUPT, &msr)) + return 0; + + dts = (msr >> 16) & 0x7F; + dts2 = (msr >> 8) & 0x7F; + fprintf(stderr, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n", + cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2); +#endif + } + + return 0; +} + +void print_power_limit_msr(int cpu, unsigned long long msr, char *label) +{ + fprintf(stderr, "cpu%d: %s: %sabled (%f Watts, %f sec, clamp %sabled)\n", + cpu, label, + ((msr >> 15) & 1) ? "EN" : "DIS", + ((msr >> 0) & 0x7FFF) * rapl_power_units, + (1.0 + (((msr >> 22) & 0x3)/4.0)) * (1 << ((msr >> 17) & 0x1F)) * rapl_time_units, + (((msr >> 16) & 1) ? "EN" : "DIS")); + + return; +} + +int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ + unsigned long long msr; + int cpu; + double local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units; + + if (!do_rapl) + return 0; + + /* RAPL counters are per package, so print only for 1st thread/package */ + if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) + return 0; + + cpu = t->cpu_id; + if (cpu_migrate(cpu)) { + fprintf(stderr, "Could not migrate to CPU %d\n", cpu); + return -1; + } + + if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr)) + return -1; + + local_rapl_power_units = 1.0 / (1 << (msr & 0xF)); + local_rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F)); + local_rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF)); + + if (local_rapl_power_units != rapl_power_units) + fprintf(stderr, "cpu%d, ERROR: Power units mis-match\n", cpu); + if (local_rapl_energy_units != rapl_energy_units) + fprintf(stderr, "cpu%d, ERROR: Energy units mis-match\n", cpu); + if (local_rapl_time_units != rapl_time_units) + fprintf(stderr, "cpu%d, ERROR: Time units mis-match\n", cpu); + + if (verbose) { + fprintf(stderr, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx " + "(%f Watts, %f Joules, %f sec.)\n", cpu, msr, + local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units); + } + if (do_rapl & RAPL_PKG) { + if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr)) + return -5; + + + fprintf(stderr, "cpu%d: MSR_PKG_POWER_INFO: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n", + cpu, msr, + ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units, + ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units, + ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units, + ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units); + + if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr)) + return -9; + + fprintf(stderr, "cpu%d: MSR_PKG_POWER_LIMIT: 0x%08llx (%slocked)\n", + cpu, msr, (msr >> 63) & 1 ? "": "UN"); + + print_power_limit_msr(cpu, msr, "PKG Limit #1"); + fprintf(stderr, "cpu%d: PKG Limit #2: %sabled (%f Watts, %f* sec, clamp %sabled)\n", + cpu, + ((msr >> 47) & 1) ? "EN" : "DIS", + ((msr >> 32) & 0x7FFF) * rapl_power_units, + (1.0 + (((msr >> 54) & 0x3)/4.0)) * (1 << ((msr >> 49) & 0x1F)) * rapl_time_units, + ((msr >> 48) & 1) ? "EN" : "DIS"); + } + + if (do_rapl & RAPL_DRAM) { + if (get_msr(cpu, MSR_DRAM_POWER_INFO, &msr)) + return -6; + + + fprintf(stderr, "cpu%d: MSR_DRAM_POWER_INFO,: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n", + cpu, msr, + ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units, + ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units, + ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units, + ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units); + + + if (get_msr(cpu, MSR_DRAM_POWER_LIMIT, &msr)) + return -9; + fprintf(stderr, "cpu%d: MSR_DRAM_POWER_LIMIT: 0x%08llx (%slocked)\n", + cpu, msr, (msr >> 31) & 1 ? "": "UN"); + + print_power_limit_msr(cpu, msr, "DRAM Limit"); + } + if (do_rapl & RAPL_CORES) { + if (verbose) { + if (get_msr(cpu, MSR_PP0_POLICY, &msr)) + return -7; + + fprintf(stderr, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF); + + if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr)) + return -9; + fprintf(stderr, "cpu%d: MSR_PP0_POWER_LIMIT: 0x%08llx (%slocked)\n", + cpu, msr, (msr >> 31) & 1 ? "": "UN"); + print_power_limit_msr(cpu, msr, "Cores Limit"); + } + } + if (do_rapl & RAPL_GFX) { + if (verbose) { + if (get_msr(cpu, MSR_PP1_POLICY, &msr)) + return -8; + + fprintf(stderr, "cpu%d: MSR_PP1_POLICY: %lld\n", cpu, msr & 0xF); + + if (get_msr(cpu, MSR_PP1_POWER_LIMIT, &msr)) + return -9; + fprintf(stderr, "cpu%d: MSR_PP1_POWER_LIMIT: 0x%08llx (%slocked)\n", + cpu, msr, (msr >> 31) & 1 ? "": "UN"); + print_power_limit_msr(cpu, msr, "GFX Limit"); + } + } + return 0; +} + int is_snb(unsigned int family, unsigned int model) { @@ -1229,6 +1737,72 @@ double discover_bclk(unsigned int family, unsigned int model) return 133.33; } +/* + * MSR_IA32_TEMPERATURE_TARGET indicates the temperature where + * the Thermal Control Circuit (TCC) activates. + * This is usually equal to tjMax. + * + * Older processors do not have this MSR, so there we guess, + * but also allow cmdline over-ride with -T. + * + * Several MSR temperature values are in units of degrees-C + * below this value, including the Digital Thermal Sensor (DTS), + * Package Thermal Management Sensor (PTM), and thermal event thresholds. + */ +int set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ + unsigned long long msr; + unsigned int target_c_local; + int cpu; + + /* tcc_activation_temp is used only for dts or ptm */ + if (!(do_dts || do_ptm)) + return 0; + + /* this is a per-package concept */ + if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) + return 0; + + cpu = t->cpu_id; + if (cpu_migrate(cpu)) { + fprintf(stderr, "Could not migrate to CPU %d\n", cpu); + return -1; + } + + if (tcc_activation_temp_override != 0) { + tcc_activation_temp = tcc_activation_temp_override; + fprintf(stderr, "cpu%d: Using cmdline TCC Target (%d C)\n", + cpu, tcc_activation_temp); + return 0; + } + + /* Temperature Target MSR is Nehalem and newer only */ + if (!do_nehalem_platform_info) + goto guess; + + if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr)) + goto guess; + + target_c_local = (msr >> 16) & 0x7F; + + if (verbose) + fprintf(stderr, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n", + cpu, msr, target_c_local); + + if (target_c_local < 85 || target_c_local > 120) + goto guess; + + tcc_activation_temp = target_c_local; + + return 0; + +guess: + tcc_activation_temp = TJMAX_DEFAULT; + fprintf(stderr, "cpu%d: Guessing tjMax %d C, Please use -T to specify\n", + cpu, tcc_activation_temp); + + return 0; +} void check_cpuid() { unsigned int eax, ebx, ecx, edx, max_level; @@ -1242,7 +1816,7 @@ void check_cpuid() genuine_intel = 1; if (verbose) - fprintf(stderr, "%.4s%.4s%.4s ", + fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", (char *)&ebx, (char *)&edx, (char *)&ecx); asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); @@ -1293,10 +1867,19 @@ void check_cpuid() asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6)); has_aperf = ecx & (1 << 0); - if (!has_aperf) { - fprintf(stderr, "No APERF MSR\n"); - exit(1); - } + do_dts = eax & (1 << 0); + do_ptm = eax & (1 << 6); + has_epb = ecx & (1 << 3); + + if (verbose) + fprintf(stderr, "CPUID(6): %s%s%s%s\n", + has_aperf ? "APERF" : "No APERF!", + do_dts ? ", DTS" : "", + do_ptm ? ", PTM": "", + has_epb ? ", EPB": ""); + + if (!has_aperf) + exit(-1); do_nehalem_platform_info = genuine_intel && has_invariant_tsc; do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */ @@ -1305,12 +1888,15 @@ void check_cpuid() do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model); + rapl_probe(family, model); + + return; } void usage() { - fprintf(stderr, "%s: [-v][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", + fprintf(stderr, "%s: [-v][-R][-T][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", progname); exit(1); } @@ -1546,6 +2132,17 @@ void turbostat_init() if (verbose) print_verbose_header(); + + if (verbose) + for_all_cpus(print_epb, ODD_COUNTERS); + + if (verbose) + for_all_cpus(print_rapl, ODD_COUNTERS); + + for_all_cpus(set_temperature_target, ODD_COUNTERS); + + if (verbose) + for_all_cpus(print_thermal, ODD_COUNTERS); } int fork_it(char **argv) @@ -1602,7 +2199,7 @@ void cmdline(int argc, char **argv) progname = argv[0]; - while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:")) != -1) { + while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:RT:")) != -1) { switch (opt) { case 'p': show_core_only++; @@ -1634,6 +2231,12 @@ void cmdline(int argc, char **argv) case 'M': sscanf(optarg, "%x", &extra_msr_offset64); break; + case 'R': + rapl_verbose++; + break; + case 'T': + tcc_activation_temp_override = atoi(optarg); + break; default: usage(); } @@ -1644,8 +2247,8 @@ int main(int argc, char **argv) { cmdline(argc, argv); - if (verbose > 1) - fprintf(stderr, "turbostat v2.1 October 6, 2012" + if (verbose) + fprintf(stderr, "turbostat v3.0 November 23, 2012" " - Len Brown \n"); turbostat_init(); -- cgit v0.10.2 From 84764a415c707b43e751deb579a421776f190a95 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 15 Nov 2012 14:02:00 -0500 Subject: tools/power x86_energy_perf_policy: close /proc/stat in for_every_cpu() Instead of returning out of for_every_cpu() we should break out of the loop= which will then tidy up correctly by closing the file /proc/stat. Signed-off-by: Colin Ian King Signed-off-by: Len Brown diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c index 33c5c7e..40b3e54 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c @@ -289,7 +289,7 @@ void for_every_cpu(void (func)(int)) "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu); if (retval != 1) - return; + break; func(cpu); } -- cgit v0.10.2 From ee0778a3015370779f603d2b6119a6ec2b1c811a Mon Sep 17 00:00:00 2001 From: Mark Asselstine Date: Tue, 9 Oct 2012 11:31:44 -0400 Subject: tools/power: turbostat: make Makefile a bit more capable The turbostat Makefile is pretty simple, its output is placed in the same directory as the source, the install rule has no concept of a prefix or sysroot, and you can set CC to use a specific compiler but not use the more familiar CROSS_COMPILE. By making a few minor changes these limitations are removed while leaving the default behavior matching what it used to be. Example build with these changes: make CROSS_COMPILE=i686-wrs-linux-gnu- DESTDIR=/tmp install or from the tools directory make CROSS_COMPILE=i686-wrs-linux-gnu- DESTDIR=/tmp turbostat_install Signed-off-by: Mark Asselstine Signed-off-by: Len Brown diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile index 51880e8..e48ef07 100644 --- a/tools/power/x86/turbostat/Makefile +++ b/tools/power/x86/turbostat/Makefile @@ -1,10 +1,22 @@ +CC = $(CROSS_COMPILE)gcc +BUILD_OUTPUT := $(PWD) +PREFIX := /usr +DESTDIR := + turbostat : turbostat.c CFLAGS += -Wall CFLAGS += -I../../../../arch/x86/include/ +%: %.c + @mkdir -p $(BUILD_OUTPUT) + $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ + +.PHONY : clean clean : - rm -f turbostat + @rm -f $(BUILD_OUTPUT)/turbostat -install : - install turbostat /usr/bin/turbostat - install turbostat.8 /usr/share/man/man8 +install : turbostat + install -d $(DESTDIR)$(PREFIX)/bin + install $(BUILD_OUTPUT)/turbostat $(DESTDIR)$(PREFIX)/bin/turbostat + install -d $(DESTDIR)$(PREFIX)/share/man/man8 + install turbostat.8 $(DESTDIR)$(PREFIX)/share/man/man8 -- cgit v0.10.2 From 55f1f545f709a6023371848028a3029118855576 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 30 Oct 2012 13:38:05 -0400 Subject: tools: Allow tools to be installed in a user specified location When building x86_energy_perf_policy or turbostat within the confines of a packaging system such as RPM, we need to be able to have it install to the buildroot and not the root filesystem of the build machine. This adds a DESTDIR variable that when set will act as a prefix for the install location of these tools. Signed-off-by: Josh Boyer Signed-off-by: Len Brown diff --git a/tools/power/x86/x86_energy_perf_policy/Makefile b/tools/power/x86/x86_energy_perf_policy/Makefile index f458237..971c9ff 100644 --- a/tools/power/x86/x86_energy_perf_policy/Makefile +++ b/tools/power/x86/x86_energy_perf_policy/Makefile @@ -1,8 +1,10 @@ +DESTDIR ?= + x86_energy_perf_policy : x86_energy_perf_policy.c clean : rm -f x86_energy_perf_policy install : - install x86_energy_perf_policy /usr/bin/ - install x86_energy_perf_policy.8 /usr/share/man/man8/ + install x86_energy_perf_policy ${DESTDIR}/usr/bin/ + install x86_energy_perf_policy.8 ${DESTDIR}/usr/share/man/man8/ -- cgit v0.10.2 From 41c043842f047af682daf4940a1fc6dfc807bdbb Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 19 Nov 2012 20:35:20 -0300 Subject: UBI: gluebi: rename misleading variables Both names 'total_read' and 'total_written' are actually used as the number of bytes left to read and write. Fix this confusion by renaming both to 'bytes_left'. Signed-off-by: Ezequiel Garcia Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c index 4bd4db8..b93807b 100644 --- a/drivers/mtd/ubi/gluebi.c +++ b/drivers/mtd/ubi/gluebi.c @@ -171,17 +171,17 @@ static void gluebi_put_device(struct mtd_info *mtd) static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, unsigned char *buf) { - int err = 0, lnum, offs, total_read; + int err = 0, lnum, offs, bytes_left; struct gluebi_device *gluebi; gluebi = container_of(mtd, struct gluebi_device, mtd); lnum = div_u64_rem(from, mtd->erasesize, &offs); - total_read = len; - while (total_read) { + bytes_left = len; + while (bytes_left) { size_t to_read = mtd->erasesize - offs; - if (to_read > total_read) - to_read = total_read; + if (to_read > bytes_left) + to_read = bytes_left; err = ubi_read(gluebi->desc, lnum, buf, offs, to_read); if (err) @@ -189,11 +189,11 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, lnum += 1; offs = 0; - total_read -= to_read; + bytes_left -= to_read; buf += to_read; } - *retlen = len - total_read; + *retlen = len - bytes_left; return err; } @@ -211,7 +211,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - int err = 0, lnum, offs, total_written; + int err = 0, lnum, offs, bytes_left; struct gluebi_device *gluebi; gluebi = container_of(mtd, struct gluebi_device, mtd); @@ -220,12 +220,12 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, if (len % mtd->writesize || offs % mtd->writesize) return -EINVAL; - total_written = len; - while (total_written) { + bytes_left = len; + while (bytes_left) { size_t to_write = mtd->erasesize - offs; - if (to_write > total_written) - to_write = total_written; + if (to_write > bytes_left) + to_write = bytes_left; err = ubi_leb_write(gluebi->desc, lnum, buf, offs, to_write); if (err) @@ -233,11 +233,11 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, lnum += 1; offs = 0; - total_written -= to_write; + bytes_left -= to_write; buf += to_write; } - *retlen = len - total_written; + *retlen = len - bytes_left; return err; } -- cgit v0.10.2 From 38f92cca8aae5b2e4ff2700c47eee0b807e22980 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 21 Nov 2012 12:46:12 -0300 Subject: UBI: remove spurious comment This line of comment looks completely bogus. It was introduced in: commit d99383b00eba9c6ac3dea462d718b2849012ee03 Author: Artem Bityutskiy Date: Wed May 18 14:47:34 2011 +0300 UBI: change the interface of a debugging check function Remove it. Signed-off-by: Ezequiel Garcia Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index da7b449..ae95517 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1,5 +1,4 @@ /* - * @ubi: UBI device description object * Copyright (c) International Business Machines Corp., 2006 * * This program is free software; you can redistribute it and/or modify -- cgit v0.10.2 From 26047e2d6bde5b2e1b791e0ec1c3234894fdf3fa Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 30 Nov 2012 11:28:55 +0100 Subject: ASoC: cs4271: fix sparse warning Make the flag in the pdata of type bool to fix a sparse warning. Signed-off-by: Daniel Mack Reported-by: Fengguang Wu Signed-off-by: Mark Brown diff --git a/include/sound/cs4271.h b/include/sound/cs4271.h index 6d9e15e..dd8c48d 100644 --- a/include/sound/cs4271.h +++ b/include/sound/cs4271.h @@ -19,7 +19,7 @@ struct cs4271_platform_data { int gpio_nreset; /* GPIO driving Reset pin, if any */ - int amutec_eq_bmutec:1; /* flag to enable AMUTEC=BMUTEC */ + bool amutec_eq_bmutec; /* flag to enable AMUTEC=BMUTEC */ }; #endif /* __CS4271_H */ diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 2ac5fe6..f07d1b7 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -474,7 +474,7 @@ static int cs4271_probe(struct snd_soc_codec *codec) struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; int ret; int gpio_nreset = -EINVAL; - int amutec_eq_bmutec = 0; + bool amutec_eq_bmutec = false; #ifdef CONFIG_OF if (of_match_device(cs4271_dt_ids, codec->dev)) { @@ -483,7 +483,7 @@ static int cs4271_probe(struct snd_soc_codec *codec) if (!of_get_property(codec->dev->of_node, "cirrus,amutec-eq-bmutec", NULL)) - amutec_eq_bmutec = 1; + amutec_eq_bmutec = true; } #endif -- cgit v0.10.2 From b8455c9f6f661fb9bcb791370478d6d15c9bf2b3 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 30 Nov 2012 11:28:56 +0100 Subject: ASoC: cs4271: fix property check The driver had the property check for 'cirrus,amutec_eq_bmutec' the wrong way around. That happens if you misspell the property in the bindings during tests. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index f07d1b7..449a98b 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -481,7 +481,7 @@ static int cs4271_probe(struct snd_soc_codec *codec) gpio_nreset = of_get_named_gpio(codec->dev->of_node, "reset-gpio", 0); - if (!of_get_property(codec->dev->of_node, + if (of_get_property(codec->dev->of_node, "cirrus,amutec-eq-bmutec", NULL)) amutec_eq_bmutec = true; } -- cgit v0.10.2 From 954e3dd8308501bb00cae4ed655968282dc65314 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Sun, 2 Dec 2012 15:35:37 +0100 Subject: iommu/amd: Don't use 512GB pages There is a bug in the hardware that will be triggered when this page size is used. Make sure this does not happen. Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index cb63cc5..98d74ab 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -66,8 +66,10 @@ * * If at some point we'd like to utilize the IOMMU core's new behavior, * we could change this to advertise the real page sizes we support. + * + * 512GB Pages are not supported due to a hardware bug */ -#define AMD_IOMMU_PGSIZES (~0xFFFUL) +#define AMD_IOMMU_PGSIZES ((~0xFFFUL) & ~(2ULL << 38)) static DEFINE_RWLOCK(amd_iommu_devtable_lock); -- cgit v0.10.2 From 310aa95078443c7b7b56c60dbc55b7a11b946edb Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Sun, 2 Dec 2012 15:40:56 +0100 Subject: iommu/amd: Remove obsolete comment The AMD IOMMU driver only uses the page-sizes it gets from IOMMU core and uses the appropriate page-size. So this comment is not necessary. Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 98d74ab..c1c74e0 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -57,16 +57,6 @@ * physically contiguous memory regions it is mapping into page sizes * that we support. * - * Traditionally the IOMMU core just handed us the mappings directly, - * after making sure the size is an order of a 4KiB page and that the - * mapping has natural alignment. - * - * To retain this behavior, we currently advertise that we support - * all page sizes that are an order of 4KiB. - * - * If at some point we'd like to utilize the IOMMU core's new behavior, - * we could change this to advertise the real page sizes we support. - * * 512GB Pages are not supported due to a hardware bug */ #define AMD_IOMMU_PGSIZES ((~0xFFFUL) & ~(2ULL << 38)) -- cgit v0.10.2 From d856c13c11d81dfa545f927db8d31663d45bbc94 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 23 Nov 2012 08:58:05 -0300 Subject: UBI: replace memcpy with struct assignment This kind of memcpy() is error-prone. Its replacement with a struct assignment is prefered because it's type-safe and much easier to read. Found by coccinelle. Hand patched and reviewed. Tested by compilation only. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier struct_name; struct struct_name to; struct struct_name from; expression E; @@ -memcpy(&(to), &(from), E); +to = from; // Signed-off-by: Peter Senna Tschudin Signed-off-by: Ezequiel Garcia Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 344b4cb..fb59604 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -825,8 +825,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id) * No available PEBs to re-size the volume, clear the flag on * flash and exit. */ - memcpy(&vtbl_rec, &ubi->vtbl[vol_id], - sizeof(struct ubi_vtbl_record)); + vtbl_rec = ubi->vtbl[vol_id]; err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); if (err) ubi_err("cannot clean auto-resize flag for volume %d", diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 9f2ebd8..ec2c2dc 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -64,8 +64,7 @@ static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol) return 0; } - memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], - sizeof(struct ubi_vtbl_record)); + vtbl_rec = ubi->vtbl[vol->vol_id]; vtbl_rec.upd_marker = 1; mutex_lock(&ubi->device_mutex); @@ -93,8 +92,7 @@ static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol, dbg_gen("clear update marker for volume %d", vol->vol_id); - memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], - sizeof(struct ubi_vtbl_record)); + vtbl_rec = ubi->vtbl[vol->vol_id]; ubi_assert(vol->upd_marker && vtbl_rec.upd_marker); vtbl_rec.upd_marker = 0; diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 9169e58..99ef8a1 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -535,7 +535,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) } /* Change volume table record */ - memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); + vtbl_rec = ubi->vtbl[vol_id]; vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs); err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); if (err) -- cgit v0.10.2 From d1f3b65d2d6fdb4bf0edd4b67e86e191af48daee Mon Sep 17 00:00:00 2001 From: Nathan Williams Date: Thu, 22 Nov 2012 10:42:52 +1100 Subject: mtd cs553x_nand: Initialise ecc.strength before nand_scan() Loading cs553x_nand with Hynix H27U1G8F2BTR NAND flash causes this bug: kernel BUG at drivers/mtd/nand/nand_base.c:3345! invalid opcode: 0000 [#1] Modules linked in: cs553x_nand(+) vfat fat usb_storage ehci_hcd usbcore usb_comr Pid: 436, comm: modprobe Not tainted 3.6.7 #1 EIP: 0060:[] EFLAGS: 00010296 CPU: 0 EIP is at nand_scan_tail+0x64c/0x69c EAX: 00000034 EBX: cea6ed98 ECX: 00000000 EDX: 00000000 ESI: cea6ec00 EDI: cea6ec00 EBP: 20000000 ESP: cdd17e48 DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 CR0: 8005003b CR2: 0804e119 CR3: 0d850000 CR4: 00000090 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Process modprobe (pid: 436, ti=cdd16000 task=cdd1c320 task.ti=cdd16000) Stack: c12e962c c118f7ef 00000003 cea6ed98 d014b25c 20000000 fffff007 00000001 00000000 cdd53b00 d014b000 c1001021 cdd53b00 d01493c0 cdd53b00 cdd53b00 d01493c0 c1047f83 d014b4a0 00000000 cdd17f9c ce4be454 cdd17f48 cdd1c320 Call Trace: [] ? nand_scan+0x1b/0x4d [] ? init_module+0x25c/0x2de [cs553x_nand] [] ? 0xd014afff [] ? do_one_initcall+0x21/0x111 [] ? sys_init_module+0xe4/0x1261 [] ? task_work_run+0x36/0x43 [] ? syscall_call+0x7/0xb Code: fa ff ff c7 86 d8 00 00 00 01 00 00 00 e9 5f fc ff ff 68 f8 26 2e c1 e8 a7 EIP: [] nand_scan_tail+0x64c/0x69c SS:ESP 0068:cdd17e48 Initialising ecc.strength before the call to nand_scan() fixes this. Signed-off-by: Nathan Williams Cc: stable@vger.kernel.org [3.4+] Acked-by: Brian Norris Acked-by: Mike Dunn Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index adb6c3e..2cdeab8 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -237,6 +237,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) this->ecc.hwctl = cs_enable_hwecc; this->ecc.calculate = cs_calculate_ecc; this->ecc.correct = nand_correct_data; + this->ecc.strength = 1; /* Enable the following for a flash based bad block table */ this->bbt_options = NAND_BBT_USE_FLASH; @@ -247,8 +248,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) goto out_ior; } - this->ecc.strength = 1; - new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs); cs553x_mtd[cs] = new_mtd; -- cgit v0.10.2 From 98a9e2450667e497246449f96eab06eb3fb4d24b Mon Sep 17 00:00:00 2001 From: Liming Wang Date: Thu, 22 Nov 2012 14:58:09 +0800 Subject: mtd: m25p80: modify info for Micron N25Q128 Micron N25Q128 has two types of flash: - One is for 1.8v supply voltage, prefixed with "n25q128a11" and the jedec code is 0x20bb18. - Another is for 3v supply voltage, prefixed with "n25q128a13" and the jedec code is 0x20ba18. So modify the original type info and add another type for Micron N25Q128. Signed-off-by: Liming Wang Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index f402b67..4eeeb2d 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -661,7 +661,8 @@ static const struct spi_device_id m25p_ids[] = { { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, /* Micron */ - { "n25q128", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, + { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, + { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, /* Spansion -- single (large) sector size only, at least -- cgit v0.10.2 From b0bb6903c8fca2d5ebef1f8ae63d420eb931bb1e Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 19 Nov 2012 14:43:29 +0800 Subject: mtd: remove the de-select chip code in nand_release_device() The nand_get_device() does not select the chip, but nand_release_device() does de-select the chip. It is really strange. With the current code, nand_sync() will de-select the chip, even if the chip has never been selected. To make the balance of select/de-select chip, it's better to remove the de-select chip code in nand_release_device() which makes the code more clear. Signed-off-by: Huang Shijie Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 6eef7fb..861a87d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -130,15 +130,12 @@ static int check_offs_len(struct mtd_info *mtd, * nand_release_device - [GENERIC] release chip * @mtd: MTD device structure * - * Deselect, release chip lock and wake up anyone waiting on the device. + * Release chip lock and wake up anyone waiting on the device. */ static void nand_release_device(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - /* De-select the NAND device */ - chip->select_chip(mtd, -1); - /* Release the controller and the chip */ spin_lock(&chip->controller->lock); chip->controller->active = NULL; @@ -333,8 +330,10 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) i++; } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); - if (getchip) + if (getchip) { + chip->select_chip(mtd, -1); nand_release_device(mtd); + } return res; } @@ -952,6 +951,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ret = __nand_unlock(mtd, ofs, len, 0); out: + chip->select_chip(mtd, -1); nand_release_device(mtd); return ret; @@ -1016,6 +1016,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ret = __nand_unlock(mtd, ofs, len, 0x1); out: + chip->select_chip(mtd, -1); nand_release_device(mtd); return ret; @@ -1552,6 +1553,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, chipnr); } } + chip->select_chip(mtd, -1); ops->retlen = ops->len - (size_t) readlen; if (oob) @@ -1806,6 +1808,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, chipnr); } } + chip->select_chip(mtd, -1); ops->oobretlen = ops->ooblen - readlen; @@ -2188,8 +2191,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, chip->select_chip(mtd, chipnr); /* Check, if it is write protected */ - if (nand_check_wp(mtd)) - return -EIO; + if (nand_check_wp(mtd)) { + ret = -EIO; + goto err_out; + } realpage = (int)(to >> chip->page_shift); page = realpage & chip->pagemask; @@ -2201,8 +2206,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, chip->pagebuf = -1; /* Don't allow multipage oob writes with offset */ - if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) - return -EINVAL; + if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) { + ret = -EINVAL; + goto err_out; + } while (1) { int bytes = mtd->writesize; @@ -2253,6 +2260,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, ops->retlen = ops->len - writelen; if (unlikely(oob)) ops->oobretlen = ops->ooblen; + +err_out: + chip->select_chip(mtd, -1); return ret; } @@ -2379,8 +2389,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); /* Check, if it is write protected */ - if (nand_check_wp(mtd)) + if (nand_check_wp(mtd)) { + chip->select_chip(mtd, -1); return -EROFS; + } /* Invalidate the page cache, if we write to the cached page */ if (page == chip->pagebuf) @@ -2393,6 +2405,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, else status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); + chip->select_chip(mtd, -1); + if (status) return status; @@ -2625,6 +2639,7 @@ erase_exit: ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; /* Deselect and wake up anyone waiting on the device */ + chip->select_chip(mtd, -1); nand_release_device(mtd); /* Do call back function */ -- cgit v0.10.2 From 6a8214aa3d323d2e185523ea112116759bc3c5ce Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Mon, 19 Nov 2012 14:43:30 +0800 Subject: mtd: remove the "chip" parameter in nand_get_device() There are two reasons to remove the "chip" parameter in nand_get_device(): [1] The nand_release_device() does not have the "chip" parameter. [2] We can get the nand_chip by the mtd->priv field. This patch removes the "chip" parameter in nand_get_device(). Signed-off-by: Huang Shijie Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 861a87d..55c2883 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -93,8 +93,7 @@ static struct nand_ecclayout nand_oob_128 = { .length = 78} } }; -static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, - int new_state); +static int nand_get_device(struct mtd_info *mtd, int new_state); static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops); @@ -300,7 +299,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) if (getchip) { chipnr = (int)(ofs >> chip->chip_shift); - nand_get_device(chip, mtd, FL_READING); + nand_get_device(mtd, FL_READING); /* Select the NAND device */ chip->select_chip(mtd, chipnr); @@ -382,7 +381,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) struct mtd_oob_ops ops; loff_t wr_ofs = ofs; - nand_get_device(chip, mtd, FL_WRITING); + nand_get_device(mtd, FL_WRITING); ops.datbuf = NULL; ops.oobbuf = buf; @@ -749,15 +748,15 @@ static void panic_nand_get_device(struct nand_chip *chip, /** * nand_get_device - [GENERIC] Get chip for selected access - * @chip: the nand chip descriptor * @mtd: MTD device structure * @new_state: the state which is requested * * Get the device and lock it for exclusive access */ static int -nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) +nand_get_device(struct mtd_info *mtd, int new_state) { + struct nand_chip *chip = mtd->priv; spinlock_t *lock = &chip->controller->lock; wait_queue_head_t *wq = &chip->controller->wq; DECLARE_WAITQUEUE(wait, current); @@ -933,7 +932,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) if (ofs + len == mtd->size) len -= mtd->erasesize; - nand_get_device(chip, mtd, FL_UNLOCKING); + nand_get_device(mtd, FL_UNLOCKING); /* Shift to get chip number */ chipnr = ofs >> chip->chip_shift; @@ -983,7 +982,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) if (check_offs_len(mtd, ofs, len)) ret = -EINVAL; - nand_get_device(chip, mtd, FL_LOCKING); + nand_get_device(mtd, FL_LOCKING); /* Shift to get chip number */ chipnr = ofs >> chip->chip_shift; @@ -1581,11 +1580,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) { - struct nand_chip *chip = mtd->priv; struct mtd_oob_ops ops; int ret; - nand_get_device(chip, mtd, FL_READING); + nand_get_device(mtd, FL_READING); ops.len = len; ops.datbuf = buf; ops.oobbuf = NULL; @@ -1832,7 +1830,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, static int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - struct nand_chip *chip = mtd->priv; int ret = -ENOTSUPP; ops->retlen = 0; @@ -1844,7 +1841,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, return -EINVAL; } - nand_get_device(chip, mtd, FL_READING); + nand_get_device(mtd, FL_READING); switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -2314,11 +2311,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { - struct nand_chip *chip = mtd->priv; struct mtd_oob_ops ops; int ret; - nand_get_device(chip, mtd, FL_WRITING); + nand_get_device(mtd, FL_WRITING); ops.len = len; ops.datbuf = (uint8_t *)buf; ops.oobbuf = NULL; @@ -2424,7 +2420,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { - struct nand_chip *chip = mtd->priv; int ret = -ENOTSUPP; ops->retlen = 0; @@ -2436,7 +2431,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, return -EINVAL; } - nand_get_device(chip, mtd, FL_WRITING); + nand_get_device(mtd, FL_WRITING); switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -2529,7 +2524,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, return -EINVAL; /* Grab the lock and see if the device is available */ - nand_get_device(chip, mtd, FL_ERASING); + nand_get_device(mtd, FL_ERASING); /* Shift to get first page */ page = (int)(instr->addr >> chip->page_shift); @@ -2675,12 +2670,10 @@ erase_exit: */ static void nand_sync(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; - pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ - nand_get_device(chip, mtd, FL_SYNCING); + nand_get_device(mtd, FL_SYNCING); /* Release it and go back */ nand_release_device(mtd); } @@ -2766,9 +2759,7 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, */ static int nand_suspend(struct mtd_info *mtd) { - struct nand_chip *chip = mtd->priv; - - return nand_get_device(chip, mtd, FL_PM_SUSPENDED); + return nand_get_device(mtd, FL_PM_SUSPENDED); } /** -- cgit v0.10.2 From e7e46168bcc768fa31628d3d080ac9ee7b553b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 23 Nov 2012 07:51:31 +0100 Subject: mtd: bcm47xxnflash: define some magic numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index e42e182..672dc90 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -22,6 +22,15 @@ #define NFLASH_SECTOR_SIZE 512 +#define NCTL_CMD0 0x00010000 +#define NCTL_CMD1W 0x00080000 +#define NCTL_READ 0x00100000 +#define NCTL_SPECADDR 0x01000000 +#define NCTL_READY 0x04000000 +#define NCTL_ERR 0x08000000 +#define NCTL_CSA 0x40000000 +#define NCTL_START 0x80000000 + /************************************************** * Various helpers **************************************************/ @@ -35,9 +44,9 @@ static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code) { int i = 0; - bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, 0x80000000 | code); + bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code); for (i = 0; i < NFLASH_READY_RETRIES; i++) { - if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & 0x80000000)) { + if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) { i = 0; break; } @@ -54,7 +63,7 @@ static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc) int i; for (i = 0; i < NFLASH_READY_RETRIES; i++) { - if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & 0x04000000) { + if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) { if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & BCMA_CC_NFLASH_CTL_ERR) { pr_err("Error on polling\n"); @@ -99,8 +108,8 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, b47n->curr_page_addr); /* Prepare to read */ - ctlcode = 0x40000000 | 0x00080000 | 0x00040000 | 0x00020000 | - 0x00010000; + ctlcode = NCTL_CSA | NCTL_CMD1W | 0x00040000 | 0x00020000 | + NCTL_CMD0; ctlcode |= NAND_CMD_READSTART << 8; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) return; @@ -109,9 +118,9 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, /* Eventually read some data :) */ for (i = 0; i < toread; i += 4, dest++) { - ctlcode = 0x40000000 | 0x30000000 | 0x00100000; + ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ; if (i == toread - 4) /* Last read goes without that */ - ctlcode &= ~0x40000000; + ctlcode &= ~NCTL_CSA; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) return; @@ -160,7 +169,7 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, pr_warn("Chip reset not implemented yet\n"); break; case NAND_CMD_READID: - ctlcode = 0x40000000 | 0x01000000 | 0x00080000 | 0x00010000; + ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0; ctlcode |= NAND_CMD_READID; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) { pr_err("READID error\n"); @@ -168,14 +177,14 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, } /* - * Reading is specific, last one has to go without 0x40000000 + * Reading is specific, last one has to go without NCTL_CSA * bit. We don't know how many reads NAND subsystem is going * to perform, so cache everything. */ for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) { - ctlcode = 0x40000000 | 0x00100000; + ctlcode = NCTL_CSA | NCTL_READ; if (i == ARRAY_SIZE(b47n->id_data) - 1) - ctlcode &= ~0x40000000; + ctlcode &= ~NCTL_CSA; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) { pr_err("READID error\n"); -- cgit v0.10.2 From a6b3ed29ae3fd9853280d4f6a9275c43fb4e1c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 23 Nov 2012 09:58:11 +0100 Subject: mtd: bcm47xxnflash: support NAND_CMD_STATUS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index 672dc90..ece343c 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -156,6 +156,7 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, { struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + struct bcma_drv_cc *cc = b47n->cc; u32 ctlcode; int i; @@ -196,6 +197,11 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, } break; + case NAND_CMD_STATUS: + ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS; + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) + pr_err("STATUS command error\n"); + break; case NAND_CMD_READ0: break; case NAND_CMD_READOOB: @@ -213,6 +219,7 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) { struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + struct bcma_drv_cc *cc = b47n->cc; u32 tmp = 0; switch (b47n->curr_command) { @@ -223,6 +230,10 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) return 0; } return b47n->id_data[b47n->curr_column++]; + case NAND_CMD_STATUS: + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_READ)) + return 0; + return bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xff; case NAND_CMD_READOOB: bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4); return tmp & 0xFF; -- cgit v0.10.2 From ca6a24893073414c549920d93bac57d46d7f3e1e Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Thu, 22 Nov 2012 18:31:28 +0100 Subject: mted: nand_wait_ready timeout fix nand_wait_ready timeout should not assume HZ=100. Make it independent of HZ value by using msecs_to_jiffies. Signed-off-by: Matthieu CASTET Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 55c2883..7738432 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -490,7 +490,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) void nand_wait_ready(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - unsigned long timeo = jiffies + 2; + unsigned long timeo = jiffies + msecs_to_jiffies(20); /* 400ms timeout */ if (in_interrupt() || oops_in_progress) -- cgit v0.10.2 From 2fd71a294a0aac407ec69e04916dc28eb39c8ac0 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Thu, 22 Nov 2012 18:33:40 +0100 Subject: mtd: nand: print flash size during detection This help to detect bad flash identification in case the size is not present on the name (ONFI). Signed-off-by: Matthieu CASTET Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 7738432..6f58e16 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3293,10 +3293,10 @@ ident_done: chip->cmdfunc = nand_command_lp; pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," - " page size: %d, OOB size: %d\n", + " %dMiB, page size: %d, OOB size: %d\n", *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, chip->onfi_version ? chip->onfi_params.model : type->name, - mtd->writesize, mtd->oobsize); + (int)(chip->chipsize >> 20), mtd->writesize, mtd->oobsize); return type; } -- cgit v0.10.2 From 64b37b2a63eb2f80b65c7185f0013f8ffc637ae3 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Tue, 6 Nov 2012 11:51:44 +0100 Subject: mtd: nand: add NAND_BUSWIDTH_AUTO to autodetect bus width The driver call nand_scan_ident in 8 bit mode, then readid or onfi detection are done (and detect bus width). The driver should update its bus width before calling nand_scan_tail. This work because readid and onfi are read work 8 byte mode. Note that nand_scan_ident send command (NAND_CMD_RESET, NAND_CMD_READID, NAND_CMD_PARAM), address and read data The ONFI specificication is not very clear for x16 device if high byte of address should be driven to 0, but according to [1] it should be ok to not drive it during autodetection. [1] 3.3.2. Target Initialization [...] The Read ID and Read Parameter Page commands only use the lower 8-bits of the data bus. The host shall not issue commands that use a word data width on x16 devices until the host determines the device supports a 16-bit data bus width in the parameter page. Signed-off-by: Matthieu CASTET Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 6f58e16..5851c51 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3250,11 +3250,15 @@ ident_done: break; } - /* - * Check, if buswidth is correct. Hardware drivers should set - * chip correct! - */ - if (busw != (chip->options & NAND_BUSWIDTH_16)) { + if (chip->options & NAND_BUSWIDTH_AUTO) { + WARN_ON(chip->options & NAND_BUSWIDTH_16); + chip->options |= busw; + nand_set_defaults(chip, busw); + } else if (busw != (chip->options & NAND_BUSWIDTH_16)) { + /* + * Check, if buswidth is correct. Hardware drivers should set + * chip correct! + */ pr_info("NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 9d8a604..7ccb3c5 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -219,6 +219,13 @@ typedef enum { #define NAND_OWN_BUFFERS 0x00020000 /* Chip may not exist, so silence any errors in scan */ #define NAND_SCAN_SILENT_NODEV 0x00040000 +/* + * Autodetect nand buswidth with readid/onfi. + * This suppose the driver will configure the hardware in 8 bits mode + * when calling nand_scan_ident, and update its configuration + * before calling nand_scan_tail. + */ +#define NAND_BUSWIDTH_AUTO 0x00080000 /* Options set by nand scan */ /* Nand scan has allocated controller struct */ -- cgit v0.10.2 From ff3206b2450499203532af2505a7f6f8413e92c0 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Tue, 6 Nov 2012 11:51:43 +0100 Subject: mtd: nand: onfi need to be probed in 8 bits mode - NAND_CMD_READID want an address that it is not scaled on x16 device (it is always 0x20) - NAND_CMD_PARAM want 8 bits data Signed-off-by: Matthieu CASTET Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5851c51..0ac49ca 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2857,6 +2857,8 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int i; int val; + /* ONFI need to be probed in 8 bits mode */ + WARN_ON(chip->options & NAND_BUSWIDTH_16); /* Try ONFI for unknown chip or LP */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || -- cgit v0.10.2 From 070c32223ae8a724a190ea769104ea41567e3673 Mon Sep 17 00:00:00 2001 From: Harald Nordgard-Hansen Date: Fri, 23 Nov 2012 23:11:03 +0100 Subject: mtd: fix recovery after failed write-buffer operation in cfi_cmdset_0002.c When working on a problem with some flash chips that lock up during write-buffer operations, I think there may be a bug in the linux handling of chips using cfi_cmdset_0002.c. The datasheets I have found for a number of these chips all specify that when aborting a write-buffer command, it is not enough to use the standard reset. Rather a "write-to-buffer-reset command" is needed. This command is quite similar for all chips, the main variance seem to be if the final 0xF0 can go to any address or must go to addr_unlock1. The bug is then in the recovery handling when timing out at the end of do_write_buffer, where using the normal reset command is not sufficient. Without this change, if the write-buffer command fails then any following operations on the flash also fail. Signed-off-by: Harald Nordgard-Hansen Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 5ff5c4a..b861972 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -1536,8 +1536,20 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, UDELAY(map, chip, adr, 1); } - /* reset on all failures. */ - map_write( map, CMD(0xF0), chip->start ); + /* + * Recovery from write-buffer programming failures requires + * the write-to-buffer-reset sequence. Since the last part + * of the sequence also works as a normal reset, we can run + * the same commands regardless of why we are here. + * See e.g. + * http://www.spansion.com/Support/Application%20Notes/MirrorBit_Write_Buffer_Prog_Page_Buffer_Read_AN.pdf + */ + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, + cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, + cfi->device_type, NULL); + cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, chip->start, map, cfi, + cfi->device_type, NULL); xip_enable(map, chip, adr); /* FIXME - should have reset delay before continuing */ -- cgit v0.10.2 From c0c70d9ee6569150ff6a10f9d3c50c63c917e3a1 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 27 Nov 2012 18:50:31 +0800 Subject: mtd: at91: atmel_nand: return bit flips for the PMECC read_page() This patch fix pmecc's read_page() to return maximum number of bitflips, 0 if uncorrectable. In the commit: 3f91e94f7f511de74c0d2abe08672ccdbdd1961c ("mtd: nand: read_page() returns max_bitflips ()"), The ecc.read_page() is changed to return the maximum number of bitflips. And when meet uncorrectable bitflips it needs to return 0. See the comment in nand.h: * @read_page: function to read a page according to the ECC generator * requirements; returns maximum number of bitflips corrected in * any single ECC step, 0 if bitflips uncorrectable, -EIO hw error Signed-off-by: Josh Wu Reviewed-by: Mike Dunn Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index c918386..1669d27 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -723,6 +723,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, struct atmel_nand_host *host = nand_chip->priv; int i, err_nbr, eccbytes; uint8_t *buf_pos; + int total_err = 0; eccbytes = nand_chip->ecc.bytes; for (i = 0; i < eccbytes; i++) @@ -750,12 +751,13 @@ normal_check: pmecc_correct_data(mtd, buf_pos, ecc, i, host->pmecc_bytes_per_sector, err_nbr); mtd->ecc_stats.corrected += err_nbr; + total_err += err_nbr; } } pmecc_stat >>= 1; } - return 0; + return total_err; } static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, @@ -767,6 +769,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, uint32_t *eccpos = chip->ecc.layout->eccpos; uint32_t stat; unsigned long end_time; + int bitflips = 0; pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); @@ -789,11 +792,14 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, } stat = pmecc_readl_relaxed(host->ecc, ISR); - if (stat != 0) - if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0) - return -EIO; + if (stat != 0) { + bitflips = pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]); + if (bitflips < 0) + /* uncorrectable errors */ + return 0; + } - return 0; + return bitflips; } static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, -- cgit v0.10.2 From e5f9570319771bb0a5afc792b34fbd5564b935c8 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 30 Nov 2012 17:24:18 -0500 Subject: nfsd4: discard some unused nfsd4_verify xdr code Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b775366..3bf8a9d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1106,31 +1106,14 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s static __be32 nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) { -#if 0 - struct nfsd4_compoundargs save = { - .p = argp->p, - .end = argp->end, - .rqstp = argp->rqstp, - }; - u32 ve_bmval[2]; - struct iattr ve_iattr; /* request */ - struct nfs4_acl *ve_acl; /* request */ -#endif DECODE_HEAD; if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) goto out; /* For convenience's sake, we compare raw xdr'd attributes in - * nfsd4_proc_verify; however we still decode here just to return - * correct error in case of bad xdr. */ -#if 0 - status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl); - if (status == nfserr_inval) { - status = nfserrno(status); - goto out; - } -#endif + * nfsd4_proc_verify */ + READ_BUF(4); READ32(verify->ve_attrlen); READ_BUF(verify->ve_attrlen); -- cgit v0.10.2 From 043958395a6b91863046b0cd7cae9c67fa845144 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 29 Nov 2012 11:40:38 -0500 Subject: NFSD: Lock state before calling fault injection function Each function touches state in some way, so getting the lock earlier can help simplify code. Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 0278112..4b385a1 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -51,7 +51,9 @@ static int nfsd_inject_set(void *op_ptr, u64 val) else printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val); + nfs4_lock_state(); op->func(val); + nfs4_unlock_state(); return 0; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b1aa577..8e19c69 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4611,13 +4611,11 @@ void nfsd_forget_clients(u64 num) int count = 0; struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); - nfs4_lock_state(); list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { expire_client(clp); if (++count == num) break; } - nfs4_unlock_state(); printk(KERN_INFO "NFSD: Forgot %d clients", count); } @@ -4653,25 +4651,15 @@ static int nfsd_release_n_owners(u64 num, bool is_open_owner, void nfsd_forget_locks(u64 num) { - int count; struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); - - nfs4_lock_state(); - count = nfsd_release_n_owners(num, false, release_lockowner_sop, nn); - nfs4_unlock_state(); - + int count = nfsd_release_n_owners(num, false, release_lockowner_sop, nn); printk(KERN_INFO "NFSD: Forgot %d locks", count); } void nfsd_forget_openowners(u64 num) { - int count; struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); - - nfs4_lock_state(); - count = nfsd_release_n_owners(num, true, release_openowner_sop, nn); - nfs4_unlock_state(); - + int count = nfsd_release_n_owners(num, true, release_openowner_sop, nn); printk(KERN_INFO "NFSD: Forgot %d open owners", count); } @@ -4704,10 +4692,8 @@ void nfsd_forget_delegations(u64 num) count = nfsd_process_n_delegations(num, &victims); spin_unlock(&recall_lock); - nfs4_lock_state(); list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) unhash_delegation(dp); - nfs4_unlock_state(); printk(KERN_INFO "NFSD: Forgot %d delegations", count); } -- cgit v0.10.2 From 44e34da60b24ca14666534b61cc9579aa4e1eac5 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 29 Nov 2012 11:40:39 -0500 Subject: NFSD: Clean up forgetting clients I added in a generic for-each loop that takes a pass over the client_lru list for the current net namespace and calls some function. The next few patches will update other operations to use this function as well. A value of 0 still means "forget everything that is found". Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 2c4b2e2..964b554 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -92,5 +92,8 @@ struct nfsd_net { time_t nfsd4_grace; }; +/* Simple check to find out if a given net was properly initialized */ +#define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl) + extern int nfsd_net_id; #endif /* __NFSD_NETNS_H__ */ diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 8e19c69..2478c89 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4605,19 +4605,34 @@ nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn) #ifdef CONFIG_NFSD_FAULT_INJECTION -void nfsd_forget_clients(u64 num) +u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) +{ + expire_client(clp); + return 1; +} + +u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) { struct nfs4_client *clp, *next; - int count = 0; + u64 count = 0; struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); + if (!nfsd_netns_ready(nn)) + return 0; + list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { - expire_client(clp); - if (++count == num) + count += func(clp, max - count); + if ((max != 0) && (count >= max)) break; } - printk(KERN_INFO "NFSD: Forgot %d clients", count); + return count; +} + +void nfsd_forget_clients(u64 num) +{ + u64 count = nfsd_for_n_state(num, nfsd_forget_client); + printk(KERN_INFO "NFSD: Forgot %llu clients", count); } static void release_lockowner_sop(struct nfs4_stateowner *sop) -- cgit v0.10.2 From fc29171f5b3257694bf508cf4ae51970c97af78c Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 29 Nov 2012 11:40:40 -0500 Subject: NFSD: Clean up forgetting locks I use the new "forget_n_state()" function to iterate through each client first when searching for locks. This may slow down forgetting locks a little bit, but it implements most of the code needed to forget a specified client's locks. Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2478c89..46bece4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4611,6 +4611,32 @@ u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) return 1; } +static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_lockowner *)) +{ + struct nfs4_openowner *oop; + struct nfs4_lockowner *lop, *lo_next; + struct nfs4_ol_stateid *stp, *st_next; + u64 count = 0; + + list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { + list_for_each_entry_safe(stp, st_next, &oop->oo_owner.so_stateids, st_perstateowner) { + list_for_each_entry_safe(lop, lo_next, &stp->st_lockowners, lo_perstateid) { + if (func) + func(lop); + if (++count == max) + return count; + } + } + } + + return count; +} + +u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) +{ + return nfsd_foreach_client_lock(clp, max, release_lockowner); +} + u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) { struct nfs4_client *clp, *next; @@ -4635,11 +4661,6 @@ void nfsd_forget_clients(u64 num) printk(KERN_INFO "NFSD: Forgot %llu clients", count); } -static void release_lockowner_sop(struct nfs4_stateowner *sop) -{ - release_lockowner(lockowner(sop)); -} - static void release_openowner_sop(struct nfs4_stateowner *sop) { release_openowner(openowner(sop)); @@ -4666,9 +4687,8 @@ static int nfsd_release_n_owners(u64 num, bool is_open_owner, void nfsd_forget_locks(u64 num) { - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); - int count = nfsd_release_n_owners(num, false, release_lockowner_sop, nn); - printk(KERN_INFO "NFSD: Forgot %d locks", count); + u64 count = nfsd_for_n_state(num, nfsd_forget_client_locks); + printk(KERN_INFO "NFSD: Forgot %llu locks", count); } void nfsd_forget_openowners(u64 num) -- cgit v0.10.2 From 4dbdbda84f963312e0b5dfdf2dfbf64de047dd44 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 29 Nov 2012 11:40:41 -0500 Subject: NFSD: Clean up forgetting openowners Using "forget_n_state()" forces me to implement the code needed to forget a specific client's openowners. Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 46bece4..00d4398 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4637,6 +4637,26 @@ u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) return nfsd_foreach_client_lock(clp, max, release_lockowner); } +static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) +{ + struct nfs4_openowner *oop, *next; + u64 count = 0; + + list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { + if (func) + func(oop); + if (++count == max) + break; + } + + return count; +} + +u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) +{ + return nfsd_foreach_client_open(clp, max, release_openowner); +} + u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) { struct nfs4_client *clp, *next; @@ -4661,30 +4681,6 @@ void nfsd_forget_clients(u64 num) printk(KERN_INFO "NFSD: Forgot %llu clients", count); } -static void release_openowner_sop(struct nfs4_stateowner *sop) -{ - release_openowner(openowner(sop)); -} - -static int nfsd_release_n_owners(u64 num, bool is_open_owner, - void (*release_sop)(struct nfs4_stateowner *), - struct nfsd_net *nn) -{ - int i, count = 0; - struct nfs4_stateowner *sop, *next; - - for (i = 0; i < OWNER_HASH_SIZE; i++) { - list_for_each_entry_safe(sop, next, &nn->ownerstr_hashtbl[i], so_strhash) { - if (sop->so_is_open_owner != is_open_owner) - continue; - release_sop(sop); - if (++count == num) - return count; - } - } - return count; -} - void nfsd_forget_locks(u64 num) { u64 count = nfsd_for_n_state(num, nfsd_forget_client_locks); @@ -4693,9 +4689,8 @@ void nfsd_forget_locks(u64 num) void nfsd_forget_openowners(u64 num) { - struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); - int count = nfsd_release_n_owners(num, true, release_openowner_sop, nn); - printk(KERN_INFO "NFSD: Forgot %d open owners", count); + u64 count = nfsd_for_n_state(num, nfsd_forget_client_openowners); + printk(KERN_INFO "NFSD: Forgot %llu open owners", count); } static int nfsd_process_n_delegations(u64 num, struct list_head *list) -- cgit v0.10.2 From 269de30f10604710dde8d544748b5b6c748b7de8 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 29 Nov 2012 11:40:42 -0500 Subject: NFSD: Clean up forgetting and recalling delegations Once I have a client, I can easily use its delegation list rather than searching the file hash table for delegations to remove. Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 00d4398..dc7c22f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4657,6 +4657,52 @@ u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) return nfsd_foreach_client_open(clp, max, release_openowner); } +static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, + struct list_head *victims) +{ + struct nfs4_delegation *dp, *next; + u64 count = 0; + + list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { + if (victims) + list_move(&dp->dl_recall_lru, victims); + if (++count == max) + break; + } + return count; +} + +u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max) +{ + struct nfs4_delegation *dp, *next; + LIST_HEAD(victims); + u64 count; + + spin_lock(&recall_lock); + count = nfsd_find_all_delegations(clp, max, &victims); + spin_unlock(&recall_lock); + + list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) + unhash_delegation(dp); + + return count; +} + +u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max) +{ + struct nfs4_delegation *dp, *next; + LIST_HEAD(victims); + u64 count; + + spin_lock(&recall_lock); + count = nfsd_find_all_delegations(clp, max, &victims); + list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) + nfsd_break_one_deleg(dp); + spin_unlock(&recall_lock); + + return count; +} + u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) { struct nfs4_client *clp, *next; @@ -4693,56 +4739,16 @@ void nfsd_forget_openowners(u64 num) printk(KERN_INFO "NFSD: Forgot %llu open owners", count); } -static int nfsd_process_n_delegations(u64 num, struct list_head *list) -{ - int i, count = 0; - struct nfs4_file *fp, *fnext; - struct nfs4_delegation *dp, *dnext; - - for (i = 0; i < FILE_HASH_SIZE; i++) { - list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) { - list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) { - list_move(&dp->dl_recall_lru, list); - if (++count == num) - return count; - } - } - } - - return count; -} - void nfsd_forget_delegations(u64 num) { - unsigned int count; - LIST_HEAD(victims); - struct nfs4_delegation *dp, *dnext; - - spin_lock(&recall_lock); - count = nfsd_process_n_delegations(num, &victims); - spin_unlock(&recall_lock); - - list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) - unhash_delegation(dp); - - printk(KERN_INFO "NFSD: Forgot %d delegations", count); + u64 count = nfsd_for_n_state(num, nfsd_forget_client_delegations); + printk(KERN_INFO "NFSD: Forgot %llu delegations", count); } void nfsd_recall_delegations(u64 num) { - unsigned int count; - LIST_HEAD(victims); - struct nfs4_delegation *dp, *dnext; - - spin_lock(&recall_lock); - count = nfsd_process_n_delegations(num, &victims); - list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) { - list_del(&dp->dl_recall_lru); - nfsd_break_one_deleg(dp); - } - spin_unlock(&recall_lock); - - printk(KERN_INFO "NFSD: Recalled %d delegations", count); + u64 count = nfsd_for_n_state(num, nfsd_recall_client_delegations); + printk(KERN_INFO "NFSD: Recalled %llu delegations", count); } #endif /* CONFIG_NFSD_FAULT_INJECTION */ -- cgit v0.10.2 From 8ce54e0d82730ece61737c9fd7b61b28ab8c3390 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 29 Nov 2012 11:40:43 -0500 Subject: NFSD: Fault injection operations take a per-client forget function The eventual goal is to forget state based on ip address, so it makes sense to call this function in a for-each-client loop until the correct amount of state is forgotten. I also use this patch as an opportunity to rename the forget function from "func()" to "forget()". Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 4b385a1..bf6161a 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -13,29 +13,29 @@ struct nfsd_fault_inject_op { char *file; - void (*func)(u64); + u64 (*forget)(struct nfs4_client *, u64); }; static struct nfsd_fault_inject_op inject_ops[] = { { .file = "forget_clients", - .func = nfsd_forget_clients, + .forget = nfsd_forget_client, }, { .file = "forget_locks", - .func = nfsd_forget_locks, + .forget = nfsd_forget_client_locks, }, { .file = "forget_openowners", - .func = nfsd_forget_openowners, + .forget = nfsd_forget_client_openowners, }, { .file = "forget_delegations", - .func = nfsd_forget_delegations, + .forget = nfsd_forget_client_delegations, }, { .file = "recall_delegations", - .func = nfsd_recall_delegations, + .forget = nfsd_recall_client_delegations, }, }; @@ -44,6 +44,7 @@ static struct dentry *debug_dir; static int nfsd_inject_set(void *op_ptr, u64 val) { + u64 count = 0; struct nfsd_fault_inject_op *op = op_ptr; if (val == 0) @@ -52,8 +53,9 @@ static int nfsd_inject_set(void *op_ptr, u64 val) printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val); nfs4_lock_state(); - op->func(val); + count = nfsd_for_n_state(val, op->forget); nfs4_unlock_state(); + printk(KERN_INFO "NFSD: %s: found %llu", op->file, count); return 0; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index dc7c22f..ab45cdd 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4721,36 +4721,6 @@ u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) return count; } -void nfsd_forget_clients(u64 num) -{ - u64 count = nfsd_for_n_state(num, nfsd_forget_client); - printk(KERN_INFO "NFSD: Forgot %llu clients", count); -} - -void nfsd_forget_locks(u64 num) -{ - u64 count = nfsd_for_n_state(num, nfsd_forget_client_locks); - printk(KERN_INFO "NFSD: Forgot %llu locks", count); -} - -void nfsd_forget_openowners(u64 num) -{ - u64 count = nfsd_for_n_state(num, nfsd_forget_client_openowners); - printk(KERN_INFO "NFSD: Forgot %llu open owners", count); -} - -void nfsd_forget_delegations(u64 num) -{ - u64 count = nfsd_for_n_state(num, nfsd_forget_client_delegations); - printk(KERN_INFO "NFSD: Forgot %llu delegations", count); -} - -void nfsd_recall_delegations(u64 num) -{ - u64 count = nfsd_for_n_state(num, nfsd_recall_client_delegations); - printk(KERN_INFO "NFSD: Recalled %llu delegations", count); -} - #endif /* CONFIG_NFSD_FAULT_INJECTION */ /* initialization to perform at module load time: */ diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index b542bf2..423ac64 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -501,11 +501,13 @@ extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time); #ifdef CONFIG_NFSD_FAULT_INJECTION int nfsd_fault_inject_init(void); void nfsd_fault_inject_cleanup(void); -void nfsd_forget_clients(u64); -void nfsd_forget_locks(u64); -void nfsd_forget_openowners(u64); -void nfsd_forget_delegations(u64); -void nfsd_recall_delegations(u64); +u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64)); + +u64 nfsd_forget_client(struct nfs4_client *, u64); +u64 nfsd_forget_client_locks(struct nfs4_client*, u64); +u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); +u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); +u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); #else /* CONFIG_NFSD_FAULT_INJECTION */ static inline int nfsd_fault_inject_init(void) { return 0; } static inline void nfsd_fault_inject_cleanup(void) {} -- cgit v0.10.2 From 184c18471f7d0963ad5752692c4b441a546d88f1 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 29 Nov 2012 11:40:44 -0500 Subject: NFSD: Reading a fault injection file prints a state count I also log basic information that I can figure out about the type of state (such as number of locks for each client IP address). This can be useful for checking that state was actually dropped and later for checking if the client was able to recover. Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index bf6161a..545f8e4 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -14,28 +14,34 @@ struct nfsd_fault_inject_op { char *file; u64 (*forget)(struct nfs4_client *, u64); + u64 (*print)(struct nfs4_client *, u64); }; static struct nfsd_fault_inject_op inject_ops[] = { { .file = "forget_clients", .forget = nfsd_forget_client, + .print = nfsd_print_client, }, { .file = "forget_locks", .forget = nfsd_forget_client_locks, + .print = nfsd_print_client_locks, }, { .file = "forget_openowners", .forget = nfsd_forget_client_openowners, + .print = nfsd_print_client_openowners, }, { .file = "forget_delegations", .forget = nfsd_forget_client_delegations, + .print = nfsd_print_client_delegations, }, { .file = "recall_delegations", .forget = nfsd_recall_client_delegations, + .print = nfsd_print_client_delegations, }, }; @@ -59,9 +65,12 @@ static int nfsd_inject_set(void *op_ptr, u64 val) return 0; } -static int nfsd_inject_get(void *data, u64 *val) +static int nfsd_inject_get(void *op_ptr, u64 *val) { - *val = 0; + struct nfsd_fault_inject_op *op = op_ptr; + nfs4_lock_state(); + *val = nfsd_for_n_state(0, op->print); + nfs4_unlock_state(); return 0; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ab45cdd..9fb8e52 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4611,6 +4611,22 @@ u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) return 1; } +u64 nfsd_print_client(struct nfs4_client *clp, u64 num) +{ + char buf[INET6_ADDRSTRLEN]; + rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, 129); + printk(KERN_INFO "NFS Client: %s\n", buf); + return 1; +} + +static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, + const char *type) +{ + char buf[INET6_ADDRSTRLEN]; + rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, 129); + printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); +} + static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_lockowner *)) { struct nfs4_openowner *oop; @@ -4637,6 +4653,13 @@ u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) return nfsd_foreach_client_lock(clp, max, release_lockowner); } +u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max) +{ + u64 count = nfsd_foreach_client_lock(clp, max, NULL); + nfsd_print_count(clp, count, "locked files"); + return count; +} + static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) { struct nfs4_openowner *oop, *next; @@ -4657,6 +4680,13 @@ u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) return nfsd_foreach_client_open(clp, max, release_openowner); } +u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max) +{ + u64 count = nfsd_foreach_client_open(clp, max, NULL); + nfsd_print_count(clp, count, "open files"); + return count; +} + static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, struct list_head *victims) { @@ -4703,6 +4733,18 @@ u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max) return count; } +u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max) +{ + u64 count = 0; + + spin_lock(&recall_lock); + count = nfsd_find_all_delegations(clp, max, NULL); + spin_unlock(&recall_lock); + + nfsd_print_count(clp, count, "delegations"); + return count; +} + u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) { struct nfs4_client *clp, *next; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 423ac64..4017f35 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -508,6 +508,11 @@ u64 nfsd_forget_client_locks(struct nfs4_client*, u64); u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); + +u64 nfsd_print_client(struct nfs4_client *, u64); +u64 nfsd_print_client_locks(struct nfs4_client *, u64); +u64 nfsd_print_client_openowners(struct nfs4_client *, u64); +u64 nfsd_print_client_delegations(struct nfs4_client *, u64); #else /* CONFIG_NFSD_FAULT_INJECTION */ static inline int nfsd_fault_inject_init(void) { return 0; } static inline void nfsd_fault_inject_cleanup(void) {} -- cgit v0.10.2 From d7cc431edd0a6c69a88b5ff1e304af50bfb2270e Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 29 Nov 2012 11:40:45 -0500 Subject: NFSD: Add a custom file operations structure for fault injection Controlling the read and write functions allows me to add in "forget client w.x.y.z", since we won't be limited to reading and writing only u64 values. Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 545f8e4..19f9094 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "state.h" @@ -48,10 +49,9 @@ static struct nfsd_fault_inject_op inject_ops[] = { static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op); static struct dentry *debug_dir; -static int nfsd_inject_set(void *op_ptr, u64 val) +static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val) { u64 count = 0; - struct nfsd_fault_inject_op *op = op_ptr; if (val == 0) printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file); @@ -62,19 +62,61 @@ static int nfsd_inject_set(void *op_ptr, u64 val) count = nfsd_for_n_state(val, op->forget); nfs4_unlock_state(); printk(KERN_INFO "NFSD: %s: found %llu", op->file, count); - return 0; } -static int nfsd_inject_get(void *op_ptr, u64 *val) +static void nfsd_inject_get(struct nfsd_fault_inject_op *op, u64 *val) { - struct nfsd_fault_inject_op *op = op_ptr; nfs4_lock_state(); *val = nfsd_for_n_state(0, op->print); nfs4_unlock_state(); - return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_nfsd, nfsd_inject_get, nfsd_inject_set, "%llu\n"); +static ssize_t fault_inject_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + static u64 val; + char read_buf[25]; + size_t size, ret; + loff_t pos = *ppos; + + if (!pos) + nfsd_inject_get(file->f_dentry->d_inode->i_private, &val); + size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val); + + if (pos < 0) + return -EINVAL; + if (pos >= size || !len) + return 0; + if (len > size - pos) + len = size - pos; + ret = copy_to_user(buf, read_buf + pos, len); + if (ret == len) + return -EFAULT; + len -= ret; + *ppos = pos + len; + return len; +} + +static ssize_t fault_inject_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + char write_buf[24]; + size_t size = min(sizeof(write_buf), len) - 1; + u64 val; + + if (copy_from_user(write_buf, buf, size)) + return -EFAULT; + + val = simple_strtoll(write_buf, NULL, 0); + nfsd_inject_set(file->f_dentry->d_inode->i_private, val); + return len; /* on success, claim we got the whole input */ +} + +static const struct file_operations fops_nfsd = { + .owner = THIS_MODULE, + .read = fault_inject_read, + .write = fault_inject_write, +}; void nfsd_fault_inject_cleanup(void) { -- cgit v0.10.2 From 6c1e82a4b74ad0c8b45c833a4409f153199d9be4 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Thu, 29 Nov 2012 11:40:46 -0500 Subject: NFSD: Forget state for a specific client Write the client's ip address to any state file and all appropriate state for that client will be forgotten. Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 19f9094..96ffdf5 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -8,9 +8,12 @@ #include #include #include +#include +#include #include #include "state.h" +#include "netns.h" struct nfsd_fault_inject_op { char *file; @@ -64,6 +67,24 @@ static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val) printk(KERN_INFO "NFSD: %s: found %llu", op->file, count); } +static void nfsd_inject_set_client(struct nfsd_fault_inject_op *op, + struct sockaddr_storage *addr, + size_t addr_size) +{ + char buf[INET6_ADDRSTRLEN]; + struct nfs4_client *clp; + u64 count; + + nfs4_lock_state(); + clp = nfsd_find_client(addr, addr_size); + if (clp) { + count = op->forget(clp, 0); + rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, 129); + printk(KERN_INFO "NFSD [%s]: Client %s had %llu state object(s)\n", op->file, buf, count); + } + nfs4_unlock_state(); +} + static void nfsd_inject_get(struct nfsd_fault_inject_op *op, u64 *val) { nfs4_lock_state(); @@ -100,15 +121,23 @@ static ssize_t fault_inject_read(struct file *file, char __user *buf, static ssize_t fault_inject_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { - char write_buf[24]; + char write_buf[INET6_ADDRSTRLEN]; size_t size = min(sizeof(write_buf), len) - 1; + struct net *net = current->nsproxy->net_ns; + struct sockaddr_storage sa; u64 val; if (copy_from_user(write_buf, buf, size)) return -EFAULT; - - val = simple_strtoll(write_buf, NULL, 0); - nfsd_inject_set(file->f_dentry->d_inode->i_private, val); + write_buf[size] = '\0'; + + size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa)); + if (size > 0) + nfsd_inject_set_client(file->f_dentry->d_inode->i_private, &sa, size); + else { + val = simple_strtoll(write_buf, NULL, 0); + nfsd_inject_set(file->f_dentry->d_inode->i_private, val); + } return len; /* on success, claim we got the whole input */ } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9fb8e52..eff7340 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4763,6 +4763,21 @@ u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) return count; } +struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) +{ + struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); + + if (!nfsd_netns_ready(nn)) + return NULL; + + list_for_each_entry(clp, &nn->client_lru, cl_lru) { + if (memcmp(&clp->cl_addr, addr, addr_size) == 0) + return clp; + } + return NULL; +} + #endif /* CONFIG_NFSD_FAULT_INJECTION */ /* initialization to perform at module load time: */ diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 4017f35..d1c229f 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -502,6 +502,7 @@ extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time); int nfsd_fault_inject_init(void); void nfsd_fault_inject_cleanup(void); u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64)); +struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t); u64 nfsd_forget_client(struct nfs4_client *, u64); u64 nfsd_forget_client_locks(struct nfs4_client*, u64); -- cgit v0.10.2 From a33977206cd167cb7541cf9044828552d9cae540 Mon Sep 17 00:00:00 2001 From: Omar Ramirez Luna Date: Mon, 19 Nov 2012 19:05:48 -0600 Subject: iommu/omap: Remove redundant clock handling on ISR For the interrupt to be generated, the mmu clock should be already enabled while translating a virtual address, so, this call to clock handling is just increasing/decreasing the counter. This works now, because its users need the same clock and they indirectly power the mmu, in this interrupt context the handling of clocks inside the ISR doesn't seem to be needed nor helping. Next patch should also correct the dependency on clients to handle iommu clocks. Signed-off-by: Omar Ramirez Luna Tested-by: Ohad Ben-Cohen Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index badc17c..6b1288c 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -807,9 +807,7 @@ static irqreturn_t iommu_fault_handler(int irq, void *data) if (!obj->refcount) return IRQ_NONE; - clk_enable(obj->clk); errs = iommu_report_fault(obj, &da); - clk_disable(obj->clk); if (errs == 0) return IRQ_HANDLED; -- cgit v0.10.2 From 87f8e57327bd8d85fb5b46cad29ac281430cc50d Mon Sep 17 00:00:00 2001 From: Omar Ramirez Luna Date: Mon, 19 Nov 2012 19:05:49 -0600 Subject: iommu/omap: Keep mmu enabled when requested The purpose of the mmu is to handle the memory accesses requested by its users. Typically, the mmu is bundled with the processing unit in a single IP block, which makes them to share the same clock to be functional. Currently, iommu code assumes that its user will be indirectly clocking it, but being a separate mmu driver, it should handle its own clocks, so as long as the mmu is requested it will be powered ON and once detached it will be powered OFF. The remaining clock handling out of iommu_enable and iommu_disable corresponds to paths that can be accessed through debugfs, some of them doesn't work if the module is not enabled first, but in future if the mmu is idled withouth freeing, these are needed to debug. Signed-off-by: Omar Ramirez Luna Tested-by: Ohad Ben-Cohen Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 6b1288c..f8082da 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -154,7 +154,6 @@ static int iommu_enable(struct omap_iommu *obj) err = arch_iommu->enable(obj); - clk_disable(obj->clk); return err; } @@ -163,8 +162,6 @@ static void iommu_disable(struct omap_iommu *obj) if (!obj) return; - clk_enable(obj->clk); - arch_iommu->disable(obj); clk_disable(obj->clk); -- cgit v0.10.2 From 72b15b6ae97796c5fac687addde5dbfab872cf94 Mon Sep 17 00:00:00 2001 From: Omar Ramirez Luna Date: Mon, 19 Nov 2012 19:05:50 -0600 Subject: iommu/omap: Migrate to hwmod framework Use hwmod data and device attributes to build and register an omap device for iommu driver. - Update the naming convention in isp module. - Remove unneeded check for number of resources, as this is now handled by omap_device and prevents driver from loading. - Now unused, remove platform device and resource data, handling of sysconfig register for softreset purposes, use default latency structure. - Use hwmod API for reset handling. Signed-off-by: Omar Ramirez Luna Tested-by: Ohad Ben-Cohen Signed-off-by: Joerg Roedel diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index c15f5a9..787a996 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -214,7 +214,7 @@ static struct platform_device omap3isp_device = { }; static struct omap_iommu_arch_data omap3_isp_iommu = { - .name = "isp", + .name = "mmu_isp", }; int omap3_init_camera(struct isp_platform_data *pdata) diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c index a6a4ff8..02726a6 100644 --- a/arch/arm/mach-omap2/omap-iommu.c +++ b/arch/arm/mach-omap2/omap-iommu.c @@ -12,153 +12,61 @@ #include #include +#include +#include #include +#include +#include -#include "soc.h" -#include "common.h" - -struct iommu_device { - resource_size_t base; - int irq; - struct iommu_platform_data pdata; - struct resource res[2]; -}; -static struct iommu_device *devices; -static int num_iommu_devices; - -#ifdef CONFIG_ARCH_OMAP3 -static struct iommu_device omap3_devices[] = { - { - .base = 0x480bd400, - .irq = 24 + OMAP_INTC_START, - .pdata = { - .name = "isp", - .nr_tlb_entries = 8, - .clk_name = "cam_ick", - .da_start = 0x0, - .da_end = 0xFFFFF000, - }, - }, -#if defined(CONFIG_OMAP_IOMMU_IVA2) - { - .base = 0x5d000000, - .irq = 28 + OMAP_INTC_START, - .pdata = { - .name = "iva2", - .nr_tlb_entries = 32, - .clk_name = "iva2_ck", - .da_start = 0x11000000, - .da_end = 0xFFFFF000, - }, - }, -#endif -}; -#define NR_OMAP3_IOMMU_DEVICES ARRAY_SIZE(omap3_devices) -static struct platform_device *omap3_iommu_pdev[NR_OMAP3_IOMMU_DEVICES]; -#else -#define omap3_devices NULL -#define NR_OMAP3_IOMMU_DEVICES 0 -#define omap3_iommu_pdev NULL -#endif - -#ifdef CONFIG_ARCH_OMAP4 -static struct iommu_device omap4_devices[] = { - { - .base = OMAP4_MMU1_BASE, - .irq = 100 + OMAP44XX_IRQ_GIC_START, - .pdata = { - .name = "ducati", - .nr_tlb_entries = 32, - .clk_name = "ipu_fck", - .da_start = 0x0, - .da_end = 0xFFFFF000, - }, - }, - { - .base = OMAP4_MMU2_BASE, - .irq = 28 + OMAP44XX_IRQ_GIC_START, - .pdata = { - .name = "tesla", - .nr_tlb_entries = 32, - .clk_name = "dsp_fck", - .da_start = 0x0, - .da_end = 0xFFFFF000, - }, - }, -}; -#define NR_OMAP4_IOMMU_DEVICES ARRAY_SIZE(omap4_devices) -static struct platform_device *omap4_iommu_pdev[NR_OMAP4_IOMMU_DEVICES]; -#else -#define omap4_devices NULL -#define NR_OMAP4_IOMMU_DEVICES 0 -#define omap4_iommu_pdev NULL -#endif - -static struct platform_device **omap_iommu_pdev; - -static int __init omap_iommu_init(void) +static int __init omap_iommu_dev_init(struct omap_hwmod *oh, void *unused) { - int i, err; - struct resource res[] = { - { .flags = IORESOURCE_MEM }, - { .flags = IORESOURCE_IRQ }, - }; + struct platform_device *pdev; + struct iommu_platform_data *pdata; + struct omap_mmu_dev_attr *a = (struct omap_mmu_dev_attr *)oh->dev_attr; + static int i; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->name = oh->name; + pdata->clk_name = oh->main_clk; + pdata->nr_tlb_entries = a->nr_tlb_entries; + pdata->da_start = a->da_start; + pdata->da_end = a->da_end; + + if (oh->rst_lines_cnt == 1) { + pdata->reset_name = oh->rst_lines->name; + pdata->assert_reset = omap_device_assert_hardreset; + pdata->deassert_reset = omap_device_deassert_hardreset; + } - if (cpu_is_omap34xx()) { - devices = omap3_devices; - omap_iommu_pdev = omap3_iommu_pdev; - num_iommu_devices = NR_OMAP3_IOMMU_DEVICES; - } else if (cpu_is_omap44xx()) { - devices = omap4_devices; - omap_iommu_pdev = omap4_iommu_pdev; - num_iommu_devices = NR_OMAP4_IOMMU_DEVICES; - } else - return -ENODEV; + pdev = omap_device_build("omap-iommu", i, oh, pdata, sizeof(*pdata), + NULL, 0, 0); - for (i = 0; i < num_iommu_devices; i++) { - struct platform_device *pdev; - const struct iommu_device *d = &devices[i]; + kfree(pdata); - pdev = platform_device_alloc("omap-iommu", i); - if (!pdev) { - err = -ENOMEM; - goto err_out; - } + if (IS_ERR(pdev)) { + pr_err("%s: device build err: %ld\n", __func__, PTR_ERR(pdev)); + return PTR_ERR(pdev); + } - res[0].start = d->base; - res[0].end = d->base + MMU_REG_SIZE - 1; - res[1].start = res[1].end = d->irq; + i++; - err = platform_device_add_resources(pdev, res, - ARRAY_SIZE(res)); - if (err) - goto err_out; - err = platform_device_add_data(pdev, &d->pdata, - sizeof(d->pdata)); - if (err) - goto err_out; - err = platform_device_add(pdev); - if (err) - goto err_out; - omap_iommu_pdev[i] = pdev; - } return 0; +} -err_out: - while (i--) - platform_device_put(omap_iommu_pdev[i]); - return err; +static int __init omap_iommu_init(void) +{ + return omap_hwmod_for_each_by_class("mmu", omap_iommu_dev_init, NULL); } /* must be ready before omap3isp is probed */ subsys_initcall(omap_iommu_init); static void __exit omap_iommu_exit(void) { - int i; - - for (i = 0; i < num_iommu_devices; i++) - platform_device_unregister(omap_iommu_pdev[i]); + /* Do nothing */ } module_exit(omap_iommu_exit); diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index f8082da..af9b4f3 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -143,13 +143,23 @@ EXPORT_SYMBOL_GPL(omap_iommu_arch_version); static int iommu_enable(struct omap_iommu *obj) { int err; + struct platform_device *pdev = to_platform_device(obj->dev); + struct iommu_platform_data *pdata = pdev->dev.platform_data; - if (!obj) + if (!obj || !pdata) return -EINVAL; if (!arch_iommu) return -ENODEV; + if (pdata->deassert_reset) { + err = pdata->deassert_reset(pdev, pdata->reset_name); + if (err) { + dev_err(obj->dev, "deassert_reset failed: %d\n", err); + return err; + } + } + clk_enable(obj->clk); err = arch_iommu->enable(obj); @@ -159,12 +169,18 @@ static int iommu_enable(struct omap_iommu *obj) static void iommu_disable(struct omap_iommu *obj) { - if (!obj) + struct platform_device *pdev = to_platform_device(obj->dev); + struct iommu_platform_data *pdata = pdev->dev.platform_data; + + if (!obj || !pdata) return; arch_iommu->disable(obj); clk_disable(obj->clk); + + if (pdata->assert_reset) + pdata->assert_reset(pdev, pdata->reset_name); } /* @@ -926,9 +942,6 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev) struct resource *res; struct iommu_platform_data *pdata = pdev->dev.platform_data; - if (pdev->num_resources != 2) - return -EINVAL; - obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL); if (!obj) return -ENOMEM; diff --git a/drivers/iommu/omap-iommu2.c b/drivers/iommu/omap-iommu2.c index c020202..4a3a1c7 100644 --- a/drivers/iommu/omap-iommu2.c +++ b/drivers/iommu/omap-iommu2.c @@ -35,12 +35,8 @@ #define MMU_SYS_IDLE_SMART (2 << MMU_SYS_IDLE_SHIFT) #define MMU_SYS_IDLE_MASK (3 << MMU_SYS_IDLE_SHIFT) -#define MMU_SYS_SOFTRESET (1 << 1) #define MMU_SYS_AUTOIDLE 1 -/* SYSSTATUS */ -#define MMU_SYS_RESETDONE 1 - /* IRQSTATUS & IRQENABLE */ #define MMU_IRQ_MULTIHITFAULT (1 << 4) #define MMU_IRQ_TABLEWALKFAULT (1 << 3) @@ -97,7 +93,6 @@ static void __iommu_set_twl(struct omap_iommu *obj, bool on) static int omap2_iommu_enable(struct omap_iommu *obj) { u32 l, pa; - unsigned long timeout; if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd, SZ_16K)) return -EINVAL; @@ -106,20 +101,6 @@ static int omap2_iommu_enable(struct omap_iommu *obj) if (!IS_ALIGNED(pa, SZ_16K)) return -EINVAL; - iommu_write_reg(obj, MMU_SYS_SOFTRESET, MMU_SYSCONFIG); - - timeout = jiffies + msecs_to_jiffies(20); - do { - l = iommu_read_reg(obj, MMU_SYSSTATUS); - if (l & MMU_SYS_RESETDONE) - break; - } while (!time_after(jiffies, timeout)); - - if (!(l & MMU_SYS_RESETDONE)) { - dev_err(obj->dev, "can't take mmu out of reset\n"); - return -ENODEV; - } - l = iommu_read_reg(obj, MMU_REVISION); dev_info(obj->dev, "%s: version %d.%d\n", obj->name, (l >> 4) & 0xf, l & 0xf); diff --git a/include/linux/platform_data/iommu-omap.h b/include/linux/platform_data/iommu-omap.h index c677b9f..ef2060d 100644 --- a/include/linux/platform_data/iommu-omap.h +++ b/include/linux/platform_data/iommu-omap.h @@ -10,6 +10,8 @@ * published by the Free Software Foundation. */ +#include + #define MMU_REG_SIZE 256 /** @@ -43,7 +45,11 @@ struct omap_mmu_dev_attr { struct iommu_platform_data { const char *name; const char *clk_name; - const int nr_tlb_entries; + const char *reset_name; + int nr_tlb_entries; u32 da_start; u32 da_end; + + int (*assert_reset)(struct platform_device *pdev, const char *name); + int (*deassert_reset)(struct platform_device *pdev, const char *name); }; -- cgit v0.10.2 From ebf7cda0f92effd8169b831fae81e9437dce1fef Mon Sep 17 00:00:00 2001 From: Omar Ramirez Luna Date: Mon, 19 Nov 2012 19:05:51 -0600 Subject: iommu/omap: Adapt to runtime pm Use runtime PM functionality interfaced with hwmod enable/idle functions, to replace direct clock operations and sysconfig handling. Due to reset sequence, pm_runtime_[get|put]_sync must be used, to avoid possible operations with the module under reset. Because of this and given that the driver uses spin_locks to protect their critical sections, we must use pm_runtime_irq_safe in order for the runtime ops to be happy, otherwise might_sleep_if checks in runtime framework will complain. The remaining pm_runtime out of iommu_enable and iommu_disable corresponds to paths that can be accessed through debugfs, some of them doesn't work if the module is not enabled first, but in future if the mmu is idled withouth freeing, these are needed to debug. Signed-off-by: Omar Ramirez Luna Tested-by: Ohad Ben-Cohen Acked-by: Tony Lindgren Signed-off-by: Joerg Roedel diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c index 02726a6..7642fc4 100644 --- a/arch/arm/mach-omap2/omap-iommu.c +++ b/arch/arm/mach-omap2/omap-iommu.c @@ -31,7 +31,6 @@ static int __init omap_iommu_dev_init(struct omap_hwmod *oh, void *unused) return -ENOMEM; pdata->name = oh->name; - pdata->clk_name = oh->main_clk; pdata->nr_tlb_entries = a->nr_tlb_entries; pdata->da_start = a->da_start; pdata->da_end = a->da_end; diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index af9b4f3..18108c14 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -16,13 +16,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include @@ -160,7 +160,7 @@ static int iommu_enable(struct omap_iommu *obj) } } - clk_enable(obj->clk); + pm_runtime_get_sync(obj->dev); err = arch_iommu->enable(obj); @@ -177,7 +177,7 @@ static void iommu_disable(struct omap_iommu *obj) arch_iommu->disable(obj); - clk_disable(obj->clk); + pm_runtime_put_sync(obj->dev); if (pdata->assert_reset) pdata->assert_reset(pdev, pdata->reset_name); @@ -303,7 +303,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e) if (!obj || !obj->nr_tlb_entries || !e) return -EINVAL; - clk_enable(obj->clk); + pm_runtime_get_sync(obj->dev); iotlb_lock_get(obj, &l); if (l.base == obj->nr_tlb_entries) { @@ -333,7 +333,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e) cr = iotlb_alloc_cr(obj, e); if (IS_ERR(cr)) { - clk_disable(obj->clk); + pm_runtime_put_sync(obj->dev); return PTR_ERR(cr); } @@ -347,7 +347,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e) l.vict = l.base; iotlb_lock_set(obj, &l); out: - clk_disable(obj->clk); + pm_runtime_put_sync(obj->dev); return err; } @@ -377,7 +377,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da) int i; struct cr_regs cr; - clk_enable(obj->clk); + pm_runtime_get_sync(obj->dev); for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) { u32 start; @@ -396,7 +396,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da) iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY); } } - clk_disable(obj->clk); + pm_runtime_put_sync(obj->dev); if (i == obj->nr_tlb_entries) dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da); @@ -410,7 +410,7 @@ static void flush_iotlb_all(struct omap_iommu *obj) { struct iotlb_lock l; - clk_enable(obj->clk); + pm_runtime_get_sync(obj->dev); l.base = 0; l.vict = 0; @@ -418,7 +418,7 @@ static void flush_iotlb_all(struct omap_iommu *obj) iommu_write_reg(obj, 1, MMU_GFLUSH); - clk_disable(obj->clk); + pm_runtime_put_sync(obj->dev); } #if defined(CONFIG_OMAP_IOMMU_DEBUG) || defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE) @@ -428,11 +428,11 @@ ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t bytes) if (!obj || !buf) return -EINVAL; - clk_enable(obj->clk); + pm_runtime_get_sync(obj->dev); bytes = arch_iommu->dump_ctx(obj, buf, bytes); - clk_disable(obj->clk); + pm_runtime_put_sync(obj->dev); return bytes; } @@ -446,7 +446,7 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num) struct cr_regs tmp; struct cr_regs *p = crs; - clk_enable(obj->clk); + pm_runtime_get_sync(obj->dev); iotlb_lock_get(obj, &saved); for_each_iotlb_cr(obj, num, i, tmp) { @@ -456,7 +456,7 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num) } iotlb_lock_set(obj, &saved); - clk_disable(obj->clk); + pm_runtime_put_sync(obj->dev); return p - crs; } @@ -946,10 +946,6 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev) if (!obj) return -ENOMEM; - obj->clk = clk_get(&pdev->dev, pdata->clk_name); - if (IS_ERR(obj->clk)) - goto err_clk; - obj->nr_tlb_entries = pdata->nr_tlb_entries; obj->name = pdata->name; obj->dev = &pdev->dev; @@ -992,6 +988,9 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev) goto err_irq; platform_set_drvdata(pdev, obj); + pm_runtime_irq_safe(obj->dev); + pm_runtime_enable(obj->dev); + dev_info(&pdev->dev, "%s registered\n", obj->name); return 0; @@ -1000,8 +999,6 @@ err_irq: err_ioremap: release_mem_region(res->start, resource_size(res)); err_mem: - clk_put(obj->clk); -err_clk: kfree(obj); return err; } @@ -1022,7 +1019,8 @@ static int __devexit omap_iommu_remove(struct platform_device *pdev) release_mem_region(res->start, resource_size(res)); iounmap(obj->regbase); - clk_put(obj->clk); + pm_runtime_disable(obj->dev); + dev_info(&pdev->dev, "%s removed\n", obj->name); kfree(obj); return 0; diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h index 2b5f3c0..1200842 100644 --- a/drivers/iommu/omap-iommu.h +++ b/drivers/iommu/omap-iommu.h @@ -29,7 +29,6 @@ struct iotlb_entry { struct omap_iommu { const char *name; struct module *owner; - struct clk *clk; void __iomem *regbase; struct device *dev; void *isr_priv; @@ -116,8 +115,6 @@ static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev) * MMU Register offsets */ #define MMU_REVISION 0x00 -#define MMU_SYSCONFIG 0x10 -#define MMU_SYSSTATUS 0x14 #define MMU_IRQSTATUS 0x18 #define MMU_IRQENABLE 0x1c #define MMU_WALKING_ST 0x40 diff --git a/drivers/iommu/omap-iommu2.c b/drivers/iommu/omap-iommu2.c index 4a3a1c7..d745094 100644 --- a/drivers/iommu/omap-iommu2.c +++ b/drivers/iommu/omap-iommu2.c @@ -28,15 +28,6 @@ */ #define IOMMU_ARCH_VERSION 0x00000011 -/* SYSCONF */ -#define MMU_SYS_IDLE_SHIFT 3 -#define MMU_SYS_IDLE_FORCE (0 << MMU_SYS_IDLE_SHIFT) -#define MMU_SYS_IDLE_NONE (1 << MMU_SYS_IDLE_SHIFT) -#define MMU_SYS_IDLE_SMART (2 << MMU_SYS_IDLE_SHIFT) -#define MMU_SYS_IDLE_MASK (3 << MMU_SYS_IDLE_SHIFT) - -#define MMU_SYS_AUTOIDLE 1 - /* IRQSTATUS & IRQENABLE */ #define MMU_IRQ_MULTIHITFAULT (1 << 4) #define MMU_IRQ_TABLEWALKFAULT (1 << 3) @@ -105,11 +96,6 @@ static int omap2_iommu_enable(struct omap_iommu *obj) dev_info(obj->dev, "%s: version %d.%d\n", obj->name, (l >> 4) & 0xf, l & 0xf); - l = iommu_read_reg(obj, MMU_SYSCONFIG); - l &= ~MMU_SYS_IDLE_MASK; - l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE); - iommu_write_reg(obj, l, MMU_SYSCONFIG); - iommu_write_reg(obj, pa, MMU_TTB); __iommu_set_twl(obj, true); @@ -123,7 +109,6 @@ static void omap2_iommu_disable(struct omap_iommu *obj) l &= ~MMU_CNTL_MASK; iommu_write_reg(obj, l, MMU_CNTL); - iommu_write_reg(obj, MMU_SYS_IDLE_FORCE, MMU_SYSCONFIG); dev_dbg(obj->dev, "%s is shutting down\n", obj->name); } @@ -252,8 +237,6 @@ omap2_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len) char *p = buf; pr_reg(REVISION); - pr_reg(SYSCONFIG); - pr_reg(SYSSTATUS); pr_reg(IRQSTATUS); pr_reg(IRQENABLE); pr_reg(WALKING_ST); diff --git a/include/linux/platform_data/iommu-omap.h b/include/linux/platform_data/iommu-omap.h index ef2060d..5b429c4 100644 --- a/include/linux/platform_data/iommu-omap.h +++ b/include/linux/platform_data/iommu-omap.h @@ -44,7 +44,6 @@ struct omap_mmu_dev_attr { struct iommu_platform_data { const char *name; - const char *clk_name; const char *reset_name; int nr_tlb_entries; u32 da_start; -- cgit v0.10.2 From 298ea44f211de93ce1b30dc4e2bd2d3b23e41556 Mon Sep 17 00:00:00 2001 From: Omar Ramirez Luna Date: Mon, 19 Nov 2012 19:05:52 -0600 Subject: ARM: OMAP4: hwmod data: ipu and dsp to use parent clocks instead of leaf clocks This prevents hwmod _enable_clocks...omap2_dflt_clk_enable path from enabling modulemode inside CLKCTRL using its clk->enable_reg field. Instead is left to _omap4_enable_module though soc_ops, as the one in charge of this setting. According to comments received[1] for related patches the idea is to get rid of leaf clocks in future. So remove these two while at it. [1] http://lkml.org/lkml/2012/8/20/226 Signed-off-by: Omar Ramirez Luna Tested-by: Ohad Ben-Cohen Acked-by: Paul Walmsley Signed-off-by: Joerg Roedel diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 6efc30c..067c486 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -1316,16 +1316,6 @@ static struct clk dmic_fck = { .clkdm_name = "abe_clkdm", }; -static struct clk dsp_fck = { - .name = "dsp_fck", - .ops = &clkops_omap2_dflt, - .enable_reg = OMAP4430_CM_TESLA_TESLA_CLKCTRL, - .enable_bit = OMAP4430_MODULEMODE_HWCTRL, - .clkdm_name = "tesla_clkdm", - .parent = &dpll_iva_m4x2_ck, - .recalc = &followparent_recalc, -}; - static struct clk dss_sys_clk = { .name = "dss_sys_clk", .ops = &clkops_omap2_dflt, @@ -1696,16 +1686,6 @@ static struct clk i2c4_fck = { .recalc = &followparent_recalc, }; -static struct clk ipu_fck = { - .name = "ipu_fck", - .ops = &clkops_omap2_dflt, - .enable_reg = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL, - .enable_bit = OMAP4430_MODULEMODE_HWCTRL, - .clkdm_name = "ducati_clkdm", - .parent = &ducati_clk_mux_ck, - .recalc = &followparent_recalc, -}; - static struct clk iss_ctrlclk = { .name = "iss_ctrlclk", .ops = &clkops_omap2_dflt, @@ -3151,7 +3131,6 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "div_ts_ck", &div_ts_ck, CK_446X), CLK(NULL, "dmic_sync_mux_ck", &dmic_sync_mux_ck, CK_443X), CLK(NULL, "dmic_fck", &dmic_fck, CK_443X), - CLK(NULL, "dsp_fck", &dsp_fck, CK_443X), CLK(NULL, "dss_sys_clk", &dss_sys_clk, CK_443X), CLK(NULL, "dss_tv_clk", &dss_tv_clk, CK_443X), CLK(NULL, "dss_48mhz_clk", &dss_48mhz_clk, CK_443X), @@ -3183,7 +3162,6 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "i2c2_fck", &i2c2_fck, CK_443X), CLK(NULL, "i2c3_fck", &i2c3_fck, CK_443X), CLK(NULL, "i2c4_fck", &i2c4_fck, CK_443X), - CLK(NULL, "ipu_fck", &ipu_fck, CK_443X), CLK(NULL, "iss_ctrlclk", &iss_ctrlclk, CK_443X), CLK(NULL, "iss_fck", &iss_fck, CK_443X), CLK(NULL, "iva_fck", &iva_fck, CK_443X), diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 1e00ea8..4b985b9 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -651,7 +651,7 @@ static struct omap_hwmod omap44xx_dsp_hwmod = { .mpu_irqs = omap44xx_dsp_irqs, .rst_lines = omap44xx_dsp_resets, .rst_lines_cnt = ARRAY_SIZE(omap44xx_dsp_resets), - .main_clk = "dsp_fck", + .main_clk = "dpll_iva_m4x2_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_TESLA_TESLA_CLKCTRL_OFFSET, @@ -1678,7 +1678,7 @@ static struct omap_hwmod omap44xx_ipu_hwmod = { .mpu_irqs = omap44xx_ipu_irqs, .rst_lines = omap44xx_ipu_resets, .rst_lines_cnt = ARRAY_SIZE(omap44xx_ipu_resets), - .main_clk = "ipu_fck", + .main_clk = "ducati_clk_mux_ck", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_DUCATI_DUCATI_CLKCTRL_OFFSET, -- cgit v0.10.2 From a0157573041403e7507a6f3f32279fc14ff5c02e Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 22 Oct 2012 20:44:03 +0800 Subject: ARM: dma-mapping: support debug_dma_mapping_error Without the patch, kind of below warning will be dumped if DMA-API debug is enabled: [ 11.069763] ------------[ cut here ]------------ [ 11.074645] WARNING: at lib/dma-debug.c:948 check_unmap+0x770/0x860() [ 11.081420] ehci-omap ehci-omap.0: DMA-API: device driver failed to check map error[device address=0x0000000 0adb78e80] [size=8 bytes] [mapped as single] [ 11.095611] Modules linked in: Cc: Russell King Cc: Marek Szyprowski Signed-off-by: Ming Lei Signed-off-by: Joerg Roedel diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 2300484..78d8e9b 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -91,6 +91,7 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) */ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { + debug_dma_mapping_error(dev, dma_addr); return dma_addr == DMA_ERROR_CODE; } -- cgit v0.10.2 From 6c27b20395d21235b73771a2bcf5325ece94c4c8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 10 Oct 2012 08:32:24 +0000 Subject: powerpc/mpc52xx: use module_platform_driver macro This patch removes some code duplication by using module_platform_driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Anatolij Gustschin diff --git a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c index 2351f9e..16150fa 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c @@ -578,18 +578,4 @@ static struct platform_driver mpc52xx_lpbfifo_driver = { .probe = mpc52xx_lpbfifo_probe, .remove = __devexit_p(mpc52xx_lpbfifo_remove), }; - -/*********************************************************************** - * Module init/exit - */ -static int __init mpc52xx_lpbfifo_init(void) -{ - return platform_driver_register(&mpc52xx_lpbfifo_driver); -} -module_init(mpc52xx_lpbfifo_init); - -static void __exit mpc52xx_lpbfifo_exit(void) -{ - platform_driver_unregister(&mpc52xx_lpbfifo_driver); -} -module_exit(mpc52xx_lpbfifo_exit); +module_platform_driver(mpc52xx_lpbfifo_driver); -- cgit v0.10.2 From 6baf11906e7687ad517567f6b93b94a90f0db3f9 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Mon, 15 Oct 2012 09:52:20 +0000 Subject: powerpc/512x: don't compile any platform DIU code if the DIU is not enabled If the DIU framebuffer driver is not enabled, then there's no point in compiling any platform DIU code, because it will never be used. Most of the platform code was protected in the appropriate #ifdef, but not all. This caused a break in some randconfig builds. This is only a problem on the 512x platforms. The P1022DS and MPC8610HPCD platforms are already correct. This patch reverts commit 12e36309f8774f4ccc769d5e3ff11ef092e524bc ("powerpc: Option FB_FSL_DIU is not really optional for mpc512x") and restores the ability to configure DIU support. Signed-off-by: Timur Tabi Signed-off-by: Anatolij Gustschin diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index b62508b..c169998 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig @@ -2,7 +2,6 @@ config PPC_MPC512x bool "512x-based boards" depends on 6xx select FSL_SOC - select FB_FSL_DIU select IPIC select PPC_CLOCK select PPC_PCI_CHOICE diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c index dcef6ad..0a134e0 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c @@ -42,7 +42,10 @@ static void __init mpc5121_ads_setup_arch(void) for_each_compatible_node(np, "pci", "fsl,mpc5121-pci") mpc83xx_add_bridge(np); #endif + +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) mpc512x_setup_diu(); +#endif } static void __init mpc5121_ads_init_IRQ(void) diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h index 1ab6d11..c32b399 100644 --- a/arch/powerpc/platforms/512x/mpc512x.h +++ b/arch/powerpc/platforms/512x/mpc512x.h @@ -16,6 +16,13 @@ extern void __init mpc512x_init(void); extern int __init mpc5121_clk_init(void); void __init mpc512x_declare_of_platform_devices(void); extern void mpc512x_restart(char *cmd); -extern void mpc512x_init_diu(void); -extern void mpc512x_setup_diu(void); + +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) +void mpc512x_init_diu(void); +void mpc512x_setup_diu(void); +#else +#define mpc512x_init_diu NULL +#define mpc512x_setup_diu NULL +#endif + #endif /* __MPC512X_H__ */ diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c index 1650e09..35f14fd 100644 --- a/arch/powerpc/platforms/512x/mpc512x_shared.c +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c @@ -58,6 +58,8 @@ void mpc512x_restart(char *cmd) ; } +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + struct fsl_diu_shared_fb { u8 gamma[0x300]; /* 32-bit aligned! */ struct diu_ad ad0; /* 32-bit aligned! */ @@ -66,25 +68,6 @@ struct fsl_diu_shared_fb { bool in_use; }; -u32 mpc512x_get_pixel_format(enum fsl_diu_monitor_port port, - unsigned int bits_per_pixel) -{ - switch (bits_per_pixel) { - case 32: - return 0x88883316; - case 24: - return 0x88082219; - case 16: - return 0x65053118; - } - return 0x00000400; -} - -void mpc512x_set_gamma_table(enum fsl_diu_monitor_port port, - char *gamma_table_base) -{ -} - void mpc512x_set_monitor_port(enum fsl_diu_monitor_port port) { } @@ -320,14 +303,14 @@ void __init mpc512x_setup_diu(void) } } - diu_ops.get_pixel_format = mpc512x_get_pixel_format; - diu_ops.set_gamma_table = mpc512x_set_gamma_table; diu_ops.set_monitor_port = mpc512x_set_monitor_port; diu_ops.set_pixel_clock = mpc512x_set_pixel_clock; diu_ops.valid_monitor_port = mpc512x_valid_monitor_port; diu_ops.release_bootmem = mpc512x_release_bootmem; } +#endif + void __init mpc512x_init_IRQ(void) { struct device_node *np; -- cgit v0.10.2 From 0d027966b9b0b2a5f24b9e5aa60a6cdb7d47b0e3 Mon Sep 17 00:00:00 2001 From: "Guillermo A. Amaral" Date: Sun, 2 Dec 2012 23:26:11 -0800 Subject: Input: xpad - minor formatting fixes Fixed a few minor coding style issues in xpad driver. Signed-off-by: "Guillermo A. Amaral B." Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 83811e4..3d8f39b 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -235,7 +235,7 @@ static const signed short xpad_abs_triggers[] = { { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \ { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) } -static struct usb_device_id xpad_table [] = { +static struct usb_device_id xpad_table[] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ @@ -251,7 +251,7 @@ static struct usb_device_id xpad_table [] = { { } }; -MODULE_DEVICE_TABLE (usb, xpad_table); +MODULE_DEVICE_TABLE(usb, xpad_table); struct usb_xpad { struct input_dev *dev; /* input device interface */ @@ -783,7 +783,7 @@ static int xpad_open(struct input_dev *dev) struct usb_xpad *xpad = input_get_drvdata(dev); /* URB was submitted in probe */ - if(xpad->xtype == XTYPE_XBOX360W) + if (xpad->xtype == XTYPE_XBOX360W) return 0; xpad->irq_in->dev = xpad->udev; -- cgit v0.10.2 From 540602a43ae5fa94064f8fae100f5ca75d4c002b Mon Sep 17 00:00:00 2001 From: "Guillermo A. Amaral" Date: Sun, 2 Dec 2012 23:26:18 -0800 Subject: Input: xpad - add a few new VID/PID combinations This adds VID/PID combinations for MadCatz, PDP and PowerA (new). Removed Pelican 'TSZ' Wired Xbox 360 Controller since it's clashing with Edge wireless Controller and I failed to confirm the PID. Signed-off-by: "Guillermo A. Amaral B." Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 3d8f39b..d6cbfe9 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -118,11 +118,12 @@ static const struct xpad_device { u8 xtype; } xpad_device[] = { { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX }, - { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX }, { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX }, { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX }, + { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX }, + { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 }, + { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, - { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 }, { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX }, @@ -136,9 +137,12 @@ static const struct xpad_device { { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX }, { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, + { 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", XTYPE_XBOX360 }, { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, + { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 }, { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, + { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX }, { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX }, { 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX }, @@ -148,24 +152,28 @@ static const struct xpad_device { { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX }, - { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, + { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, + { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX }, + { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, - { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, - { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 }, { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, - { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 }, + { 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 }, { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, - { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, - { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, - { 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, + { 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 }, + { 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 }, + { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } }; @@ -248,6 +256,7 @@ static struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */ XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */ + XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */ { } }; -- cgit v0.10.2 From e12b3cecf221644ccab64d7c30a6df58b7630cb0 Mon Sep 17 00:00:00 2001 From: Diego Calleja Date: Mon, 3 Dec 2012 21:16:11 -0800 Subject: Input: wacom - fix touch support for Bamboo Fun CTH-461 Commit f393ee2b814e3291c12565000210b3cf10aa5c1d forgot to add the touch_max property for Wacom Bamboo Fun CTH-461/S, ID 056a:00d2. This broke the touch functionality for that device. This patch, (done with help of Ping Cheng), adds the correct value and makes touch work again. Signed-off-by: Diego Calleja Reviewed-by: Ping Cheng Cc: stable@kernel.org Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 0a67031..c2bfe92 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -2034,7 +2034,8 @@ static const struct wacom_features wacom_features_0xD1 = .touch_max = 2 }; static const struct wacom_features wacom_features_0xD2 = { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, - 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + .touch_max = 2 }; static const struct wacom_features wacom_features_0xD3 = { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, -- cgit v0.10.2 From 333e34bfe2149e634fb0613b4936fd838c36fafb Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 29 Nov 2012 09:00:19 -0800 Subject: Input: gpio_keys - switch to using gpio_request_one() This saves us a few lines of code. Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 79435de..d327f5a 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -440,21 +440,13 @@ static int gpio_keys_setup_key(struct platform_device *pdev, if (gpio_is_valid(button->gpio)) { - error = gpio_request(button->gpio, desc); + error = gpio_request_one(button->gpio, GPIOF_IN, desc); if (error < 0) { dev_err(dev, "Failed to request GPIO %d, error %d\n", button->gpio, error); return error; } - error = gpio_direction_input(button->gpio); - if (error < 0) { - dev_err(dev, - "Failed to configure direction for GPIO %d, error %d\n", - button->gpio, error); - goto fail; - } - if (button->debounce_interval) { error = gpio_set_debounce(button->gpio, button->debounce_interval * 1000); -- cgit v0.10.2 From da5ee074ce8e07b9a91596de3576b59990c0c8c6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 29 Nov 2012 09:24:08 -0800 Subject: Input: gpio_keys_polled - switch to using gpio_request_one() This saves us a few lines of code. Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index d72d0e5..f686fd9 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -270,22 +270,14 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) goto err_free_gpio; } - error = gpio_request(gpio, - button->desc ? button->desc : DRV_NAME); + error = gpio_request_one(gpio, GPIOF_IN, + button->desc ?: DRV_NAME); if (error) { dev_err(dev, "unable to claim gpio %u, err=%d\n", gpio, error); goto err_free_gpio; } - error = gpio_direction_input(gpio); - if (error) { - dev_err(dev, - "unable to set direction on gpio %u, err=%d\n", - gpio, error); - goto err_free_gpio; - } - bdata->can_sleep = gpio_cansleep(gpio); bdata->last_state = -1; bdata->threshold = DIV_ROUND_UP(button->debounce_interval, -- cgit v0.10.2 From cc248d4b1ddf05fefc1373d9d7a4dd1df71b6190 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 3 Dec 2012 16:11:13 -0500 Subject: svcrpc: don't byte-swap sk_reclen in place Byte-swapping in place is always a little dubious. Let's instead define this field to always be big-endian, and do the swapping on demand where we need it. Signed-off-by: J. Bruce Fields diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 92ad02f..613cf42 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -26,11 +26,21 @@ struct svc_sock { void (*sk_owspace)(struct sock *); /* private TCP part */ - u32 sk_reclen; /* length of record */ + __be32 sk_reclen; /* length of record */ u32 sk_tcplen; /* current read length */ struct page * sk_pages[RPCSVC_MAXPAGES]; /* received data */ }; +static inline u32 svc_sock_reclen(struct svc_sock *svsk) +{ + return ntohl(svsk->sk_reclen) & RPC_FRAGMENT_SIZE_MASK; +} + +static inline u32 svc_sock_final_rec(struct svc_sock *svsk) +{ + return ntohl(svsk->sk_reclen) & RPC_LAST_STREAM_FRAGMENT; +} + /* * Function prototypes. */ diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 03827ce..d50de2b 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -950,8 +950,7 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) return -EAGAIN; } - svsk->sk_reclen = ntohl(svsk->sk_reclen); - if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) { + if (!(svc_sock_final_rec(svsk))) { /* FIXME: technically, a record can be fragmented, * and non-terminal fragments will not have the top * bit set in the fragment length header. @@ -961,21 +960,18 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) goto err_delete; } - svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK; - dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen); - if (svsk->sk_reclen > serv->sv_max_mesg) { + dprintk("svc: TCP record, %d bytes\n", svc_sock_reclen(svsk)); + if (svc_sock_reclen(svsk) > serv->sv_max_mesg) { net_notice_ratelimited("RPC: fragment too large: 0x%08lx\n", - (unsigned long)svsk->sk_reclen); + (unsigned long)svc_sock_reclen(svsk)); goto err_delete; } } - if (svsk->sk_reclen < 8) + if (svc_sock_reclen(svsk) < 8) goto err_delete; /* client is nuts. */ - len = svsk->sk_reclen; - - return len; + return svc_sock_reclen(svsk); error: dprintk("RPC: TCP recv_record got %d\n", len); return len; @@ -1019,7 +1015,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) if (dst->iov_len < src->iov_len) return -EAGAIN; /* whatever; just giving up. */ memcpy(dst->iov_base, src->iov_base, src->iov_len); - xprt_complete_rqst(req->rq_task, svsk->sk_reclen); + xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); rqstp->rq_arg.len = 0; return 0; } @@ -1064,12 +1060,12 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) goto error; base = svc_tcp_restore_pages(svsk, rqstp); - want = svsk->sk_reclen - base; + want = svc_sock_reclen(svsk) - base; vec = rqstp->rq_vec; pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], - svsk->sk_reclen); + svc_sock_reclen(svsk)); rqstp->rq_respages = &rqstp->rq_pages[pnum]; @@ -1082,11 +1078,11 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) if (len < 0 && len != -EAGAIN) goto err_other; dprintk("svc: incomplete TCP record (%d of %d)\n", - svsk->sk_tcplen, svsk->sk_reclen); + svsk->sk_tcplen, svc_sock_reclen(svsk)); goto err_noclose; } - rqstp->rq_arg.len = svsk->sk_reclen; + rqstp->rq_arg.len = svc_sock_reclen(svsk); rqstp->rq_arg.page_base = 0; if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; -- cgit v0.10.2 From ad46ccf09440975618e8fc1ead53d0a27b9bcf4c Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 3 Dec 2012 16:30:42 -0500 Subject: svcrpc: delay minimum-rpc-size check till later Soon we want to support multiple fragments, in which case it may be legal for a single fragment to be smaller than 8 bytes, so we'll want to delay this check till we've reached the last fragment. Also fix an outdated comment. Signed-off-by: J. Bruce Fields diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index d50de2b..1557179 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -921,10 +921,8 @@ out: } /* - * Receive data. + * Receive fragment record header. * If we haven't gotten the record length yet, get the next four bytes. - * Otherwise try to gobble up as much as possible up to the complete - * record length. */ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) { @@ -968,9 +966,6 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) } } - if (svc_sock_reclen(svsk) < 8) - goto err_delete; /* client is nuts. */ - return svc_sock_reclen(svsk); error: dprintk("RPC: TCP recv_record got %d\n", len); @@ -1076,12 +1071,15 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) if (len != want) { svc_tcp_save_pages(svsk, rqstp); if (len < 0 && len != -EAGAIN) - goto err_other; + goto err_delete; dprintk("svc: incomplete TCP record (%d of %d)\n", svsk->sk_tcplen, svc_sock_reclen(svsk)); goto err_noclose; } + if (svc_sock_reclen(svsk) < 8) + goto err_delete; /* client is nuts. */ + rqstp->rq_arg.len = svc_sock_reclen(svsk); rqstp->rq_arg.page_base = 0; if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { @@ -1117,10 +1115,10 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) error: if (len != -EAGAIN) - goto err_other; + goto err_delete; dprintk("RPC: TCP recvfrom got EAGAIN\n"); return 0; -err_other: +err_delete: printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", svsk->sk_xprt.xpt_server->sv_name, -len); set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); -- cgit v0.10.2 From 6a72ae2e23922bc96e8f3de24a5203be6edc2539 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 3 Dec 2012 16:35:35 -0500 Subject: svcrpc: fix off-by-4 error in "incomplete TCP record" dprintk The full reclen doesn't include the fragment header, but sk_tcplen does. Fix this to make it an apples-to-apples comparison. Signed-off-by: J. Bruce Fields diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 1557179..1db42b1 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1073,7 +1073,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) if (len < 0 && len != -EAGAIN) goto err_delete; dprintk("svc: incomplete TCP record (%d of %d)\n", - svsk->sk_tcplen, svc_sock_reclen(svsk)); + svsk->sk_tcplen - sizeof(rpc_fraghdr), + svc_sock_reclen(svsk)); goto err_noclose; } -- cgit v0.10.2 From 8af345f58ac9b350bb23c1457c613381d9f00472 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 3 Dec 2012 16:45:35 -0500 Subject: svcrpc: track rpc data length separately from sk_tcplen Keep a separate field, sk_datalen, that tracks only the data contained in a fragment, not including the fragment header. For now, this is always just max(0, sk_tcplen - 4), but after we allow multiple fragments sk_datalen will accumulate the total rpc data size while sk_tcplen only tracks progress receiving the current fragment. Signed-off-by: J. Bruce Fields diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 613cf42..62fd1b7 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -26,8 +26,15 @@ struct svc_sock { void (*sk_owspace)(struct sock *); /* private TCP part */ - __be32 sk_reclen; /* length of record */ - u32 sk_tcplen; /* current read length */ + /* On-the-wire fragment header: */ + __be32 sk_reclen; + /* As we receive a record, this includes the length received so + * far (including the fragment header): */ + u32 sk_tcplen; + /* Total length of the data (not including fragment headers) + * received so far in the fragments making up this rpc: */ + u32 sk_datalen; + struct page * sk_pages[RPCSVC_MAXPAGES]; /* received data */ }; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 1db42b1..2b09e23 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -874,9 +874,9 @@ static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst { unsigned int i, len, npages; - if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) + if (svsk->sk_datalen == 0) return 0; - len = svsk->sk_tcplen - sizeof(rpc_fraghdr); + len = svsk->sk_datalen; npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; for (i = 0; i < npages; i++) { if (rqstp->rq_pages[i] != NULL) @@ -893,9 +893,9 @@ static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp) { unsigned int i, len, npages; - if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) + if (svsk->sk_datalen == 0) return; - len = svsk->sk_tcplen - sizeof(rpc_fraghdr); + len = svsk->sk_datalen; npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; for (i = 0; i < npages; i++) { svsk->sk_pages[i] = rqstp->rq_pages[i]; @@ -907,9 +907,9 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) { unsigned int i, len, npages; - if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) + if (svsk->sk_datalen == 0) goto out; - len = svsk->sk_tcplen - sizeof(rpc_fraghdr); + len = svsk->sk_datalen; npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; for (i = 0; i < npages; i++) { BUG_ON(svsk->sk_pages[i] == NULL); @@ -918,6 +918,7 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) } out: svsk->sk_tcplen = 0; + svsk->sk_datalen = 0; } /* @@ -1066,8 +1067,10 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) /* Now receive data */ len = svc_partial_recvfrom(rqstp, vec, pnum, want, base); - if (len >= 0) + if (len >= 0) { svsk->sk_tcplen += len; + svsk->sk_datalen += len; + } if (len != want) { svc_tcp_save_pages(svsk, rqstp); if (len < 0 && len != -EAGAIN) @@ -1100,6 +1103,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) /* Reset TCP read info */ svsk->sk_reclen = 0; svsk->sk_tcplen = 0; + svsk->sk_datalen = 0; /* If we have more data, signal svc_xprt_enqueue() to try again */ if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); @@ -1296,6 +1300,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) svsk->sk_reclen = 0; svsk->sk_tcplen = 0; + svsk->sk_datalen = 0; memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; -- cgit v0.10.2 From 836fbadb96a8308e6283eee5c7b3bdae818b58ca Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 3 Dec 2012 15:50:38 -0500 Subject: svcrpc: support multiple-fragment rpc's Over TCP, RPC's are preceded by a single 4-byte field telling you how long the rpc is (in bytes). The spec also allows you to send an RPC in multiple such records (the high bit of the length field is used to tell you whether this is the final record). We've survived for years without supporting this because in practice the clients we care about don't use it. But the userland rpc libraries do, and every now and then an experimental client will run into this. (Most recently I noticed it while trying to write a pynfs check.) And we're really on the wrong side of the spec here--let's fix this. Signed-off-by: J. Bruce Fields diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 2b09e23..38ec968 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -949,20 +949,11 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) return -EAGAIN; } - if (!(svc_sock_final_rec(svsk))) { - /* FIXME: technically, a record can be fragmented, - * and non-terminal fragments will not have the top - * bit set in the fragment length header. - * But apparently no known nfs clients send fragmented - * records. */ - net_notice_ratelimited("RPC: multiple fragments per record not supported\n"); - goto err_delete; - } - dprintk("svc: TCP record, %d bytes\n", svc_sock_reclen(svsk)); - if (svc_sock_reclen(svsk) > serv->sv_max_mesg) { + if (svc_sock_reclen(svsk) + svsk->sk_datalen > + serv->sv_max_mesg) { net_notice_ratelimited("RPC: fragment too large: 0x%08lx\n", - (unsigned long)svc_sock_reclen(svsk)); + (unsigned long)svsk->sk_reclen); goto err_delete; } } @@ -1030,6 +1021,17 @@ static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) return i; } +static void svc_tcp_fragment_received(struct svc_sock *svsk) +{ + /* If we have more data, signal svc_xprt_enqueue() to try again */ + if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) + set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); + dprintk("svc: TCP %s record (%d bytes)\n", + svc_sock_final_rec(svsk) ? "final" : "nonfinal", + svc_sock_reclen(svsk)); + svsk->sk_tcplen = 0; + svsk->sk_reclen = 0; +} /* * Receive data from a TCP socket. @@ -1056,12 +1058,12 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) goto error; base = svc_tcp_restore_pages(svsk, rqstp); - want = svc_sock_reclen(svsk) - base; + want = svc_sock_reclen(svsk) - (svsk->sk_tcplen - sizeof(rpc_fraghdr)); vec = rqstp->rq_vec; pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], - svc_sock_reclen(svsk)); + svsk->sk_datalen + want); rqstp->rq_respages = &rqstp->rq_pages[pnum]; @@ -1071,20 +1073,23 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) svsk->sk_tcplen += len; svsk->sk_datalen += len; } - if (len != want) { + if (len != want || !svc_sock_final_rec(svsk)) { svc_tcp_save_pages(svsk, rqstp); if (len < 0 && len != -EAGAIN) goto err_delete; - dprintk("svc: incomplete TCP record (%d of %d)\n", - svsk->sk_tcplen - sizeof(rpc_fraghdr), - svc_sock_reclen(svsk)); + if (len == want) + svc_tcp_fragment_received(svsk); + else + dprintk("svc: incomplete TCP record (%ld of %d)\n", + svsk->sk_tcplen - sizeof(rpc_fraghdr), + svc_sock_reclen(svsk)); goto err_noclose; } if (svc_sock_reclen(svsk) < 8) goto err_delete; /* client is nuts. */ - rqstp->rq_arg.len = svc_sock_reclen(svsk); + rqstp->rq_arg.len = svsk->sk_datalen; rqstp->rq_arg.page_base = 0; if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; @@ -1101,12 +1106,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) len = receive_cb_reply(svsk, rqstp); /* Reset TCP read info */ - svsk->sk_reclen = 0; - svsk->sk_tcplen = 0; svsk->sk_datalen = 0; - /* If we have more data, signal svc_xprt_enqueue() to try again */ - if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) - set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); + svc_tcp_fragment_received(svsk); if (len < 0) goto error; @@ -1115,7 +1116,6 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) if (serv->sv_stats) serv->sv_stats->nettcpcnt++; - dprintk("svc: TCP complete record (%d bytes)\n", rqstp->rq_arg.len); return rqstp->rq_arg.len; error: -- cgit v0.10.2 From 9b2ef62b1541f176ea1b1f6e13b16df14bb16e99 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 3 Dec 2012 17:24:41 -0500 Subject: nfsd4: lockt, release_lockowner should renew clients Fix nfsd4_lockt and release_lockowner to lookup the referenced client, so that it can renew it, or correctly return "expired", as appropriate. Also share some code while we're here. Reported-by: Frank Filz Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index eff7340..16e954c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3132,6 +3132,18 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status) free_generic_stateid(open->op_stp); } +static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp) +{ + struct nfs4_client *found; + + if (STALE_CLIENTID(clid, nn)) + return nfserr_stale_clientid; + found = find_confirmed_client(clid, session, nn); + if (clp) + *clp = found; + return found ? nfs_ok : nfserr_expired; +} + __be32 nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, clientid_t *clid) @@ -3143,16 +3155,9 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfs4_lock_state(); dprintk("process_renew(%08x/%08x): starting\n", clid->cl_boot, clid->cl_id); - status = nfserr_stale_clientid; - if (STALE_CLIENTID(clid, nn)) - goto out; - clp = find_confirmed_client(clid, cstate->minorversion, nn); - status = nfserr_expired; - if (clp == NULL) { - /* We assume the client took too long to RENEW. */ - dprintk("nfsd4_renew: clientid not found!\n"); + status = lookup_clientid(clid, cstate->minorversion, nn, &clp); + if (status) goto out; - } status = nfserr_cb_path_down; if (!list_empty(&clp->cl_delegations) && clp->cl_cb_state != NFSD4_CB_UP) @@ -4293,9 +4298,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfs4_lock_state(); - status = nfserr_stale_clientid; - if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid, nn)) - goto out; + if (!nfsd4_has_session(cstate)) { + status = lookup_clientid(&lockt->lt_clientid, false, nn, NULL); + if (status) + goto out; + } if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) goto out; @@ -4466,14 +4473,12 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", clid->cl_boot, clid->cl_id); - /* XXX check for lease expiration */ - - status = nfserr_stale_clientid; - if (STALE_CLIENTID(clid, nn)) - return status; - nfs4_lock_state(); + status = lookup_clientid(clid, cstate->minorversion, nn, NULL); + if (status) + goto out; + status = nfserr_locks_held; INIT_LIST_HEAD(&matches); -- cgit v0.10.2 From d8b1e34e248d89f43bab18704894d537dc0b497e Mon Sep 17 00:00:00 2001 From: Christian Herzig Date: Fri, 23 Nov 2012 15:31:26 +0100 Subject: mtd: tests/read: initialize buffer for whole next page fix: do block-buffer initialize for the whole next page to zero. Signed-off-by: Christian Herzig Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c index 31f505c..266de04 100644 --- a/drivers/mtd/tests/mtd_readtest.c +++ b/drivers/mtd/tests/mtd_readtest.c @@ -51,7 +51,7 @@ static int read_eraseblock_by_page(int ebnum) void *oobbuf = iobuf1; for (i = 0; i < pgcnt; i++) { - memset(buf, 0 , pgcnt); + memset(buf, 0 , pgsize); ret = mtd_read(mtd, addr, pgsize, &read, buf); if (ret == -EUCLEAN) ret = 0; -- cgit v0.10.2 From 464ee9f966404786ba4c6be35dc8362ee8e6ba4e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 12:49:27 -0500 Subject: NFSv4.1: Ensure that the client tracks the server target_highest_slotid Dynamic slot allocation in NFSv4.1 depends on the client being able to track the server's target value for the highest slotid in the slot table. See the reference in Section 2.10.6.1 of RFC5661. To avoid ordering problems in the case where 2 SEQUENCE replies contain conflicting updates to this target value, we also introduce a generation counter, to track whether or not an RPC containing a SEQUENCE operation was launched before or after the last update. Also rename the nfs4_slot_table target_max_slots field to 'target_highest_slotid' to avoid confusion with a slot table size or number of slots. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 0be08b9..0ef047b 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -576,7 +576,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, if (args->crsa_target_max_slots == fc_tbl->max_slots) goto out; - fc_tbl->target_max_slots = args->crsa_target_max_slots; + fc_tbl->target_highest_slotid = args->crsa_target_max_slots; nfs41_handle_recall_slot(cps->clp); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 197ef3e..d91abaa 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -488,6 +488,28 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) res->sr_slot = NULL; } +/* Update the client's idea of target_highest_slotid */ +static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, + u32 target_highest_slotid) +{ + if (tbl->target_highest_slotid == target_highest_slotid) + return; + tbl->target_highest_slotid = target_highest_slotid; + tbl->generation++; +} + +static void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, + struct nfs4_slot *slot, + struct nfs4_sequence_res *res) +{ + spin_lock(&tbl->slot_tbl_lock); + if (tbl->generation != slot->generation) + goto out; + nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); +out: + spin_unlock(&tbl->slot_tbl_lock); +} + static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) { struct nfs4_session *session; @@ -522,6 +544,7 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * /* Check sequence flags */ if (res->sr_status_flags != 0) nfs4_schedule_lease_recovery(clp); + nfs41_update_target_slotid(slot->table, slot, res); break; case -NFS4ERR_DELAY: /* The server detected a resend of the RPC call and @@ -583,6 +606,7 @@ static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) tbl->highest_used_slotid = slotid; ret = &tbl->slots[slotid]; ret->renewal_time = jiffies; + ret->generation = tbl->generation; out: dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", @@ -5693,6 +5717,7 @@ static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, tbl->max_slots = max_slots; } tbl->highest_used_slotid = NFS4_NO_SLOT; + tbl->target_highest_slotid = max_slots - 1; for (i = 0; i < tbl->max_slots; i++) tbl->slots[i].seq_nr = ivalue; spin_unlock(&tbl->slot_tbl_lock); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 9495789..842cb8c 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -2033,17 +2033,16 @@ static int nfs4_recall_slot(struct nfs_client *clp) return 0; nfs4_begin_drain_session(clp); fc_tbl = &clp->cl_session->fc_slot_table; - new = nfs4_alloc_slots(fc_tbl, fc_tbl->target_max_slots, GFP_NOFS); + new = nfs4_alloc_slots(fc_tbl, fc_tbl->target_highest_slotid + 1, GFP_NOFS); if (!new) return -ENOMEM; spin_lock(&fc_tbl->slot_tbl_lock); - for (i = 0; i < fc_tbl->target_max_slots; i++) + for (i = 0; i <= fc_tbl->target_highest_slotid; i++) new[i].seq_nr = fc_tbl->slots[i].seq_nr; old = fc_tbl->slots; fc_tbl->slots = new; - fc_tbl->max_slots = fc_tbl->target_max_slots; - fc_tbl->target_max_slots = 0; + fc_tbl->max_slots = fc_tbl->target_highest_slotid + 1; clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots; spin_unlock(&fc_tbl->slot_tbl_lock); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 27b0fec..05d34f1 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -5552,8 +5552,8 @@ static int decode_sequence(struct xdr_stream *xdr, } /* highest slot id - currently not processed */ dummy = be32_to_cpup(p++); - /* target highest slot id - currently not processed */ - dummy = be32_to_cpup(p++); + /* target highest slot id */ + res->sr_target_highest_slotid = be32_to_cpup(p++); /* result flags */ res->sr_status_flags = be32_to_cpup(p); status = 0; diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index b041287..57d4069 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -217,8 +217,9 @@ struct nfs4_slot_table { u32 max_slots; /* # slots in table */ u32 highest_used_slotid; /* sent to server on each SEQ. * op for dynamic resizing */ - u32 target_max_slots; /* Set by CB_RECALL_SLOT as - * the new max_slots */ + u32 target_highest_slotid; /* Server max_slot target */ + unsigned long generation; /* Generation counter for + target_highest_slotid */ struct completion complete; }; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index deb31bb..08c47db 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -188,6 +188,7 @@ struct nfs4_channel_attrs { /* nfs41 sessions slot seqid */ struct nfs4_slot { struct nfs4_slot_table *table; + unsigned long generation; unsigned long renewal_time; u32 slot_nr; u32 seq_nr; @@ -202,6 +203,7 @@ struct nfs4_sequence_res { struct nfs4_slot *sr_slot; /* slot used to send request */ int sr_status; /* sequence operation status */ u32 sr_status_flags; + u32 sr_target_highest_slotid; }; struct nfs4_get_lease_time_args { -- cgit v0.10.2 From da0507b7c95ccd4d9c86394eef42fe076032af30 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 18:10:30 -0500 Subject: NFSv4.1: Reset the sequence number for slots that have been deallocated When the server tells us that it is dynamically resizing the session replay cache, we should reset the sequence number for those slots that have been deallocated. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d91abaa..52435ec 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -498,6 +498,22 @@ static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, tbl->generation++; } +static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, + u32 highest_slotid) +{ + unsigned int max_slotid, i; + + if (tbl->server_highest_slotid == highest_slotid) + return; + if (tbl->highest_used_slotid > highest_slotid) + return; + max_slotid = min(tbl->max_slots - 1, highest_slotid); + /* Reset the seq_nr for deallocated slots */ + for (i = tbl->server_highest_slotid + 1; i <= max_slotid; i++) + tbl->slots[i].seq_nr = 1; + tbl->server_highest_slotid = highest_slotid; +} + static void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, struct nfs4_slot *slot, struct nfs4_sequence_res *res) @@ -505,6 +521,7 @@ static void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, spin_lock(&tbl->slot_tbl_lock); if (tbl->generation != slot->generation) goto out; + nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid); nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); out: spin_unlock(&tbl->slot_tbl_lock); @@ -5718,6 +5735,7 @@ static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, } tbl->highest_used_slotid = NFS4_NO_SLOT; tbl->target_highest_slotid = max_slots - 1; + tbl->server_highest_slotid = max_slots - 1; for (i = 0; i < tbl->max_slots; i++) tbl->slots[i].seq_nr = ivalue; spin_unlock(&tbl->slot_tbl_lock); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 05d34f1..a67040f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -5550,8 +5550,8 @@ static int decode_sequence(struct xdr_stream *xdr, dprintk("%s Invalid slot id\n", __func__); goto out_err; } - /* highest slot id - currently not processed */ - dummy = be32_to_cpup(p++); + /* highest slot id */ + res->sr_highest_slotid = be32_to_cpup(p++); /* target highest slot id */ res->sr_target_highest_slotid = be32_to_cpup(p++); /* result flags */ diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 57d4069..646e64b 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -218,6 +218,7 @@ struct nfs4_slot_table { u32 highest_used_slotid; /* sent to server on each SEQ. * op for dynamic resizing */ u32 target_highest_slotid; /* Server max_slot target */ + u32 server_highest_slotid; /* Server highest slotid */ unsigned long generation; /* Generation counter for target_highest_slotid */ struct completion complete; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 08c47db..3ddb08f 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -203,6 +203,7 @@ struct nfs4_sequence_res { struct nfs4_slot *sr_slot; /* slot used to send request */ int sr_status; /* sequence operation status */ u32 sr_status_flags; + u32 sr_highest_slotid; u32 sr_target_highest_slotid; }; -- cgit v0.10.2 From ce008c4bb9766bc7eeb02e8299c8baadc25da90b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 15:16:30 -0500 Subject: NFSv4.1: Fix nfs4_callback_recallslot to work with dynamic slot allocation Ensure that the NFSv4.1 CB_RECALL_SLOT callback updates the slot table target max slotid safely. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 0ef047b..15b9879 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -576,7 +576,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, if (args->crsa_target_max_slots == fc_tbl->max_slots) goto out; - fc_tbl->target_highest_slotid = args->crsa_target_max_slots; + nfs41_set_target_slotid(fc_tbl, args->crsa_target_max_slots); nfs41_handle_recall_slot(cps->clp); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 42c5869..5d4e82b 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -260,6 +260,8 @@ extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, extern struct nfs4_slot *nfs4_alloc_slots(struct nfs4_slot_table *table, u32 max_slots, gfp_t gfp_flags); +extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, + u32 target_highest_slotid); static inline bool is_ds_only_client(struct nfs_client *clp) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 52435ec..6221223 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -498,6 +498,14 @@ static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, tbl->generation++; } +void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, + u32 target_highest_slotid) +{ + spin_lock(&tbl->slot_tbl_lock); + nfs41_set_target_slotid_locked(tbl, target_highest_slotid); + spin_unlock(&tbl->slot_tbl_lock); +} + static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, u32 highest_slotid) { -- cgit v0.10.2 From d5fb4ce33e26e4c1c31c1609b8ffbb24f80bcab8 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 20:24:02 -0500 Subject: NFSv4.1: Don't confuse target_highest_slotid and max_slots in cb_recall_slot Don't confuse the table size and the target_highest_slotid... Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index 4251c2a..e75631e 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h @@ -142,7 +142,7 @@ extern __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, struct cb_recallslotargs { struct sockaddr *crsa_addr; - uint32_t crsa_target_max_slots; + uint32_t crsa_target_highest_slotid; }; extern __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 15b9879..ed0b446 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -561,22 +561,20 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, if (!cps->clp) /* set in cb_sequence */ goto out; - dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", + dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target highest slotid %d\n", rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR), - args->crsa_target_max_slots); + args->crsa_target_highest_slotid); fc_tbl = &cps->clp->cl_session->fc_slot_table; status = htonl(NFS4ERR_BAD_HIGH_SLOT); - if (args->crsa_target_max_slots > fc_tbl->max_slots || - args->crsa_target_max_slots < 1) + if (args->crsa_target_highest_slotid >= fc_tbl->max_slots || + args->crsa_target_highest_slotid < 1) goto out; status = htonl(NFS4_OK); - if (args->crsa_target_max_slots == fc_tbl->max_slots) - goto out; - nfs41_set_target_slotid(fc_tbl, args->crsa_target_max_slots); + nfs41_set_target_slotid(fc_tbl, args->crsa_target_highest_slotid); nfs41_handle_recall_slot(cps->clp); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 742ff4f..81e8c7d 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -520,7 +520,7 @@ static __be32 decode_recallslot_args(struct svc_rqst *rqstp, p = read_buf(xdr, 4); if (unlikely(p == NULL)) return htonl(NFS4ERR_BADXDR); - args->crsa_target_max_slots = ntohl(*p++); + args->crsa_target_highest_slotid = ntohl(*p++); return 0; } -- cgit v0.10.2 From 1b285ff16ab52fb401aed7ce70abed4bb65b30b5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 22:32:48 -0500 Subject: NFSv4.1: Allow the server to recall all but one slot If the server wants to leave us with only one slot, or it wants to "shrink" our slot table to something larger than we have now, then so be it. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index ed0b446..a0546ec 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -567,11 +567,6 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, fc_tbl = &cps->clp->cl_session->fc_slot_table; - status = htonl(NFS4ERR_BAD_HIGH_SLOT); - if (args->crsa_target_highest_slotid >= fc_tbl->max_slots || - args->crsa_target_highest_slotid < 1) - goto out; - status = htonl(NFS4_OK); nfs41_set_target_slotid(fc_tbl, args->crsa_target_highest_slotid); -- cgit v0.10.2 From 97e548a93de213b149eea025a97d88e28143b445 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 14:45:48 -0500 Subject: NFSv4.1: Support dynamic resizing of the session slot table Allow the server to control the size of the session slot table by adjusting the value of sr_target_max_slots in the reply to the SEQUENCE operation. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6221223..1792ece 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -492,10 +492,17 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, u32 target_highest_slotid) { + unsigned int max_slotid, i; + if (tbl->target_highest_slotid == target_highest_slotid) return; tbl->target_highest_slotid = target_highest_slotid; tbl->generation++; + + max_slotid = min(tbl->max_slots - 1, tbl->target_highest_slotid); + for (i = tbl->max_slotid + 1; i <= max_slotid; i++) + rpc_wake_up_next(&tbl->slot_tbl_waitq); + tbl->max_slotid = max_slotid; } void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, @@ -622,8 +629,8 @@ static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", __func__, tbl->used_slots[0], tbl->highest_used_slotid, tbl->max_slots); - slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots); - if (slotid >= tbl->max_slots) + slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1); + if (slotid > tbl->max_slotid) goto out; __set_bit(slotid, tbl->used_slots); if (slotid > tbl->highest_used_slotid || @@ -5744,6 +5751,7 @@ static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, tbl->highest_used_slotid = NFS4_NO_SLOT; tbl->target_highest_slotid = max_slots - 1; tbl->server_highest_slotid = max_slots - 1; + tbl->max_slotid = max_slots - 1; for (i = 0; i < tbl->max_slots; i++) tbl->slots[i].seq_nr = ivalue; spin_unlock(&tbl->slot_tbl_lock); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 842cb8c..1b7fa73 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -254,15 +254,14 @@ static void nfs4_end_drain_session(struct nfs_client *clp) { struct nfs4_session *ses = clp->cl_session; struct nfs4_slot_table *tbl; - int max_slots; + unsigned int i; if (ses == NULL) return; tbl = &ses->fc_slot_table; if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { spin_lock(&tbl->slot_tbl_lock); - max_slots = tbl->max_slots; - while (max_slots--) { + for (i = 0; i <= tbl->max_slotid; i++) { if (rpc_wake_up_first(&tbl->slot_tbl_waitq, nfs4_set_task_privileged, NULL) == NULL) @@ -2043,6 +2042,7 @@ static int nfs4_recall_slot(struct nfs_client *clp) old = fc_tbl->slots; fc_tbl->slots = new; fc_tbl->max_slots = fc_tbl->target_highest_slotid + 1; + fc_tbl->max_slotid = fc_tbl->target_highest_slotid; clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots; spin_unlock(&fc_tbl->slot_tbl_lock); diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 646e64b..3071550 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -215,6 +215,7 @@ struct nfs4_slot_table { spinlock_t slot_tbl_lock; struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */ u32 max_slots; /* # slots in table */ + u32 max_slotid; /* Max allowed slotid value */ u32 highest_used_slotid; /* sent to server on each SEQ. * op for dynamic resizing */ u32 target_highest_slotid; /* Server max_slot target */ -- cgit v0.10.2 From 87dda67e7386ba7d2164391ea58b34e028d8157b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 19:49:20 -0500 Subject: NFSv4.1: Allow SEQUENCE to resize the slot table on the fly Instead of an array of slots, use a singly linked list of slots that can be dynamically appended to or shrunk. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 5d4e82b..856bc49 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -258,10 +258,10 @@ extern int nfs4_proc_get_lease_time(struct nfs_client *clp, extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync); -extern struct nfs4_slot *nfs4_alloc_slots(struct nfs4_slot_table *table, - u32 max_slots, gfp_t gfp_flags); extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, u32 target_highest_slotid); +extern int nfs4_resize_slot_table(struct nfs4_slot_table *tbl, + u32 max_reqs, u32 ivalue); static inline bool is_ds_only_client(struct nfs_client *clp) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1792ece..fc65300 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -397,6 +397,27 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp #if defined(CONFIG_NFS_V4_1) /* + * nfs4_shrink_slot_table - free retired slots from the slot table + */ +static void nfs4_shrink_slot_table(struct nfs4_slot_table *tbl, u32 newsize) +{ + struct nfs4_slot **p; + if (newsize >= tbl->max_slots) + return; + + p = &tbl->slots; + while (newsize--) + p = &(*p)->next; + while (*p) { + struct nfs4_slot *slot = *p; + + *p = slot->next; + kfree(slot); + tbl->max_slots--; + } +} + +/* * nfs4_free_slot - free a slot and efficiently update slot table. * * freeing a slot is trivially done by clearing its respective bit @@ -499,7 +520,7 @@ static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, tbl->target_highest_slotid = target_highest_slotid; tbl->generation++; - max_slotid = min(tbl->max_slots - 1, tbl->target_highest_slotid); + max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid); for (i = tbl->max_slotid + 1; i <= max_slotid; i++) rpc_wake_up_next(&tbl->slot_tbl_waitq); tbl->max_slotid = max_slotid; @@ -516,16 +537,12 @@ void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, u32 highest_slotid) { - unsigned int max_slotid, i; - if (tbl->server_highest_slotid == highest_slotid) return; if (tbl->highest_used_slotid > highest_slotid) return; - max_slotid = min(tbl->max_slots - 1, highest_slotid); - /* Reset the seq_nr for deallocated slots */ - for (i = tbl->server_highest_slotid + 1; i <= max_slotid; i++) - tbl->slots[i].seq_nr = 1; + /* Deallocate slots */ + nfs4_shrink_slot_table(tbl, highest_slotid + 1); tbl->server_highest_slotid = highest_slotid; } @@ -612,6 +629,42 @@ static int nfs4_sequence_done(struct rpc_task *task, return nfs41_sequence_done(task, res); } +static struct nfs4_slot *nfs4_new_slot(struct nfs4_slot_table *tbl, + u32 slotid, u32 seq_init, gfp_t gfp_mask) +{ + struct nfs4_slot *slot; + + slot = kzalloc(sizeof(*slot), gfp_mask); + if (slot) { + slot->table = tbl; + slot->slot_nr = slotid; + slot->seq_nr = seq_init; + } + return slot; +} + +static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table *tbl, + u32 slotid, u32 seq_init, gfp_t gfp_mask) +{ + struct nfs4_slot **p, *slot; + + p = &tbl->slots; + for (;;) { + if (*p == NULL) { + *p = nfs4_new_slot(tbl, tbl->max_slots, + seq_init, gfp_mask); + if (*p == NULL) + break; + tbl->max_slots++; + } + slot = *p; + if (slot->slot_nr == slotid) + return slot; + p = &slot->next; + } + return NULL; +} + /* * nfs4_alloc_slot - efficiently look for a free slot * @@ -628,15 +681,17 @@ static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", __func__, tbl->used_slots[0], tbl->highest_used_slotid, - tbl->max_slots); + tbl->max_slotid + 1); slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1); if (slotid > tbl->max_slotid) goto out; + ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT); + if (ret == NULL) + goto out; __set_bit(slotid, tbl->used_slots); if (slotid > tbl->highest_used_slotid || tbl->highest_used_slotid == NFS4_NO_SLOT) tbl->highest_used_slotid = slotid; - ret = &tbl->slots[slotid]; ret->renewal_time = jiffies; ret->generation = tbl->generation; @@ -5718,67 +5773,56 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) return status; } -struct nfs4_slot *nfs4_alloc_slots(struct nfs4_slot_table *table, - u32 max_slots, gfp_t gfp_flags) +static int nfs4_grow_slot_table(struct nfs4_slot_table *tbl, + u32 max_reqs, u32 ivalue) { - struct nfs4_slot *tbl; - u32 i; - - tbl = kmalloc_array(max_slots, sizeof(*tbl), gfp_flags); - if (tbl != NULL) { - for (i = 0; i < max_slots; i++) { - tbl[i].table = table; - tbl[i].slot_nr = i; - } - } - return tbl; + if (max_reqs <= tbl->max_slots) + return 0; + if (nfs4_find_or_create_slot(tbl, max_reqs - 1, ivalue, GFP_NOFS)) + return 0; + return -ENOMEM; } -static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl, - struct nfs4_slot *new, - u32 max_slots, +static void nfs4_reset_slot_table(struct nfs4_slot_table *tbl, + u32 server_highest_slotid, u32 ivalue) { - struct nfs4_slot *old = NULL; - u32 i; + struct nfs4_slot **p; - spin_lock(&tbl->slot_tbl_lock); - if (new) { - old = tbl->slots; - tbl->slots = new; - tbl->max_slots = max_slots; + nfs4_shrink_slot_table(tbl, server_highest_slotid + 1); + p = &tbl->slots; + while (*p) { + (*p)->seq_nr = ivalue; + p = &(*p)->next; } tbl->highest_used_slotid = NFS4_NO_SLOT; - tbl->target_highest_slotid = max_slots - 1; - tbl->server_highest_slotid = max_slots - 1; - tbl->max_slotid = max_slots - 1; - for (i = 0; i < tbl->max_slots; i++) - tbl->slots[i].seq_nr = ivalue; - spin_unlock(&tbl->slot_tbl_lock); - kfree(old); + tbl->target_highest_slotid = server_highest_slotid; + tbl->server_highest_slotid = server_highest_slotid; + tbl->max_slotid = server_highest_slotid; } /* * (re)Initialise a slot table */ -static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, - u32 ivalue) +static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, + u32 max_reqs, u32 ivalue) { - struct nfs4_slot *new = NULL; - int ret = -ENOMEM; + int ret; dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, max_reqs, tbl->max_slots); - /* Does the newly negotiated max_reqs match the existing slot table? */ - if (max_reqs != tbl->max_slots) { - new = nfs4_alloc_slots(tbl, max_reqs, GFP_NOFS); - if (!new) - goto out; - } - ret = 0; + if (max_reqs > NFS4_MAX_SLOT_TABLE) + max_reqs = NFS4_MAX_SLOT_TABLE; + + ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue); + if (ret) + goto out; + + spin_lock(&tbl->slot_tbl_lock); + nfs4_reset_slot_table(tbl, max_reqs - 1, ivalue); + spin_unlock(&tbl->slot_tbl_lock); - nfs4_add_and_init_slots(tbl, new, max_reqs, ivalue); dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, tbl, tbl->slots, tbl->max_slots); out: @@ -5786,18 +5830,28 @@ out: return ret; } +int nfs4_resize_slot_table(struct nfs4_slot_table *tbl, + u32 max_reqs, u32 ivalue) +{ + int ret; + + if (max_reqs > NFS4_MAX_SLOT_TABLE) + max_reqs = NFS4_MAX_SLOT_TABLE; + ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue); + if (ret) + return ret; + spin_lock(&tbl->slot_tbl_lock); + nfs4_shrink_slot_table(tbl, max_reqs); + tbl->max_slotid = max_reqs - 1; + spin_unlock(&tbl->slot_tbl_lock); + return 0; +} + /* Destroy the slot table */ static void nfs4_destroy_slot_tables(struct nfs4_session *session) { - if (session->fc_slot_table.slots != NULL) { - kfree(session->fc_slot_table.slots); - session->fc_slot_table.slots = NULL; - } - if (session->bc_slot_table.slots != NULL) { - kfree(session->bc_slot_table.slots); - session->bc_slot_table.slots = NULL; - } - return; + nfs4_shrink_slot_table(&session->fc_slot_table, 0); + nfs4_shrink_slot_table(&session->bc_slot_table, 0); } /* diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 1b7fa73..c14b2c7 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -2025,29 +2025,15 @@ out: static int nfs4_recall_slot(struct nfs_client *clp) { struct nfs4_slot_table *fc_tbl; - struct nfs4_slot *new, *old; - int i; + u32 new_size; if (!nfs4_has_session(clp)) return 0; nfs4_begin_drain_session(clp); - fc_tbl = &clp->cl_session->fc_slot_table; - new = nfs4_alloc_slots(fc_tbl, fc_tbl->target_highest_slotid + 1, GFP_NOFS); - if (!new) - return -ENOMEM; - spin_lock(&fc_tbl->slot_tbl_lock); - for (i = 0; i <= fc_tbl->target_highest_slotid; i++) - new[i].seq_nr = fc_tbl->slots[i].seq_nr; - old = fc_tbl->slots; - fc_tbl->slots = new; - fc_tbl->max_slots = fc_tbl->target_highest_slotid + 1; - fc_tbl->max_slotid = fc_tbl->target_highest_slotid; - clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots; - spin_unlock(&fc_tbl->slot_tbl_lock); - - kfree(old); - return 0; + fc_tbl = &clp->cl_session->fc_slot_table; + new_size = fc_tbl->server_highest_slotid + 1; + return nfs4_resize_slot_table(fc_tbl, new_size, 1); } static int nfs4_bind_conn_to_session(struct nfs_client *clp) diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 3ddb08f..44d256f 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -188,6 +188,7 @@ struct nfs4_channel_attrs { /* nfs41 sessions slot seqid */ struct nfs4_slot { struct nfs4_slot_table *table; + struct nfs4_slot *next; unsigned long generation; unsigned long renewal_time; u32 slot_nr; -- cgit v0.10.2 From afa296103ea3841fdc81d9d66902fe49bb765527 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 20 Nov 2012 20:12:38 -0500 Subject: NFSv4.1: Remove the state manager code to resize the slot table The state manager no longer needs any special machinery to stop the session flow and resize the slot table. It is all done on the fly by the SEQUENCE op code now. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index a0546ec..8610bd1 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -570,7 +570,6 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, status = htonl(NFS4_OK); nfs41_set_target_slotid(fc_tbl, args->crsa_target_highest_slotid); - nfs41_handle_recall_slot(cps->clp); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 856bc49..fa1a055 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -21,7 +21,6 @@ enum nfs4_client_state { NFS4CLNT_RECLAIM_NOGRACE, NFS4CLNT_DELEGRETURN, NFS4CLNT_SESSION_RESET, - NFS4CLNT_RECALL_SLOT, NFS4CLNT_LEASE_CONFIRM, NFS4CLNT_SERVER_SCOPE_MISMATCH, NFS4CLNT_PURGE_STATE, @@ -260,8 +259,6 @@ extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, u32 target_highest_slotid); -extern int nfs4_resize_slot_table(struct nfs4_slot_table *tbl, - u32 max_reqs, u32 ivalue); static inline bool is_ds_only_client(struct nfs_client *clp) @@ -358,7 +355,6 @@ extern void nfs4_schedule_state_manager(struct nfs_client *); extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); -extern void nfs41_handle_recall_slot(struct nfs_client *clp); extern void nfs41_handle_server_scope(struct nfs_client *, struct nfs41_server_scope **); extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index fc65300..0642e28 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5830,23 +5830,6 @@ out: return ret; } -int nfs4_resize_slot_table(struct nfs4_slot_table *tbl, - u32 max_reqs, u32 ivalue) -{ - int ret; - - if (max_reqs > NFS4_MAX_SLOT_TABLE) - max_reqs = NFS4_MAX_SLOT_TABLE; - ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue); - if (ret) - return ret; - spin_lock(&tbl->slot_tbl_lock); - nfs4_shrink_slot_table(tbl, max_reqs); - tbl->max_slotid = max_reqs - 1; - spin_unlock(&tbl->slot_tbl_lock); - return 0; -} - /* Destroy the slot table */ static void nfs4_destroy_slot_tables(struct nfs4_session *session) { diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index c14b2c7..3940cd4 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -302,7 +302,6 @@ static void nfs41_finish_session_reset(struct nfs_client *clp) clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); /* create_session negotiated new slot table */ - clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state); nfs41_setup_state_renewal(clp); } @@ -1905,14 +1904,6 @@ void nfs4_schedule_session_recovery(struct nfs4_session *session, int err) } EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery); -void nfs41_handle_recall_slot(struct nfs_client *clp) -{ - set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); - dprintk("%s: scheduling slot recall for server %s\n", __func__, - clp->cl_hostname); - nfs4_schedule_state_manager(clp); -} - static void nfs4_reset_all_state(struct nfs_client *clp) { if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { @@ -2022,20 +2013,6 @@ out: return status; } -static int nfs4_recall_slot(struct nfs_client *clp) -{ - struct nfs4_slot_table *fc_tbl; - u32 new_size; - - if (!nfs4_has_session(clp)) - return 0; - nfs4_begin_drain_session(clp); - - fc_tbl = &clp->cl_session->fc_slot_table; - new_size = fc_tbl->server_highest_slotid + 1; - return nfs4_resize_slot_table(fc_tbl, new_size, 1); -} - static int nfs4_bind_conn_to_session(struct nfs_client *clp) { struct rpc_cred *cred; @@ -2066,7 +2043,6 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp) #else /* CONFIG_NFS_V4_1 */ static int nfs4_reset_session(struct nfs_client *clp) { return 0; } static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; } -static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } static int nfs4_bind_conn_to_session(struct nfs_client *clp) { @@ -2126,15 +2102,6 @@ static void nfs4_state_manager(struct nfs_client *clp) continue; } - /* Recall session slots */ - if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)) { - section = "recall slot"; - status = nfs4_recall_slot(clp); - if (status < 0) - goto out_error; - continue; - } - /* First recover reboot state... */ if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { section = "reclaim reboot"; -- cgit v0.10.2 From ac0748359a55faf4618f5f0bd9f9bf967c41d218 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 21 Nov 2012 09:06:11 -0500 Subject: NFSv4.1: CB_RECALL_SLOT must schedule a sequence op after updating targets RFC5661 requires us to make sure that the server knows we've updated our slot table size by sending at least one SEQUENCE op containing the new 'highest_slotid' value. We can do so using the 'CHECK_LEASE' functionality of the state manager. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 8610bd1..f99faad 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -570,6 +570,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, status = htonl(NFS4_OK); nfs41_set_target_slotid(fc_tbl, args->crsa_target_highest_slotid); + nfs41_server_notify_target_slotid_update(cps->clp); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index fa1a055..0a109ec 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -334,6 +334,7 @@ struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp); int nfs41_discover_server_trunking(struct nfs_client *clp, struct nfs_client **, struct rpc_cred *); extern void nfs4_schedule_session_recovery(struct nfs4_session *, int); +extern void nfs41_server_notify_target_slotid_update(struct nfs_client *clp); #else static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err) { diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 3940cd4..896be21 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1904,6 +1904,18 @@ void nfs4_schedule_session_recovery(struct nfs4_session *session, int err) } EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery); +static void nfs41_ping_server(struct nfs_client *clp) +{ + /* Use CHECK_LEASE to ping the server with a SEQUENCE */ + set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); + nfs4_schedule_state_manager(clp); +} + +void nfs41_server_notify_target_slotid_update(struct nfs_client *clp) +{ + nfs41_ping_server(clp); +} + static void nfs4_reset_all_state(struct nfs_client *clp) { if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { -- cgit v0.10.2 From 69d206b5b39e298755b60e8e7056cb240182eb95 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 22 Nov 2012 13:21:02 -0500 Subject: NFSv4.1: If slot allocation fails due to OOM, retry more quickly If the NFSv4.1 session slot allocation fails due to an ENOMEM condition, then set the task->tk_timeout to 1/4 second to ensure that we do retry the slot allocation more quickly. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0642e28..e9e4d63 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -662,7 +662,7 @@ static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table *tbl, return slot; p = &slot->next; } - return NULL; + return ERR_PTR(-ENOMEM); } /* @@ -676,7 +676,7 @@ static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table *tbl, */ static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) { - struct nfs4_slot *ret = NULL; + struct nfs4_slot *ret = ERR_PTR(-EBUSY); u32 slotid; dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", @@ -686,7 +686,7 @@ static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) if (slotid > tbl->max_slotid) goto out; ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT); - if (ret == NULL) + if (IS_ERR(ret)) goto out; __set_bit(slotid, tbl->used_slots); if (slotid > tbl->highest_used_slotid || @@ -698,7 +698,7 @@ static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) out: dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", __func__, tbl->used_slots[0], tbl->highest_used_slotid, - ret ? ret->slot_nr : -1); + !IS_ERR(ret) ? ret->slot_nr : -1); return ret; } @@ -727,6 +727,8 @@ int nfs41_setup_sequence(struct nfs4_session *session, tbl = &session->fc_slot_table; + task->tk_timeout = 0; + spin_lock(&tbl->slot_tbl_lock); if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { @@ -746,7 +748,10 @@ int nfs41_setup_sequence(struct nfs4_session *session, } slot = nfs4_alloc_slot(tbl); - if (slot == NULL) { + if (IS_ERR(slot)) { + /* If out of memory, try again in 1/4 second */ + if (slot == ERR_PTR(-ENOMEM)) + task->tk_timeout = HZ >> 2; rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); spin_unlock(&tbl->slot_tbl_lock); dprintk("<-- %s: no free slots\n", __func__); @@ -5778,7 +5783,7 @@ static int nfs4_grow_slot_table(struct nfs4_slot_table *tbl, { if (max_reqs <= tbl->max_slots) return 0; - if (nfs4_find_or_create_slot(tbl, max_reqs - 1, ivalue, GFP_NOFS)) + if (!IS_ERR(nfs4_find_or_create_slot(tbl, max_reqs - 1, ivalue, GFP_NOFS))) return 0; return -ENOMEM; } -- cgit v0.10.2 From 5d63360dd8daffc2bc86531e9a44ff9d4881b102 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 23 Nov 2012 13:09:38 -0500 Subject: NFSv4.1: Clean up session draining Coalesce nfs4_check_drain_bc_complete and nfs4_check_drain_fc_complete into a single function that can be called when the slot table is known to be empty, then change nfs4_callback_free_slot() and nfs4_free_slot() to use it. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index e75631e..efd54f0a 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h @@ -167,8 +167,6 @@ extern __be32 nfs4_callback_layoutrecall( struct cb_layoutrecallargs *args, void *dummy, struct cb_process_state *cps); -extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses); - struct cb_devicenotifyitem { uint32_t cbd_notify_type; uint32_t cbd_layout_type; diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 81e8c7d..ea6a7b1 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -762,7 +762,7 @@ static void nfs4_callback_free_slot(struct nfs4_session *session) * A single slot, so highest used slotid is either 0 or -1 */ tbl->highest_used_slotid = NFS4_NO_SLOT; - nfs4_check_drain_bc_complete(session); + nfs4_session_drain_complete(session, tbl); spin_unlock(&tbl->slot_tbl_lock); } diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 0a109ec..16b1937 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -335,6 +335,14 @@ int nfs41_discover_server_trunking(struct nfs_client *clp, struct nfs_client **, struct rpc_cred *); extern void nfs4_schedule_session_recovery(struct nfs4_session *, int); extern void nfs41_server_notify_target_slotid_update(struct nfs_client *clp); + +extern void nfs4_session_drain_complete(struct nfs4_session *session, + struct nfs4_slot_table *tbl); + +static inline bool nfs4_session_draining(struct nfs4_session *session) +{ + return !!test_bit(NFS4_SESSION_DRAINING, &session->session_state); +} #else static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err) { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e9e4d63..0b0f11b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -445,8 +445,10 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot) u32 new_max = find_last_bit(tbl->used_slots, slotid); if (new_max < slotid) tbl->highest_used_slotid = new_max; - else + else { tbl->highest_used_slotid = NFS4_NO_SLOT; + nfs4_session_drain_complete(tbl->session, tbl); + } } dprintk("%s: slotid %u highest_used_slotid %d\n", __func__, slotid, tbl->highest_used_slotid); @@ -458,36 +460,6 @@ bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy) return true; } -/* - * Signal state manager thread if session fore channel is drained - */ -static void nfs4_check_drain_fc_complete(struct nfs4_session *ses) -{ - if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { - rpc_wake_up_first(&ses->fc_slot_table.slot_tbl_waitq, - nfs4_set_task_privileged, NULL); - return; - } - - if (ses->fc_slot_table.highest_used_slotid != NFS4_NO_SLOT) - return; - - dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__); - complete(&ses->fc_slot_table.complete); -} - -/* - * Signal state manager thread if session back channel is drained - */ -void nfs4_check_drain_bc_complete(struct nfs4_session *ses) -{ - if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) || - ses->bc_slot_table.highest_used_slotid != NFS4_NO_SLOT) - return; - dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__); - complete(&ses->bc_slot_table.complete); -} - static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) { struct nfs4_session *session; @@ -504,7 +476,9 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) spin_lock(&tbl->slot_tbl_lock); nfs4_free_slot(tbl, res->sr_slot); - nfs4_check_drain_fc_complete(session); + if (!nfs4_session_draining(session)) + rpc_wake_up_first(&tbl->slot_tbl_waitq, + nfs4_set_task_privileged, NULL); spin_unlock(&tbl->slot_tbl_lock); res->sr_slot = NULL; } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 896be21..1fb3e6c 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -271,6 +271,16 @@ static void nfs4_end_drain_session(struct nfs_client *clp) } } +/* + * Signal state manager thread if session fore channel is drained + */ +void nfs4_session_drain_complete(struct nfs4_session *session, + struct nfs4_slot_table *tbl) +{ + if (nfs4_session_draining(session)) + complete(&tbl->complete); +} + static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl) { spin_lock(&tbl->slot_tbl_lock); -- cgit v0.10.2 From 330212796756ca2752b2a70a83860e145b77487c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 26 Nov 2012 13:13:29 -0500 Subject: NFSv4: Move nfs4_wait_clnt_recover and nfs4_client_recover_expired_lease nfs4_wait_clnt_recover and nfs4_client_recover_expired_lease are both generic state related functions. As such, they belong in nfs4state.c, and not nfs4proc.c Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 16b1937..2f6a9f9 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -11,6 +11,8 @@ #if IS_ENABLED(CONFIG_NFS_V4) +#define NFS4_MAX_LOOP_ON_RECOVER (10) + struct idmap; enum nfs4_client_state { @@ -360,6 +362,8 @@ extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); extern void nfs_inode_find_state_and_recover(struct inode *inode, const nfs4_stateid *stateid); extern void nfs4_schedule_lease_recovery(struct nfs_client *); +extern int nfs4_wait_clnt_recover(struct nfs_client *clp); +extern int nfs4_client_recover_expired_lease(struct nfs_client *clp); extern void nfs4_schedule_state_manager(struct nfs_client *); extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0b0f11b..d75e2a2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -70,8 +70,6 @@ #define NFS4_POLL_RETRY_MIN (HZ/10) #define NFS4_POLL_RETRY_MAX (15*HZ) -#define NFS4_MAX_LOOP_ON_RECOVER (10) - struct nfs4_opendata; static int _nfs4_proc_open(struct nfs4_opendata *data); static int _nfs4_recover_proc_open(struct nfs4_opendata *data); @@ -255,22 +253,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent kunmap_atomic(start); } -static int nfs4_wait_clnt_recover(struct nfs_client *clp) -{ - int res; - - might_sleep(); - - res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING, - nfs_wait_bit_killable, TASK_KILLABLE); - if (res) - return res; - - if (clp->cl_cons_state < 0) - return clp->cl_cons_state; - return 0; -} - static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) { int res = 0; @@ -1883,24 +1865,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) return 0; } -static int nfs4_client_recover_expired_lease(struct nfs_client *clp) -{ - unsigned int loop; - int ret; - - for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { - ret = nfs4_wait_clnt_recover(clp); - if (ret != 0) - break; - if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && - !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) - break; - nfs4_schedule_state_manager(clp); - ret = -EIO; - } - return ret; -} - static int nfs4_recover_expired_lease(struct nfs_server *server) { return nfs4_client_recover_expired_lease(server->nfs_client); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 1fb3e6c..1077b96 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1216,6 +1216,40 @@ void nfs4_schedule_lease_recovery(struct nfs_client *clp) } EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery); +int nfs4_wait_clnt_recover(struct nfs_client *clp) +{ + int res; + + might_sleep(); + + res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING, + nfs_wait_bit_killable, TASK_KILLABLE); + if (res) + return res; + + if (clp->cl_cons_state < 0) + return clp->cl_cons_state; + return 0; +} + +int nfs4_client_recover_expired_lease(struct nfs_client *clp) +{ + unsigned int loop; + int ret; + + for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { + ret = nfs4_wait_clnt_recover(clp); + if (ret != 0) + break; + if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && + !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) + break; + nfs4_schedule_state_manager(clp); + ret = -EIO; + } + return ret; +} + /* * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN * @clp: client to process -- cgit v0.10.2 From 73e39aaa8366694450cd6034050f542f965e277d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 26 Nov 2012 12:49:34 -0500 Subject: NFSv4.1: Cleanup move session slot management to fs/nfs/nfs4session.c NFSv4.1 session management is getting complex enough to deserve a separate file. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index b7db608..cce2c05 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -24,7 +24,7 @@ nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \ nfs4namespace.o nfs4getroot.o nfs4client.o nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o -nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o +nfsv4-$(CONFIG_NFS_V4_1) += nfs4session.o pnfs.o pnfs_dev.o obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index f99faad..c89b26b 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -14,6 +14,7 @@ #include "delegation.h" #include "internal.h" #include "pnfs.h" +#include "nfs4session.h" #ifdef NFS_DEBUG #define NFSDBG_FACILITY NFSDBG_CALLBACK diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 05521ca..8965a99 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -276,8 +276,6 @@ extern const u32 nfs41_maxwrite_overhead; extern struct rpc_procinfo nfs4_procedures[]; #endif -extern int nfs4_init_ds_session(struct nfs_client *, unsigned long); - /* proc.c */ void nfs_close_context(struct nfs_open_context *ctx, int is_sync); extern struct nfs_client *nfs_init_client(struct nfs_client *clp, diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 2f6a9f9..cd3e309 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -249,19 +249,13 @@ extern int nfs4_setup_sequence(const struct nfs_server *server, extern int nfs41_setup_sequence(struct nfs4_session *session, struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, struct rpc_task *task); -extern void nfs4_destroy_session(struct nfs4_session *session); -extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *); extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *); -extern int nfs4_init_session(struct nfs_server *server); extern int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo); extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync); -extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, - u32 target_highest_slotid); - static inline bool is_ds_only_client(struct nfs_client *clp) { @@ -287,11 +281,6 @@ static inline int nfs4_setup_sequence(const struct nfs_server *server, return 0; } -static inline int nfs4_init_session(struct nfs_server *server) -{ - return 0; -} - static inline bool is_ds_only_client(struct nfs_client *clp) { diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 72717e6..acc3472 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -12,6 +12,7 @@ #include "internal.h" #include "callback.h" #include "delegation.h" +#include "nfs4session.h" #include "pnfs.h" #include "netns.h" diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 93e2530..b720064 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c @@ -33,6 +33,7 @@ #include #include "internal.h" +#include "nfs4session.h" #include "nfs4filelayout.h" #define NFSDBG_FACILITY NFSDBG_PNFS_LD diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d75e2a2..a0c35ab 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -52,7 +52,6 @@ #include #include #include -#include #include #include #include @@ -64,6 +63,8 @@ #include "callback.h" #include "pnfs.h" #include "netns.h" +#include "nfs4session.h" + #define NFSDBG_FACILITY NFSDBG_PROC @@ -378,64 +379,6 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp #if defined(CONFIG_NFS_V4_1) -/* - * nfs4_shrink_slot_table - free retired slots from the slot table - */ -static void nfs4_shrink_slot_table(struct nfs4_slot_table *tbl, u32 newsize) -{ - struct nfs4_slot **p; - if (newsize >= tbl->max_slots) - return; - - p = &tbl->slots; - while (newsize--) - p = &(*p)->next; - while (*p) { - struct nfs4_slot *slot = *p; - - *p = slot->next; - kfree(slot); - tbl->max_slots--; - } -} - -/* - * nfs4_free_slot - free a slot and efficiently update slot table. - * - * freeing a slot is trivially done by clearing its respective bit - * in the bitmap. - * If the freed slotid equals highest_used_slotid we want to update it - * so that the server would be able to size down the slot table if needed, - * otherwise we know that the highest_used_slotid is still in use. - * When updating highest_used_slotid there may be "holes" in the bitmap - * so we need to scan down from highest_used_slotid to 0 looking for the now - * highest slotid in use. - * If none found, highest_used_slotid is set to NFS4_NO_SLOT. - * - * Must be called while holding tbl->slot_tbl_lock - */ -static void -nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot) -{ - u32 slotid = slot->slot_nr; - - /* clear used bit in bitmap */ - __clear_bit(slotid, tbl->used_slots); - - /* update highest_used_slotid when it is freed */ - if (slotid == tbl->highest_used_slotid) { - u32 new_max = find_last_bit(tbl->used_slots, slotid); - if (new_max < slotid) - tbl->highest_used_slotid = new_max; - else { - tbl->highest_used_slotid = NFS4_NO_SLOT; - nfs4_session_drain_complete(tbl->session, tbl); - } - } - dprintk("%s: slotid %u highest_used_slotid %d\n", __func__, - slotid, tbl->highest_used_slotid); -} - bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy) { rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); @@ -465,56 +408,6 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) res->sr_slot = NULL; } -/* Update the client's idea of target_highest_slotid */ -static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, - u32 target_highest_slotid) -{ - unsigned int max_slotid, i; - - if (tbl->target_highest_slotid == target_highest_slotid) - return; - tbl->target_highest_slotid = target_highest_slotid; - tbl->generation++; - - max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid); - for (i = tbl->max_slotid + 1; i <= max_slotid; i++) - rpc_wake_up_next(&tbl->slot_tbl_waitq); - tbl->max_slotid = max_slotid; -} - -void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, - u32 target_highest_slotid) -{ - spin_lock(&tbl->slot_tbl_lock); - nfs41_set_target_slotid_locked(tbl, target_highest_slotid); - spin_unlock(&tbl->slot_tbl_lock); -} - -static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, - u32 highest_slotid) -{ - if (tbl->server_highest_slotid == highest_slotid) - return; - if (tbl->highest_used_slotid > highest_slotid) - return; - /* Deallocate slots */ - nfs4_shrink_slot_table(tbl, highest_slotid + 1); - tbl->server_highest_slotid = highest_slotid; -} - -static void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, - struct nfs4_slot *slot, - struct nfs4_sequence_res *res) -{ - spin_lock(&tbl->slot_tbl_lock); - if (tbl->generation != slot->generation) - goto out; - nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid); - nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); -out: - spin_unlock(&tbl->slot_tbl_lock); -} - static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) { struct nfs4_session *session; @@ -585,79 +478,6 @@ static int nfs4_sequence_done(struct rpc_task *task, return nfs41_sequence_done(task, res); } -static struct nfs4_slot *nfs4_new_slot(struct nfs4_slot_table *tbl, - u32 slotid, u32 seq_init, gfp_t gfp_mask) -{ - struct nfs4_slot *slot; - - slot = kzalloc(sizeof(*slot), gfp_mask); - if (slot) { - slot->table = tbl; - slot->slot_nr = slotid; - slot->seq_nr = seq_init; - } - return slot; -} - -static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table *tbl, - u32 slotid, u32 seq_init, gfp_t gfp_mask) -{ - struct nfs4_slot **p, *slot; - - p = &tbl->slots; - for (;;) { - if (*p == NULL) { - *p = nfs4_new_slot(tbl, tbl->max_slots, - seq_init, gfp_mask); - if (*p == NULL) - break; - tbl->max_slots++; - } - slot = *p; - if (slot->slot_nr == slotid) - return slot; - p = &slot->next; - } - return ERR_PTR(-ENOMEM); -} - -/* - * nfs4_alloc_slot - efficiently look for a free slot - * - * nfs4_alloc_slot looks for an unset bit in the used_slots bitmap. - * If found, we mark the slot as used, update the highest_used_slotid, - * and respectively set up the sequence operation args. - * - * Note: must be called with under the slot_tbl_lock. - */ -static struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) -{ - struct nfs4_slot *ret = ERR_PTR(-EBUSY); - u32 slotid; - - dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", - __func__, tbl->used_slots[0], tbl->highest_used_slotid, - tbl->max_slotid + 1); - slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1); - if (slotid > tbl->max_slotid) - goto out; - ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT); - if (IS_ERR(ret)) - goto out; - __set_bit(slotid, tbl->used_slots); - if (slotid > tbl->highest_used_slotid || - tbl->highest_used_slotid == NFS4_NO_SLOT) - tbl->highest_used_slotid = slotid; - ret->renewal_time = jiffies; - ret->generation = tbl->generation; - -out: - dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", - __func__, tbl->used_slots[0], tbl->highest_used_slotid, - !IS_ERR(ret) ? ret->slot_nr : -1); - return ret; -} - static void nfs41_init_sequence(struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, int cache_reply) { @@ -5716,143 +5536,6 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) return status; } -static int nfs4_grow_slot_table(struct nfs4_slot_table *tbl, - u32 max_reqs, u32 ivalue) -{ - if (max_reqs <= tbl->max_slots) - return 0; - if (!IS_ERR(nfs4_find_or_create_slot(tbl, max_reqs - 1, ivalue, GFP_NOFS))) - return 0; - return -ENOMEM; -} - -static void nfs4_reset_slot_table(struct nfs4_slot_table *tbl, - u32 server_highest_slotid, - u32 ivalue) -{ - struct nfs4_slot **p; - - nfs4_shrink_slot_table(tbl, server_highest_slotid + 1); - p = &tbl->slots; - while (*p) { - (*p)->seq_nr = ivalue; - p = &(*p)->next; - } - tbl->highest_used_slotid = NFS4_NO_SLOT; - tbl->target_highest_slotid = server_highest_slotid; - tbl->server_highest_slotid = server_highest_slotid; - tbl->max_slotid = server_highest_slotid; -} - -/* - * (re)Initialise a slot table - */ -static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, - u32 max_reqs, u32 ivalue) -{ - int ret; - - dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, - max_reqs, tbl->max_slots); - - if (max_reqs > NFS4_MAX_SLOT_TABLE) - max_reqs = NFS4_MAX_SLOT_TABLE; - - ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue); - if (ret) - goto out; - - spin_lock(&tbl->slot_tbl_lock); - nfs4_reset_slot_table(tbl, max_reqs - 1, ivalue); - spin_unlock(&tbl->slot_tbl_lock); - - dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, - tbl, tbl->slots, tbl->max_slots); -out: - dprintk("<-- %s: return %d\n", __func__, ret); - return ret; -} - -/* Destroy the slot table */ -static void nfs4_destroy_slot_tables(struct nfs4_session *session) -{ - nfs4_shrink_slot_table(&session->fc_slot_table, 0); - nfs4_shrink_slot_table(&session->bc_slot_table, 0); -} - -/* - * Initialize or reset the forechannel and backchannel tables - */ -static int nfs4_setup_session_slot_tables(struct nfs4_session *ses) -{ - struct nfs4_slot_table *tbl; - int status; - - dprintk("--> %s\n", __func__); - /* Fore channel */ - tbl = &ses->fc_slot_table; - tbl->session = ses; - status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1); - if (status) /* -ENOMEM */ - return status; - /* Back channel */ - tbl = &ses->bc_slot_table; - tbl->session = ses; - status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0); - if (status && tbl->slots == NULL) - /* Fore and back channel share a connection so get - * both slot tables or neither */ - nfs4_destroy_slot_tables(ses); - return status; -} - -struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) -{ - struct nfs4_session *session; - struct nfs4_slot_table *tbl; - - session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS); - if (!session) - return NULL; - - tbl = &session->fc_slot_table; - tbl->highest_used_slotid = NFS4_NO_SLOT; - spin_lock_init(&tbl->slot_tbl_lock); - rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); - init_completion(&tbl->complete); - - tbl = &session->bc_slot_table; - tbl->highest_used_slotid = NFS4_NO_SLOT; - spin_lock_init(&tbl->slot_tbl_lock); - rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); - init_completion(&tbl->complete); - - session->session_state = 1<clp = clp; - return session; -} - -void nfs4_destroy_session(struct nfs4_session *session) -{ - struct rpc_xprt *xprt; - struct rpc_cred *cred; - - cred = nfs4_get_exchange_id_cred(session->clp); - nfs4_proc_destroy_session(session, cred); - if (cred) - put_rpccred(cred); - - rcu_read_lock(); - xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt); - rcu_read_unlock(); - dprintk("%s Destroy backchannel for xprt %p\n", - __func__, xprt); - xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS); - nfs4_destroy_slot_tables(session); - kfree(session); -} - /* * Initialize the values to be used by the client in CREATE_SESSION * If nfs4_init_session set the fore channel request and response sizes, @@ -6047,100 +5730,6 @@ int nfs4_proc_destroy_session(struct nfs4_session *session, } /* - * With sessions, the client is not marked ready until after a - * successful EXCHANGE_ID and CREATE_SESSION. - * - * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate - * other versions of NFS can be tried. - */ -static int nfs41_check_session_ready(struct nfs_client *clp) -{ - int ret; - - if (clp->cl_cons_state == NFS_CS_SESSION_INITING) { - ret = nfs4_client_recover_expired_lease(clp); - if (ret) - return ret; - } - if (clp->cl_cons_state < NFS_CS_READY) - return -EPROTONOSUPPORT; - smp_rmb(); - return 0; -} - -int nfs4_init_session(struct nfs_server *server) -{ - struct nfs_client *clp = server->nfs_client; - struct nfs4_session *session; - unsigned int target_max_rqst_sz = NFS_MAX_FILE_IO_SIZE; - unsigned int target_max_resp_sz = NFS_MAX_FILE_IO_SIZE; - - if (!nfs4_has_session(clp)) - return 0; - - if (server->rsize != 0) - target_max_resp_sz = server->rsize; - target_max_resp_sz += nfs41_maxread_overhead; - - if (server->wsize != 0) - target_max_rqst_sz = server->wsize; - target_max_rqst_sz += nfs41_maxwrite_overhead; - - session = clp->cl_session; - spin_lock(&clp->cl_lock); - if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) { - /* Initialise targets and channel attributes */ - session->fc_target_max_rqst_sz = target_max_rqst_sz; - session->fc_attrs.max_rqst_sz = target_max_rqst_sz; - session->fc_target_max_resp_sz = target_max_resp_sz; - session->fc_attrs.max_resp_sz = target_max_resp_sz; - } else { - /* Just adjust the targets */ - if (target_max_rqst_sz > session->fc_target_max_rqst_sz) { - session->fc_target_max_rqst_sz = target_max_rqst_sz; - set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); - } - if (target_max_resp_sz > session->fc_target_max_resp_sz) { - session->fc_target_max_resp_sz = target_max_resp_sz; - set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); - } - } - spin_unlock(&clp->cl_lock); - - if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) - nfs4_schedule_lease_recovery(clp); - - return nfs41_check_session_ready(clp); -} - -int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time) -{ - struct nfs4_session *session = clp->cl_session; - int ret; - - spin_lock(&clp->cl_lock); - if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) { - /* - * Do not set NFS_CS_CHECK_LEASE_TIME instead set the - * DS lease to be equal to the MDS lease. - */ - clp->cl_lease_time = lease_time; - clp->cl_last_renewal = jiffies; - } - spin_unlock(&clp->cl_lock); - - ret = nfs41_check_session_ready(clp); - if (ret) - return ret; - /* Test for the DS role */ - if (!is_ds_client(clp)) - return -ENODEV; - return 0; -} -EXPORT_SYMBOL_GPL(nfs4_init_ds_session); - - -/* * Renew the cl_session lease. */ struct nfs4_sequence_data { diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c new file mode 100644 index 0000000..7011702 --- /dev/null +++ b/fs/nfs/nfs4session.c @@ -0,0 +1,436 @@ +/* + * fs/nfs/nfs4session.c + * + * Copyright (c) 2012 Trond Myklebust + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfs4_fs.h" +#include "internal.h" +#include "nfs4session.h" +#include "callback.h" + +#define NFSDBG_FACILITY NFSDBG_STATE + +/* + * nfs4_shrink_slot_table - free retired slots from the slot table + */ +static void nfs4_shrink_slot_table(struct nfs4_slot_table *tbl, u32 newsize) +{ + struct nfs4_slot **p; + if (newsize >= tbl->max_slots) + return; + + p = &tbl->slots; + while (newsize--) + p = &(*p)->next; + while (*p) { + struct nfs4_slot *slot = *p; + + *p = slot->next; + kfree(slot); + tbl->max_slots--; + } +} + +/* + * nfs4_free_slot - free a slot and efficiently update slot table. + * + * freeing a slot is trivially done by clearing its respective bit + * in the bitmap. + * If the freed slotid equals highest_used_slotid we want to update it + * so that the server would be able to size down the slot table if needed, + * otherwise we know that the highest_used_slotid is still in use. + * When updating highest_used_slotid there may be "holes" in the bitmap + * so we need to scan down from highest_used_slotid to 0 looking for the now + * highest slotid in use. + * If none found, highest_used_slotid is set to NFS4_NO_SLOT. + * + * Must be called while holding tbl->slot_tbl_lock + */ +void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot) +{ + u32 slotid = slot->slot_nr; + + /* clear used bit in bitmap */ + __clear_bit(slotid, tbl->used_slots); + + /* update highest_used_slotid when it is freed */ + if (slotid == tbl->highest_used_slotid) { + u32 new_max = find_last_bit(tbl->used_slots, slotid); + if (new_max < slotid) + tbl->highest_used_slotid = new_max; + else { + tbl->highest_used_slotid = NFS4_NO_SLOT; + nfs4_session_drain_complete(tbl->session, tbl); + } + } + dprintk("%s: slotid %u highest_used_slotid %d\n", __func__, + slotid, tbl->highest_used_slotid); +} + +static struct nfs4_slot *nfs4_new_slot(struct nfs4_slot_table *tbl, + u32 slotid, u32 seq_init, gfp_t gfp_mask) +{ + struct nfs4_slot *slot; + + slot = kzalloc(sizeof(*slot), gfp_mask); + if (slot) { + slot->table = tbl; + slot->slot_nr = slotid; + slot->seq_nr = seq_init; + } + return slot; +} + +static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table *tbl, + u32 slotid, u32 seq_init, gfp_t gfp_mask) +{ + struct nfs4_slot **p, *slot; + + p = &tbl->slots; + for (;;) { + if (*p == NULL) { + *p = nfs4_new_slot(tbl, tbl->max_slots, + seq_init, gfp_mask); + if (*p == NULL) + break; + tbl->max_slots++; + } + slot = *p; + if (slot->slot_nr == slotid) + return slot; + p = &slot->next; + } + return ERR_PTR(-ENOMEM); +} + +/* + * nfs4_alloc_slot - efficiently look for a free slot + * + * nfs4_alloc_slot looks for an unset bit in the used_slots bitmap. + * If found, we mark the slot as used, update the highest_used_slotid, + * and respectively set up the sequence operation args. + * + * Note: must be called with under the slot_tbl_lock. + */ +struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl) +{ + struct nfs4_slot *ret = ERR_PTR(-EBUSY); + u32 slotid; + + dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n", + __func__, tbl->used_slots[0], tbl->highest_used_slotid, + tbl->max_slotid + 1); + slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1); + if (slotid > tbl->max_slotid) + goto out; + ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT); + if (IS_ERR(ret)) + goto out; + __set_bit(slotid, tbl->used_slots); + if (slotid > tbl->highest_used_slotid || + tbl->highest_used_slotid == NFS4_NO_SLOT) + tbl->highest_used_slotid = slotid; + ret->renewal_time = jiffies; + ret->generation = tbl->generation; + +out: + dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", + __func__, tbl->used_slots[0], tbl->highest_used_slotid, + !IS_ERR(ret) ? ret->slot_nr : -1); + return ret; +} + +static int nfs4_grow_slot_table(struct nfs4_slot_table *tbl, + u32 max_reqs, u32 ivalue) +{ + if (max_reqs <= tbl->max_slots) + return 0; + if (!IS_ERR(nfs4_find_or_create_slot(tbl, max_reqs - 1, ivalue, GFP_NOFS))) + return 0; + return -ENOMEM; +} + +static void nfs4_reset_slot_table(struct nfs4_slot_table *tbl, + u32 server_highest_slotid, + u32 ivalue) +{ + struct nfs4_slot **p; + + nfs4_shrink_slot_table(tbl, server_highest_slotid + 1); + p = &tbl->slots; + while (*p) { + (*p)->seq_nr = ivalue; + p = &(*p)->next; + } + tbl->highest_used_slotid = NFS4_NO_SLOT; + tbl->target_highest_slotid = server_highest_slotid; + tbl->server_highest_slotid = server_highest_slotid; + tbl->max_slotid = server_highest_slotid; +} + +/* + * (re)Initialise a slot table + */ +static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, + u32 max_reqs, u32 ivalue) +{ + int ret; + + dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, + max_reqs, tbl->max_slots); + + if (max_reqs > NFS4_MAX_SLOT_TABLE) + max_reqs = NFS4_MAX_SLOT_TABLE; + + ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue); + if (ret) + goto out; + + spin_lock(&tbl->slot_tbl_lock); + nfs4_reset_slot_table(tbl, max_reqs - 1, ivalue); + spin_unlock(&tbl->slot_tbl_lock); + + dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, + tbl, tbl->slots, tbl->max_slots); +out: + dprintk("<-- %s: return %d\n", __func__, ret); + return ret; +} + +/* Destroy the slot table */ +static void nfs4_destroy_slot_tables(struct nfs4_session *session) +{ + nfs4_shrink_slot_table(&session->fc_slot_table, 0); + nfs4_shrink_slot_table(&session->bc_slot_table, 0); +} + +/* Update the client's idea of target_highest_slotid */ +static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, + u32 target_highest_slotid) +{ + unsigned int max_slotid, i; + + if (tbl->target_highest_slotid == target_highest_slotid) + return; + tbl->target_highest_slotid = target_highest_slotid; + tbl->generation++; + + max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid); + for (i = tbl->max_slotid + 1; i <= max_slotid; i++) + rpc_wake_up_next(&tbl->slot_tbl_waitq); + tbl->max_slotid = max_slotid; +} + +void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, + u32 target_highest_slotid) +{ + spin_lock(&tbl->slot_tbl_lock); + nfs41_set_target_slotid_locked(tbl, target_highest_slotid); + spin_unlock(&tbl->slot_tbl_lock); +} + +static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, + u32 highest_slotid) +{ + if (tbl->server_highest_slotid == highest_slotid) + return; + if (tbl->highest_used_slotid > highest_slotid) + return; + /* Deallocate slots */ + nfs4_shrink_slot_table(tbl, highest_slotid + 1); + tbl->server_highest_slotid = highest_slotid; +} + +void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, + struct nfs4_slot *slot, + struct nfs4_sequence_res *res) +{ + spin_lock(&tbl->slot_tbl_lock); + if (tbl->generation != slot->generation) + goto out; + nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid); + nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); +out: + spin_unlock(&tbl->slot_tbl_lock); +} + +/* + * Initialize or reset the forechannel and backchannel tables + */ +int nfs4_setup_session_slot_tables(struct nfs4_session *ses) +{ + struct nfs4_slot_table *tbl; + int status; + + dprintk("--> %s\n", __func__); + /* Fore channel */ + tbl = &ses->fc_slot_table; + tbl->session = ses; + status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1); + if (status) /* -ENOMEM */ + return status; + /* Back channel */ + tbl = &ses->bc_slot_table; + tbl->session = ses; + status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0); + if (status && tbl->slots == NULL) + /* Fore and back channel share a connection so get + * both slot tables or neither */ + nfs4_destroy_slot_tables(ses); + return status; +} + +struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) +{ + struct nfs4_session *session; + struct nfs4_slot_table *tbl; + + session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS); + if (!session) + return NULL; + + tbl = &session->fc_slot_table; + tbl->highest_used_slotid = NFS4_NO_SLOT; + spin_lock_init(&tbl->slot_tbl_lock); + rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); + init_completion(&tbl->complete); + + tbl = &session->bc_slot_table; + tbl->highest_used_slotid = NFS4_NO_SLOT; + spin_lock_init(&tbl->slot_tbl_lock); + rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); + init_completion(&tbl->complete); + + session->session_state = 1<clp = clp; + return session; +} + +void nfs4_destroy_session(struct nfs4_session *session) +{ + struct rpc_xprt *xprt; + struct rpc_cred *cred; + + cred = nfs4_get_exchange_id_cred(session->clp); + nfs4_proc_destroy_session(session, cred); + if (cred) + put_rpccred(cred); + + rcu_read_lock(); + xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt); + rcu_read_unlock(); + dprintk("%s Destroy backchannel for xprt %p\n", + __func__, xprt); + xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS); + nfs4_destroy_slot_tables(session); + kfree(session); +} + +/* + * With sessions, the client is not marked ready until after a + * successful EXCHANGE_ID and CREATE_SESSION. + * + * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate + * other versions of NFS can be tried. + */ +static int nfs41_check_session_ready(struct nfs_client *clp) +{ + int ret; + + if (clp->cl_cons_state == NFS_CS_SESSION_INITING) { + ret = nfs4_client_recover_expired_lease(clp); + if (ret) + return ret; + } + if (clp->cl_cons_state < NFS_CS_READY) + return -EPROTONOSUPPORT; + smp_rmb(); + return 0; +} + +int nfs4_init_session(struct nfs_server *server) +{ + struct nfs_client *clp = server->nfs_client; + struct nfs4_session *session; + unsigned int target_max_rqst_sz = NFS_MAX_FILE_IO_SIZE; + unsigned int target_max_resp_sz = NFS_MAX_FILE_IO_SIZE; + + if (!nfs4_has_session(clp)) + return 0; + + if (server->rsize != 0) + target_max_resp_sz = server->rsize; + target_max_resp_sz += nfs41_maxread_overhead; + + if (server->wsize != 0) + target_max_rqst_sz = server->wsize; + target_max_rqst_sz += nfs41_maxwrite_overhead; + + session = clp->cl_session; + spin_lock(&clp->cl_lock); + if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) { + /* Initialise targets and channel attributes */ + session->fc_target_max_rqst_sz = target_max_rqst_sz; + session->fc_attrs.max_rqst_sz = target_max_rqst_sz; + session->fc_target_max_resp_sz = target_max_resp_sz; + session->fc_attrs.max_resp_sz = target_max_resp_sz; + } else { + /* Just adjust the targets */ + if (target_max_rqst_sz > session->fc_target_max_rqst_sz) { + session->fc_target_max_rqst_sz = target_max_rqst_sz; + set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); + } + if (target_max_resp_sz > session->fc_target_max_resp_sz) { + session->fc_target_max_resp_sz = target_max_resp_sz; + set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); + } + } + spin_unlock(&clp->cl_lock); + + if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) + nfs4_schedule_lease_recovery(clp); + + return nfs41_check_session_ready(clp); +} + +int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time) +{ + struct nfs4_session *session = clp->cl_session; + int ret; + + spin_lock(&clp->cl_lock); + if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) { + /* + * Do not set NFS_CS_CHECK_LEASE_TIME instead set the + * DS lease to be equal to the MDS lease. + */ + clp->cl_lease_time = lease_time; + clp->cl_last_renewal = jiffies; + } + spin_unlock(&clp->cl_lock); + + ret = nfs41_check_session_ready(clp); + if (ret) + return ret; + /* Test for the DS role */ + if (!is_ds_client(clp)) + return -ENODEV; + return 0; +} +EXPORT_SYMBOL_GPL(nfs4_init_ds_session); + + diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h new file mode 100644 index 0000000..cb47b1e --- /dev/null +++ b/fs/nfs/nfs4session.h @@ -0,0 +1,35 @@ +/* + * fs/nfs/nfs4session.h + * + * Copyright (c) 2012 Trond Myklebust + * + */ +#ifndef __LINUX_FS_NFS_NFS4SESSION_H +#define __LINUX_FS_NFS_NFS4SESSION_H + +#if defined(CONFIG_NFS_V4_1) +extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); +extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); + +extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, + u32 target_highest_slotid); +extern void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, + struct nfs4_slot *slot, + struct nfs4_sequence_res *res); + +extern int nfs4_setup_session_slot_tables(struct nfs4_session *ses); + +extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); +extern void nfs4_destroy_session(struct nfs4_session *session); +extern int nfs4_init_session(struct nfs_server *server); +extern int nfs4_init_ds_session(struct nfs_client *, unsigned long); + +#else /* defined(CONFIG_NFS_V4_1) */ + +static inline int nfs4_init_session(struct nfs_server *server) +{ + return 0; +} + +#endif /* defined(CONFIG_NFS_V4_1) */ +#endif /* __LINUX_FS_NFS_NFS4SESSION_H */ -- cgit v0.10.2 From c34309a45ea491e5f0c0d0af49ccfa018ff35fc1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 26 Nov 2012 14:33:03 -0500 Subject: NFS: Remove unused function slot_idx Signed-off-by: Trond Myklebust diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 3071550..e707c1b 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -225,11 +225,6 @@ struct nfs4_slot_table { struct completion complete; }; -static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp) -{ - return sp - tbl->slots; -} - /* * Session related parameters */ -- cgit v0.10.2 From 76e697ba7e8d187f50e385d21a2b2f1709a62c14 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 26 Nov 2012 14:20:49 -0500 Subject: NFSv4.1: Move slot table and session struct definitions to nfs4session.h Clean up. Gather NFSv4.1 slot definitions in fs/nfs/nfs4session.h. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index f1027b0..4fa788c 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -40,6 +40,7 @@ #include #include "../pnfs.h" +#include "../nfs4session.h" #include "../internal.h" #include "blocklayout.h" diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index ea6a7b1..59461c9 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -16,6 +16,7 @@ #include "nfs4_fs.h" #include "callback.h" #include "internal.h" +#include "nfs4session.h" #define CB_OP_TAGLEN_MAXSZ (512) #define CB_OP_HDR_RES_MAXSZ (2 + CB_OP_TAGLEN_MAXSZ) diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 8965a99..9bdbfc3 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -18,27 +18,6 @@ struct nfs_string; */ #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) -/* - * Determine if sessions are in use. - */ -static inline int nfs4_has_session(const struct nfs_client *clp) -{ -#ifdef CONFIG_NFS_V4_1 - if (clp->cl_session) - return 1; -#endif /* CONFIG_NFS_V4_1 */ - return 0; -} - -static inline int nfs4_has_persistent_session(const struct nfs_client *clp) -{ -#ifdef CONFIG_NFS_V4_1 - if (nfs4_has_session(clp)) - return (clp->cl_session->flags & SESSION4_PERSIST); -#endif /* CONFIG_NFS_V4_1 */ - return 0; -} - static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct nfs_fattr *fattr) { if (!nfs_fsid_equal(&NFS_SB(parent)->fsid, &fattr->fsid)) diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index cd3e309..322bd01 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -29,11 +29,6 @@ enum nfs4_client_state { NFS4CLNT_BIND_CONN_TO_SESSION, }; -enum nfs4_session_state { - NFS4_SESSION_INITING, - NFS4_SESSION_DRAINING, -}; - #define NFS4_RENEW_TIMEOUT 0x01 #define NFS4_RENEW_DELEGATION_CB 0x02 @@ -327,13 +322,6 @@ int nfs41_discover_server_trunking(struct nfs_client *clp, extern void nfs4_schedule_session_recovery(struct nfs4_session *, int); extern void nfs41_server_notify_target_slotid_update(struct nfs_client *clp); -extern void nfs4_session_drain_complete(struct nfs4_session *session, - struct nfs4_slot_table *tbl); - -static inline bool nfs4_session_draining(struct nfs4_session *session) -{ - return !!test_bit(NFS4_SESSION_DRAINING, &session->session_state); -} #else static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err) { diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index bfb28fa..591a1a7 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -35,6 +35,7 @@ #include +#include "nfs4session.h" #include "internal.h" #include "delegation.h" #include "nfs4filelayout.h" diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index cb47b1e..e96323f 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h @@ -7,6 +7,68 @@ #ifndef __LINUX_FS_NFS_NFS4SESSION_H #define __LINUX_FS_NFS_NFS4SESSION_H +/* maximum number of slots to use */ +#define NFS4_DEF_SLOT_TABLE_SIZE (16U) +#define NFS4_MAX_SLOT_TABLE (256U) +#define NFS4_NO_SLOT ((u32)-1) + +#if IS_ENABLED(CONFIG_NFS_V4) + +/* Sessions slot seqid */ +struct nfs4_slot { + struct nfs4_slot_table *table; + struct nfs4_slot *next; + unsigned long generation; + unsigned long renewal_time; + u32 slot_nr; + u32 seq_nr; +}; + +/* Sessions */ +#define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long)) +struct nfs4_slot_table { + struct nfs4_session *session; /* Parent session */ + struct nfs4_slot *slots; /* seqid per slot */ + unsigned long used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */ + spinlock_t slot_tbl_lock; + struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */ + u32 max_slots; /* # slots in table */ + u32 max_slotid; /* Max allowed slotid value */ + u32 highest_used_slotid; /* sent to server on each SEQ. + * op for dynamic resizing */ + u32 target_highest_slotid; /* Server max_slot target */ + u32 server_highest_slotid; /* Server highest slotid */ + unsigned long generation; /* Generation counter for + target_highest_slotid */ + struct completion complete; +}; + +/* + * Session related parameters + */ +struct nfs4_session { + struct nfs4_sessionid sess_id; + u32 flags; + unsigned long session_state; + u32 hash_alg; + u32 ssv_len; + + /* The fore and back channel */ + struct nfs4_channel_attrs fc_attrs; + struct nfs4_slot_table fc_slot_table; + struct nfs4_channel_attrs bc_attrs; + struct nfs4_slot_table bc_slot_table; + struct nfs_client *clp; + /* Create session arguments */ + unsigned int fc_target_max_rqst_sz; + unsigned int fc_target_max_resp_sz; +}; + +enum nfs4_session_state { + NFS4_SESSION_INITING, + NFS4_SESSION_DRAINING, +}; + #if defined(CONFIG_NFS_V4_1) extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); @@ -24,6 +86,31 @@ extern void nfs4_destroy_session(struct nfs4_session *session); extern int nfs4_init_session(struct nfs_server *server); extern int nfs4_init_ds_session(struct nfs_client *, unsigned long); +extern void nfs4_session_drain_complete(struct nfs4_session *session, + struct nfs4_slot_table *tbl); + +static inline bool nfs4_session_draining(struct nfs4_session *session) +{ + return !!test_bit(NFS4_SESSION_DRAINING, &session->session_state); +} + +/* + * Determine if sessions are in use. + */ +static inline int nfs4_has_session(const struct nfs_client *clp) +{ + if (clp->cl_session) + return 1; + return 0; +} + +static inline int nfs4_has_persistent_session(const struct nfs_client *clp) +{ + if (nfs4_has_session(clp)) + return (clp->cl_session->flags & SESSION4_PERSIST); + return 0; +} + #else /* defined(CONFIG_NFS_V4_1) */ static inline int nfs4_init_session(struct nfs_server *server) @@ -31,5 +118,19 @@ static inline int nfs4_init_session(struct nfs_server *server) return 0; } +/* + * Determine if sessions are in use. + */ +static inline int nfs4_has_session(const struct nfs_client *clp) +{ + return 0; +} + +static inline int nfs4_has_persistent_session(const struct nfs_client *clp) +{ + return 0; +} + #endif /* defined(CONFIG_NFS_V4_1) */ +#endif /* IS_ENABLED(CONFIG_NFS_V4) */ #endif /* __LINUX_FS_NFS_NFS4SESSION_H */ diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 1077b96..1402283 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -57,6 +57,7 @@ #include "callback.h" #include "delegation.h" #include "internal.h" +#include "nfs4session.h" #include "pnfs.h" #include "netns.h" diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index a67040f..e786dc7 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -56,6 +56,7 @@ #include "nfs4_fs.h" #include "internal.h" +#include "nfs4session.h" #include "pnfs.h" #include "netns.h" diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 652d3f7..e12cea4 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -64,6 +64,7 @@ #include "iostat.h" #include "internal.h" #include "fscache.h" +#include "nfs4session.h" #include "pnfs.h" #include "nfs.h" diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index e707c1b..6c6ed15 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -198,53 +198,4 @@ struct nfs_server { #define NFS_CAP_POSIX_LOCK (1U << 14) #define NFS_CAP_UIDGID_NOMAP (1U << 15) - -/* maximum number of slots to use */ -#define NFS4_DEF_SLOT_TABLE_SIZE (16U) -#define NFS4_MAX_SLOT_TABLE (256U) -#define NFS4_NO_SLOT ((u32)-1) - -#if IS_ENABLED(CONFIG_NFS_V4) - -/* Sessions */ -#define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long)) -struct nfs4_slot_table { - struct nfs4_session *session; /* Parent session */ - struct nfs4_slot *slots; /* seqid per slot */ - unsigned long used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */ - spinlock_t slot_tbl_lock; - struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */ - u32 max_slots; /* # slots in table */ - u32 max_slotid; /* Max allowed slotid value */ - u32 highest_used_slotid; /* sent to server on each SEQ. - * op for dynamic resizing */ - u32 target_highest_slotid; /* Server max_slot target */ - u32 server_highest_slotid; /* Server highest slotid */ - unsigned long generation; /* Generation counter for - target_highest_slotid */ - struct completion complete; -}; - -/* - * Session related parameters - */ -struct nfs4_session { - struct nfs4_sessionid sess_id; - u32 flags; - unsigned long session_state; - u32 hash_alg; - u32 ssv_len; - - /* The fore and back channel */ - struct nfs4_channel_attrs fc_attrs; - struct nfs4_slot_table fc_slot_table; - struct nfs4_channel_attrs bc_attrs; - struct nfs4_slot_table bc_slot_table; - struct nfs_client *clp; - /* Create session arguments */ - unsigned int fc_target_max_rqst_sz; - unsigned int fc_target_max_resp_sz; -}; - -#endif /* CONFIG_NFS_V4 */ #endif diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 44d256f..2076149 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -185,16 +185,7 @@ struct nfs4_channel_attrs { u32 max_reqs; }; -/* nfs41 sessions slot seqid */ -struct nfs4_slot { - struct nfs4_slot_table *table; - struct nfs4_slot *next; - unsigned long generation; - unsigned long renewal_time; - u32 slot_nr; - u32 seq_nr; -}; - +struct nfs4_slot; struct nfs4_sequence_args { struct nfs4_slot *sa_slot; u8 sa_cache_this; -- cgit v0.10.2 From 0ca3f4825ac92a10aa8f6534f765c44f22778dd3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 21 Nov 2012 22:34:45 -0500 Subject: NFSv4.1: Set the maximum slot table size to 1024 slots This means that we end up statically allocating 128 bytes for the bitmap on each slot table. For a server that supports 1MB write and read I/O sizes this means that we can completely fill the maximum 1GB TCP send/receive windows. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index e96323f..bdd14a6 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h @@ -9,7 +9,7 @@ /* maximum number of slots to use */ #define NFS4_DEF_SLOT_TABLE_SIZE (16U) -#define NFS4_MAX_SLOT_TABLE (256U) +#define NFS4_MAX_SLOT_TABLE (1024U) #define NFS4_NO_SLOT ((u32)-1) #if IS_ENABLED(CONFIG_NFS_V4) -- cgit v0.10.2 From c10e449827e6008ef5a4a71c0247c7eb73948e1b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 26 Nov 2012 16:16:54 -0500 Subject: NFSv4.1: Ping server when our session table limits are too high If the server requests a lower target_highest_slotid, then ensure that we ping it with at least one RPC call containing an appropriate SEQUENCE op. This ensures that the server won't need to send a recall callback in order to shrink the slot table. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 322bd01..8fe155b 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -321,6 +321,7 @@ int nfs41_discover_server_trunking(struct nfs_client *clp, struct nfs_client **, struct rpc_cred *); extern void nfs4_schedule_session_recovery(struct nfs4_session *, int); extern void nfs41_server_notify_target_slotid_update(struct nfs_client *clp); +extern void nfs41_server_notify_highest_slotid_update(struct nfs_client *clp); #else static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a0c35ab..ecd4ed3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -389,6 +389,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) { struct nfs4_session *session; struct nfs4_slot_table *tbl; + bool send_new_highest_used_slotid = false; if (!res->sr_slot) { /* just wake up the next guy waiting since @@ -400,12 +401,25 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) session = tbl->session; spin_lock(&tbl->slot_tbl_lock); + /* Be nice to the server: try to ensure that the last transmitted + * value for highest_user_slotid <= target_highest_slotid + */ + if (tbl->highest_used_slotid > tbl->target_highest_slotid) + send_new_highest_used_slotid = true; + nfs4_free_slot(tbl, res->sr_slot); - if (!nfs4_session_draining(session)) - rpc_wake_up_first(&tbl->slot_tbl_waitq, - nfs4_set_task_privileged, NULL); + + if (tbl->highest_used_slotid != NFS4_NO_SLOT) + send_new_highest_used_slotid = false; + if (!nfs4_session_draining(session)) { + if (rpc_wake_up_first(&tbl->slot_tbl_waitq, + nfs4_set_task_privileged, NULL) != NULL) + send_new_highest_used_slotid = false; + } spin_unlock(&tbl->slot_tbl_lock); res->sr_slot = NULL; + if (send_new_highest_used_slotid) + nfs41_server_notify_highest_slotid_update(session->clp); } static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 1402283..c137421 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1961,6 +1961,11 @@ void nfs41_server_notify_target_slotid_update(struct nfs_client *clp) nfs41_ping_server(clp); } +void nfs41_server_notify_highest_slotid_update(struct nfs_client *clp) +{ + nfs41_ping_server(clp); +} + static void nfs4_reset_all_state(struct nfs_client *clp) { if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { -- cgit v0.10.2 From 6ba7db3420c0dbf3ede16f19a593e6a80edc043f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 22 Oct 2012 20:07:20 -0400 Subject: NFSv4.1: Use nfs41_setup_sequence where appropriate There is no point in using nfs4_setup_sequence or nfs4_sequence_done in pure NFSv4.1 functions. We already know that those have sessions... Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ecd4ed3..39d2415 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -597,10 +597,11 @@ struct nfs41_call_sync_data { static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) { struct nfs41_call_sync_data *data = calldata; + struct nfs4_session *session = nfs4_get_session(data->seq_server); dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server); - if (nfs4_setup_sequence(data->seq_server, data->seq_args, + if (nfs41_setup_sequence(session, data->seq_args, data->seq_res, task)) return; rpc_call_start(task); @@ -6018,6 +6019,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata) { struct nfs4_layoutget *lgp = calldata; struct nfs_server *server = NFS_SERVER(lgp->args.inode); + struct nfs4_session *session = nfs4_get_session(server); dprintk("--> %s\n", __func__); /* Note the is a race here, where a CB_LAYOUTRECALL can come in @@ -6025,7 +6027,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata) * However, that is not so catastrophic, and there seems * to be no way to prevent it completely. */ - if (nfs4_setup_sequence(server, &lgp->args.seq_args, + if (nfs41_setup_sequence(session, &lgp->args.seq_args, &lgp->res.seq_res, task)) return; if (pnfs_choose_layoutget_stateid(&lgp->args.stateid, @@ -6047,7 +6049,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) dprintk("--> %s\n", __func__); - if (!nfs4_sequence_done(task, &lgp->res.seq_res)) + if (!nfs41_sequence_done(task, &lgp->res.seq_res)) goto out; switch (task->tk_status) { @@ -6211,7 +6213,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) dprintk("--> %s\n", __func__); - if (!nfs4_sequence_done(task, &lrp->res.seq_res)) + if (!nfs41_sequence_done(task, &lrp->res.seq_res)) return; server = NFS_SERVER(lrp->args.inode); @@ -6360,8 +6362,9 @@ static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata) { struct nfs4_layoutcommit_data *data = calldata; struct nfs_server *server = NFS_SERVER(data->args.inode); + struct nfs4_session *session = nfs4_get_session(server); - if (nfs4_setup_sequence(server, &data->args.seq_args, + if (nfs41_setup_sequence(session, &data->args.seq_args, &data->res.seq_res, task)) return; rpc_call_start(task); @@ -6373,7 +6376,7 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) struct nfs4_layoutcommit_data *data = calldata; struct nfs_server *server = NFS_SERVER(data->args.inode); - if (!nfs4_sequence_done(task, &data->res.seq_res)) + if (!nfs41_sequence_done(task, &data->res.seq_res)) return; switch (task->tk_status) { /* Just ignore these failures */ -- cgit v0.10.2 From d9afbd1b0889e7da6742e9c67ccc7becc4161f65 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 22 Oct 2012 20:28:44 -0400 Subject: NFSv4.1: Simplify the sequence setup Nobody calls nfs4_setup_sequence or nfs41_setup_sequence without also calling rpc_call_start() on success. This commit therefore folds the rpc_call_start call into nfs41_setup_sequence(). Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 8fe155b..8022ade 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -273,6 +273,7 @@ static inline int nfs4_setup_sequence(const struct nfs_server *server, struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, struct rpc_task *task) { + rpc_call_start(task); return 0; } diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 591a1a7..1e42413 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -307,12 +307,10 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data) } rdata->read_done_cb = filelayout_read_done_cb; - if (nfs41_setup_sequence(rdata->ds_clp->cl_session, - &rdata->args.seq_args, &rdata->res.seq_res, - task)) - return; - - rpc_call_start(task); + nfs41_setup_sequence(rdata->ds_clp->cl_session, + &rdata->args.seq_args, + &rdata->res.seq_res, + task); } static void filelayout_read_call_done(struct rpc_task *task, void *data) @@ -409,12 +407,10 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data) rpc_exit(task, 0); return; } - if (nfs41_setup_sequence(wdata->ds_clp->cl_session, - &wdata->args.seq_args, &wdata->res.seq_res, - task)) - return; - - rpc_call_start(task); + nfs41_setup_sequence(wdata->ds_clp->cl_session, + &wdata->args.seq_args, + &wdata->res.seq_res, + task); } static void filelayout_write_call_done(struct rpc_task *task, void *data) @@ -450,12 +446,10 @@ static void filelayout_commit_prepare(struct rpc_task *task, void *data) { struct nfs_commit_data *wdata = data; - if (nfs41_setup_sequence(wdata->ds_clp->cl_session, - &wdata->args.seq_args, &wdata->res.seq_res, - task)) - return; - - rpc_call_start(task); + nfs41_setup_sequence(wdata->ds_clp->cl_session, + &wdata->args.seq_args, + &wdata->res.seq_res, + task); } static void filelayout_write_commit_done(struct rpc_task *task, void *data) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 39d2415..23b0c2f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -513,7 +513,7 @@ int nfs41_setup_sequence(struct nfs4_session *session, dprintk("--> %s\n", __func__); /* slot already allocated? */ if (res->sr_slot != NULL) - return 0; + goto out_success; tbl = &session->fc_slot_table; @@ -563,6 +563,8 @@ int nfs41_setup_sequence(struct nfs4_session *session, * set to 1 if an rpc level failure occurs. */ res->sr_status = 1; +out_success: + rpc_call_start(task); return 0; } EXPORT_SYMBOL_GPL(nfs41_setup_sequence); @@ -575,8 +577,10 @@ int nfs4_setup_sequence(const struct nfs_server *server, struct nfs4_session *session = nfs4_get_session(server); int ret = 0; - if (session == NULL) + if (session == NULL) { + rpc_call_start(task); goto out; + } dprintk("--> %s clp %p session %p sr_slot %d\n", __func__, session->clp, session, res->sr_slot ? @@ -601,10 +605,7 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server); - if (nfs41_setup_sequence(session, data->seq_args, - data->seq_res, task)) - return; - rpc_call_start(task); + nfs41_setup_sequence(session, data->seq_args, data->seq_res, task); } static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata) @@ -1485,8 +1486,6 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) &data->o_res.seq_res, task) != 0) nfs_release_seqid(data->o_arg.seqid); - else - rpc_call_start(task); return; unlock_no_action: rcu_read_unlock(); @@ -2192,8 +2191,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) &calldata->res.seq_res, task) != 0) nfs_release_seqid(calldata->arg.seqid); - else - rpc_call_start(task); out: dprintk("%s: done!\n", __func__); } @@ -2932,12 +2929,10 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data) { - if (nfs4_setup_sequence(NFS_SERVER(data->dir), - &data->args.seq_args, - &data->res.seq_res, - task)) - return; - rpc_call_start(task); + nfs4_setup_sequence(NFS_SERVER(data->dir), + &data->args.seq_args, + &data->res.seq_res, + task); } static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) @@ -2965,12 +2960,10 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir) static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data) { - if (nfs4_setup_sequence(NFS_SERVER(data->old_dir), - &data->args.seq_args, - &data->res.seq_res, - task)) - return; - rpc_call_start(task); + nfs4_setup_sequence(NFS_SERVER(data->old_dir), + &data->args.seq_args, + &data->res.seq_res, + task); } static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir, @@ -3459,12 +3452,10 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data) { - if (nfs4_setup_sequence(NFS_SERVER(data->header->inode), - &data->args.seq_args, - &data->res.seq_res, - task)) - return; - rpc_call_start(task); + nfs4_setup_sequence(NFS_SERVER(data->header->inode), + &data->args.seq_args, + &data->res.seq_res, + task); } static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data) @@ -3525,22 +3516,18 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data) { - if (nfs4_setup_sequence(NFS_SERVER(data->header->inode), - &data->args.seq_args, - &data->res.seq_res, - task)) - return; - rpc_call_start(task); + nfs4_setup_sequence(NFS_SERVER(data->header->inode), + &data->args.seq_args, + &data->res.seq_res, + task); } static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data) { - if (nfs4_setup_sequence(NFS_SERVER(data->inode), - &data->args.seq_args, - &data->res.seq_res, - task)) - return; - rpc_call_start(task); + nfs4_setup_sequence(NFS_SERVER(data->inode), + &data->args.seq_args, + &data->res.seq_res, + task); } static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_commit_data *data) @@ -4187,11 +4174,10 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) d_data = (struct nfs4_delegreturndata *)data; - if (nfs4_setup_sequence(d_data->res.server, - &d_data->args.seq_args, - &d_data->res.seq_res, task)) - return; - rpc_call_start(task); + nfs4_setup_sequence(d_data->res.server, + &d_data->args.seq_args, + &d_data->res.seq_res, + task); } #endif /* CONFIG_NFS_V4_1 */ @@ -4445,8 +4431,6 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) &calldata->res.seq_res, task) != 0) nfs_release_seqid(calldata->arg.seqid); - else - rpc_call_start(task); } static const struct rpc_call_ops nfs4_locku_ops = { @@ -4601,10 +4585,8 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) if (nfs4_setup_sequence(data->server, &data->arg.seq_args, &data->res.seq_res, - task) == 0) { - rpc_call_start(task); + task) == 0) return; - } nfs_release_seqid(data->arg.open_seqid); out_release_lock_seqid: nfs_release_seqid(data->arg.lock_seqid); @@ -5462,7 +5444,6 @@ struct nfs4_get_lease_time_data { static void nfs4_get_lease_time_prepare(struct rpc_task *task, void *calldata) { - int ret; struct nfs4_get_lease_time_data *data = (struct nfs4_get_lease_time_data *)calldata; @@ -5470,12 +5451,10 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task, rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); /* just setup sequence, do not trigger session recovery since we're invoked within one */ - ret = nfs41_setup_sequence(data->clp->cl_session, - &data->args->la_seq_args, - &data->res->lr_seq_res, task); - - if (ret != -EAGAIN) - rpc_call_start(task); + nfs41_setup_sequence(data->clp->cl_session, + &data->args->la_seq_args, + &data->res->lr_seq_res, + task); dprintk("<-- %s\n", __func__); } @@ -5809,9 +5788,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data) args = task->tk_msg.rpc_argp; res = task->tk_msg.rpc_resp; - if (nfs41_setup_sequence(clp->cl_session, args, res, task)) - return; - rpc_call_start(task); + nfs41_setup_sequence(clp->cl_session, args, res, task); } static void nfs41_sequence_prepare_privileged(struct rpc_task *task, void *data) @@ -5914,12 +5891,10 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data) struct nfs4_reclaim_complete_data *calldata = data; rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); - if (nfs41_setup_sequence(calldata->clp->cl_session, - &calldata->arg.seq_args, - &calldata->res.seq_res, task)) - return; - - rpc_call_start(task); + nfs41_setup_sequence(calldata->clp->cl_session, + &calldata->arg.seq_args, + &calldata->res.seq_res, + task); } static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp) @@ -6034,9 +6009,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata) NFS_I(lgp->args.inode)->layout, lgp->args.ctx->state)) { rpc_exit(task, NFS4_OK); - return; } - rpc_call_start(task); } static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) @@ -6200,10 +6173,10 @@ nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata) struct nfs4_layoutreturn *lrp = calldata; dprintk("--> %s\n", __func__); - if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args, - &lrp->res.seq_res, task)) - return; - rpc_call_start(task); + nfs41_setup_sequence(lrp->clp->cl_session, + &lrp->args.seq_args, + &lrp->res.seq_res, + task); } static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) @@ -6364,10 +6337,10 @@ static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata) struct nfs_server *server = NFS_SERVER(data->args.inode); struct nfs4_session *session = nfs4_get_session(server); - if (nfs41_setup_sequence(session, &data->args.seq_args, - &data->res.seq_res, task)) - return; - rpc_call_start(task); + nfs41_setup_sequence(session, + &data->args.seq_args, + &data->res.seq_res, + task); } static void -- cgit v0.10.2 From fd0c09537a8494e9dccf3856b90058e1f97f1d62 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 1 Nov 2012 14:43:38 -0400 Subject: NFSv4: Simplify the NFSv4/v4.1 synchronous call switch We shouldn't need to pass the 'cache_reply' parameter if we initialise the sequence_args/sequence_res in the caller. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 9bdbfc3..fb99447 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -451,18 +451,6 @@ extern struct nfs_client *nfs4_init_client(struct nfs_client *clp, const struct rpc_timeout *timeparms, const char *ip_addr, rpc_authflavor_t authflavour); -extern int _nfs4_call_sync(struct rpc_clnt *clnt, - struct nfs_server *server, - struct rpc_message *msg, - struct nfs4_sequence_args *args, - struct nfs4_sequence_res *res, - int cache_reply); -extern int _nfs4_call_sync_session(struct rpc_clnt *clnt, - struct nfs_server *server, - struct rpc_message *msg, - struct nfs4_sequence_args *args, - struct nfs4_sequence_res *res, - int cache_reply); extern int nfs40_walk_client_list(struct nfs_client *clp, struct nfs_client **result, struct rpc_cred *cred); diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 8022ade..4f0cdc1 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -39,8 +39,7 @@ struct nfs4_minor_version_ops { struct nfs_server *server, struct rpc_message *msg, struct nfs4_sequence_args *args, - struct nfs4_sequence_res *res, - int cache_reply); + struct nfs4_sequence_res *res); bool (*match_stateid)(const nfs4_stateid *, const nfs4_stateid *); int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 23b0c2f..4aaaa3b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -664,14 +664,13 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, return ret; } +static int _nfs4_call_sync_session(struct rpc_clnt *clnt, struct nfs_server *server, struct rpc_message *msg, struct nfs4_sequence_args *args, - struct nfs4_sequence_res *res, - int cache_reply) + struct nfs4_sequence_res *res) { - nfs41_init_sequence(args, res, cache_reply); return nfs4_call_sync_sequence(clnt, server, msg, args, res, 0); } @@ -689,18 +688,17 @@ static int nfs4_sequence_done(struct rpc_task *task, } #endif /* CONFIG_NFS_V4_1 */ +static int _nfs4_call_sync(struct rpc_clnt *clnt, struct nfs_server *server, struct rpc_message *msg, struct nfs4_sequence_args *args, - struct nfs4_sequence_res *res, - int cache_reply) + struct nfs4_sequence_res *res) { - nfs41_init_sequence(args, res, cache_reply); return rpc_call_sync(clnt, msg, 0); } -static inline +static int nfs4_call_sync(struct rpc_clnt *clnt, struct nfs_server *server, struct rpc_message *msg, @@ -708,8 +706,9 @@ int nfs4_call_sync(struct rpc_clnt *clnt, struct nfs4_sequence_res *res, int cache_reply) { + nfs41_init_sequence(args, res, cache_reply); return server->nfs_client->cl_mvops->call_sync(clnt, server, msg, - args, res, cache_reply); + args, res); } static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) -- cgit v0.10.2 From 7b939a3f44293516c4225f640e8c4b9200beeabc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 1 Nov 2012 15:19:46 -0400 Subject: NFSv4.1: Clean up nfs41_setup_sequence Move all the sleep-and-exit cases into a single section of code. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4aaaa3b..87525eb 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -523,18 +523,14 @@ int nfs41_setup_sequence(struct nfs4_session *session, if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { /* The state manager will wait until the slot table is empty */ - rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); - spin_unlock(&tbl->slot_tbl_lock); dprintk("%s session is draining\n", __func__); - return -EAGAIN; + goto out_sleep; } if (!rpc_queue_empty(&tbl->slot_tbl_waitq) && !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { - rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); - spin_unlock(&tbl->slot_tbl_lock); dprintk("%s enforce FIFO order\n", __func__); - return -EAGAIN; + goto out_sleep; } slot = nfs4_alloc_slot(tbl); @@ -542,10 +538,8 @@ int nfs41_setup_sequence(struct nfs4_session *session, /* If out of memory, try again in 1/4 second */ if (slot == ERR_PTR(-ENOMEM)) task->tk_timeout = HZ >> 2; - rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); - spin_unlock(&tbl->slot_tbl_lock); dprintk("<-- %s: no free slots\n", __func__); - return -EAGAIN; + goto out_sleep; } spin_unlock(&tbl->slot_tbl_lock); @@ -566,6 +560,10 @@ int nfs41_setup_sequence(struct nfs4_session *session, out_success: rpc_call_start(task); return 0; +out_sleep: + rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); + spin_unlock(&tbl->slot_tbl_lock); + return -EAGAIN; } EXPORT_SYMBOL_GPL(nfs41_setup_sequence); -- cgit v0.10.2 From 275e7e20aa8599719729f8ef4c09c9bfc4895642 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 1 Nov 2012 17:07:07 -0400 Subject: NFSv4.1: Remove the 'FIFO' behaviour for nfs41_setup_sequence It is more important to preserve the task priority behaviour, which ensures that things like reclaim writes take precedence over background and kupdate writes. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 4f0cdc1..4635bf5 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -236,7 +236,6 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser return server->nfs_client->cl_session; } -extern bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy); extern int nfs4_setup_sequence(const struct nfs_server *server, struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, struct rpc_task *task); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 87525eb..4b1635c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -379,12 +379,6 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp #if defined(CONFIG_NFS_V4_1) -bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy) -{ - rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); - return true; -} - static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) { struct nfs4_session *session; @@ -412,8 +406,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) if (tbl->highest_used_slotid != NFS4_NO_SLOT) send_new_highest_used_slotid = false; if (!nfs4_session_draining(session)) { - if (rpc_wake_up_first(&tbl->slot_tbl_waitq, - nfs4_set_task_privileged, NULL) != NULL) + if (rpc_wake_up_next(&tbl->slot_tbl_waitq) != NULL) send_new_highest_used_slotid = false; } spin_unlock(&tbl->slot_tbl_lock); @@ -527,12 +520,6 @@ int nfs41_setup_sequence(struct nfs4_session *session, goto out_sleep; } - if (!rpc_queue_empty(&tbl->slot_tbl_waitq) && - !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { - dprintk("%s enforce FIFO order\n", __func__); - goto out_sleep; - } - slot = nfs4_alloc_slot(tbl); if (IS_ERR(slot)) { /* If out of memory, try again in 1/4 second */ diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index c137421..7d73df5 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -263,9 +263,7 @@ static void nfs4_end_drain_session(struct nfs_client *clp) if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { spin_lock(&tbl->slot_tbl_lock); for (i = 0; i <= tbl->max_slotid; i++) { - if (rpc_wake_up_first(&tbl->slot_tbl_waitq, - nfs4_set_task_privileged, - NULL) == NULL) + if (rpc_wake_up_next(&tbl->slot_tbl_waitq) == NULL) break; } spin_unlock(&tbl->slot_tbl_lock); -- cgit v0.10.2 From 8fe72bac8de784c4059b41a7dd6bb0151a3ae898 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 29 Oct 2012 19:02:20 -0400 Subject: NFSv4: Clean up handling of privileged operations Privileged rpc calls are those that are run by the state recovery thread, in cases where we're trying to recover the system after a server reboot or a network partition. In those cases, we want to fence off all other rpc calls (see nfs4_begin_drain_session()) so that they don't end up using stateids or clientids that are in the process of being recovered. Prior to this patch, we had to set up special callback functions in order to declare an rpc call as being privileged. By adding a new field to the sequence arguments, this patch simplifies things considerably, and allows us to declare the rpc call as privileged before it is run. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4b1635c..38a709d 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -490,11 +490,17 @@ static void nfs41_init_sequence(struct nfs4_sequence_args *args, { args->sa_slot = NULL; args->sa_cache_this = 0; + args->sa_privileged = 0; if (cache_reply) args->sa_cache_this = 1; res->sr_slot = NULL; } +static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args) +{ + args->sa_privileged = 1; +} + int nfs41_setup_sequence(struct nfs4_session *session, struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, @@ -514,7 +520,7 @@ int nfs41_setup_sequence(struct nfs4_session *session, spin_lock(&tbl->slot_tbl_lock); if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && - !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { + !args->sa_privileged) { /* The state manager will wait until the slot table is empty */ dprintk("%s session is draining\n", __func__); goto out_sleep; @@ -548,6 +554,9 @@ out_success: rpc_call_start(task); return 0; out_sleep: + /* Privileged tasks are queued with top priority */ + if (args->sa_privileged) + rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); spin_unlock(&tbl->slot_tbl_lock); return -EAGAIN; @@ -593,12 +602,6 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) nfs41_setup_sequence(session, data->seq_args, data->seq_res, task); } -static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata) -{ - rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); - nfs41_call_sync_prepare(task, calldata); -} - static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) { struct nfs41_call_sync_data *data = calldata; @@ -611,17 +614,11 @@ static const struct rpc_call_ops nfs41_call_sync_ops = { .rpc_call_done = nfs41_call_sync_done, }; -static const struct rpc_call_ops nfs41_call_priv_sync_ops = { - .rpc_call_prepare = nfs41_call_priv_sync_prepare, - .rpc_call_done = nfs41_call_sync_done, -}; - static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, struct nfs_server *server, struct rpc_message *msg, struct nfs4_sequence_args *args, - struct nfs4_sequence_res *res, - int privileged) + struct nfs4_sequence_res *res) { int ret; struct rpc_task *task; @@ -637,8 +634,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, .callback_data = &data }; - if (privileged) - task_setup.callback_ops = &nfs41_call_priv_sync_ops; task = rpc_run_task(&task_setup); if (IS_ERR(task)) ret = PTR_ERR(task); @@ -656,16 +651,21 @@ int _nfs4_call_sync_session(struct rpc_clnt *clnt, struct nfs4_sequence_args *args, struct nfs4_sequence_res *res) { - return nfs4_call_sync_sequence(clnt, server, msg, args, res, 0); + return nfs4_call_sync_sequence(clnt, server, msg, args, res); } #else -static inline +static void nfs41_init_sequence(struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, int cache_reply) { } +static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args) +{ +} + + static int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) { @@ -1475,13 +1475,6 @@ unlock_no_action: rcu_read_unlock(); out_no_action: task->tk_action = NULL; - -} - -static void nfs4_recover_open_prepare(struct rpc_task *task, void *calldata) -{ - rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); - nfs4_open_prepare(task, calldata); } static void nfs4_open_done(struct rpc_task *task, void *calldata) @@ -1542,12 +1535,6 @@ static const struct rpc_call_ops nfs4_open_ops = { .rpc_release = nfs4_open_release, }; -static const struct rpc_call_ops nfs4_recover_open_ops = { - .rpc_call_prepare = nfs4_recover_open_prepare, - .rpc_call_done = nfs4_open_done, - .rpc_release = nfs4_open_release, -}; - static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) { struct inode *dir = data->dir->d_inode; @@ -1577,7 +1564,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) data->rpc_status = 0; data->cancelled = 0; if (isrecover) - task_setup_data.callback_ops = &nfs4_recover_open_ops; + nfs4_set_sequence_privileged(&o_arg->seq_args); task = rpc_run_task(&task_setup_data); if (IS_ERR(task)) return PTR_ERR(task); @@ -4558,8 +4545,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) return; /* Do we need to do an open_to_lock_owner? */ if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { - if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) + if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) { goto out_release_lock_seqid; + } data->arg.open_stateid = &state->stateid; data->arg.new_lock_owner = 1; data->res.open_seqid = data->arg.open_seqid; @@ -4574,13 +4562,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) nfs_release_seqid(data->arg.open_seqid); out_release_lock_seqid: nfs_release_seqid(data->arg.lock_seqid); - dprintk("%s: done!, ret = %d\n", __func__, task->tk_status); -} - -static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata) -{ - rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); - nfs4_lock_prepare(task, calldata); + dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); } static void nfs4_lock_done(struct rpc_task *task, void *calldata) @@ -4635,12 +4617,6 @@ static const struct rpc_call_ops nfs4_lock_ops = { .rpc_release = nfs4_lock_release, }; -static const struct rpc_call_ops nfs4_recover_lock_ops = { - .rpc_call_prepare = nfs4_recover_lock_prepare, - .rpc_call_done = nfs4_lock_done, - .rpc_release = nfs4_lock_release, -}; - static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error) { switch (error) { @@ -4683,15 +4659,15 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f return -ENOMEM; if (IS_SETLKW(cmd)) data->arg.block = 1; - if (recovery_type > NFS_LOCK_NEW) { - if (recovery_type == NFS_LOCK_RECLAIM) - data->arg.reclaim = NFS_LOCK_RECLAIM; - task_setup_data.callback_ops = &nfs4_recover_lock_ops; - } nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1); msg.rpc_argp = &data->arg; msg.rpc_resp = &data->res; task_setup_data.callback_data = data; + if (recovery_type > NFS_LOCK_NEW) { + if (recovery_type == NFS_LOCK_RECLAIM) + data->arg.reclaim = NFS_LOCK_RECLAIM; + nfs4_set_sequence_privileged(&data->arg.seq_args); + } task = rpc_run_task(&task_setup_data); if (IS_ERR(task)) return PTR_ERR(task); @@ -5432,7 +5408,6 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task, (struct nfs4_get_lease_time_data *)calldata; dprintk("--> %s\n", __func__); - rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); /* just setup sequence, do not trigger session recovery since we're invoked within one */ nfs41_setup_sequence(data->clp->cl_session, @@ -5500,6 +5475,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) int status; nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0); + nfs4_set_sequence_privileged(&args.la_seq_args); dprintk("--> %s\n", __func__); task = rpc_run_task(&task_setup); @@ -5775,26 +5751,15 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data) nfs41_setup_sequence(clp->cl_session, args, res, task); } -static void nfs41_sequence_prepare_privileged(struct rpc_task *task, void *data) -{ - rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); - nfs41_sequence_prepare(task, data); -} - static const struct rpc_call_ops nfs41_sequence_ops = { .rpc_call_done = nfs41_sequence_call_done, .rpc_call_prepare = nfs41_sequence_prepare, .rpc_release = nfs41_sequence_release, }; -static const struct rpc_call_ops nfs41_sequence_privileged_ops = { - .rpc_call_done = nfs41_sequence_call_done, - .rpc_call_prepare = nfs41_sequence_prepare_privileged, - .rpc_release = nfs41_sequence_release, -}; - -static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred, - const struct rpc_call_ops *seq_ops) +static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, + struct rpc_cred *cred, + bool is_privileged) { struct nfs4_sequence_data *calldata; struct rpc_message msg = { @@ -5804,7 +5769,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_ struct rpc_task_setup task_setup_data = { .rpc_client = clp->cl_rpcclient, .rpc_message = &msg, - .callback_ops = seq_ops, + .callback_ops = &nfs41_sequence_ops, .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT, }; @@ -5816,6 +5781,8 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_ return ERR_PTR(-ENOMEM); } nfs41_init_sequence(&calldata->args, &calldata->res, 0); + if (is_privileged) + nfs4_set_sequence_privileged(&calldata->args); msg.rpc_argp = &calldata->args; msg.rpc_resp = &calldata->res; calldata->clp = clp; @@ -5831,7 +5798,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0) return 0; - task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_ops); + task = _nfs41_proc_sequence(clp, cred, false); if (IS_ERR(task)) ret = PTR_ERR(task); else @@ -5845,7 +5812,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) struct rpc_task *task; int ret; - task = _nfs41_proc_sequence(clp, cred, &nfs41_sequence_privileged_ops); + task = _nfs41_proc_sequence(clp, cred, true); if (IS_ERR(task)) { ret = PTR_ERR(task); goto out; @@ -5874,7 +5841,6 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data) { struct nfs4_reclaim_complete_data *calldata = data; - rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); nfs41_setup_sequence(calldata->clp->cl_session, &calldata->arg.seq_args, &calldata->res.seq_res, @@ -5955,6 +5921,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp) calldata->arg.one_fs = 0; nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0); + nfs4_set_sequence_privileged(&calldata->arg.seq_args); msg.rpc_argp = &calldata->arg; msg.rpc_resp = &calldata->res; task_setup_data.callback_data = calldata; @@ -6521,7 +6488,9 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) dprintk("NFS call test_stateid %p\n", stateid); nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); - status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); + nfs4_set_sequence_privileged(&args.seq_args); + status = nfs4_call_sync_sequence(server->client, server, &msg, + &args.seq_args, &res.seq_res); if (status != NFS_OK) { dprintk("NFS reply test_stateid: failed, %d\n", status); return status; @@ -6568,8 +6537,9 @@ static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) dprintk("NFS call free_stateid %p\n", stateid); nfs41_init_sequence(&args.seq_args, &res.seq_res, 0); + nfs4_set_sequence_privileged(&args.seq_args); status = nfs4_call_sync_sequence(server->client, server, &msg, - &args.seq_args, &res.seq_res, 1); + &args.seq_args, &res.seq_res); dprintk("NFS reply free_stateid: %d\n", status); return status; } diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 2076149..baa673e 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -188,7 +188,8 @@ struct nfs4_channel_attrs { struct nfs4_slot; struct nfs4_sequence_args { struct nfs4_slot *sa_slot; - u8 sa_cache_this; + u8 sa_cache_this : 1, + sa_privileged : 1; }; struct nfs4_sequence_res { -- cgit v0.10.2 From 104287cd4ebb5484c654551c102c25c94227f717 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Mon, 12 Nov 2012 14:13:13 -0500 Subject: NFS: Remove _nfs_call_sync_session All it does is pass its arguments through to another function. Let's cut out the middleman... Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 38a709d..7f8b427 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -644,16 +644,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, return ret; } -static -int _nfs4_call_sync_session(struct rpc_clnt *clnt, - struct nfs_server *server, - struct rpc_message *msg, - struct nfs4_sequence_args *args, - struct nfs4_sequence_res *res) -{ - return nfs4_call_sync_sequence(clnt, server, msg, args, res); -} - #else static void nfs41_init_sequence(struct nfs4_sequence_args *args, @@ -6659,7 +6649,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { #if defined(CONFIG_NFS_V4_1) static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { .minor_version = 1, - .call_sync = _nfs4_call_sync_session, + .call_sync = nfs4_call_sync_sequence, .match_stateid = nfs41_match_stateid, .find_root_sec = nfs41_find_root_sec, .reboot_recovery_ops = &nfs41_reboot_recovery_ops, -- cgit v0.10.2 From 1e1093c7fd4951bb4272212c238d09cd7a22f5fc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 1 Nov 2012 16:44:05 -0400 Subject: NFSv4.1: Don't mess with task priorities in nfs41_setup_sequence We want to preserve the rpc_task priority for things like writebacks, that may have differing levels of urgency. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7f8b427..99d99a5 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -536,8 +536,6 @@ int nfs41_setup_sequence(struct nfs4_session *session, } spin_unlock(&tbl->slot_tbl_lock); - rpc_task_set_priority(task, RPC_PRIORITY_NORMAL); - args->sa_slot = slot; dprintk("<-- %s slotid=%d seqid=%d\n", __func__, @@ -556,8 +554,10 @@ out_success: out_sleep: /* Privileged tasks are queued with top priority */ if (args->sa_privileged) - rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); - rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); + rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task, + NULL, RPC_PRIORITY_PRIVILEGED); + else + rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); spin_unlock(&tbl->slot_tbl_lock); return -EAGAIN; } diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 8529026..1aefc9f 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -379,6 +379,7 @@ void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task, __rpc_sleep_on_priority(q, task, action, priority - RPC_PRIORITY_LOW); spin_unlock_bh(&q->lock); } +EXPORT_SYMBOL_GPL(rpc_sleep_on_priority); /** * __rpc_do_wake_up_task - wake up a single rpc_task -- cgit v0.10.2 From 62ae082d883d167cdaa7895cf2972d85e178228a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 29 Nov 2012 17:10:01 -0500 Subject: NFSv4: Reorder the XDR structures to put sequence at the top, not bottom Pre-condition for optimising the slot allocation and reintroducing FIFO behaviour. Signed-off-by: Trond Myklebust diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index baa673e..a55abd4 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -205,8 +205,8 @@ struct nfs4_get_lease_time_args { }; struct nfs4_get_lease_time_res { - struct nfs_fsinfo *lr_fsinfo; struct nfs4_sequence_res lr_seq_res; + struct nfs_fsinfo *lr_fsinfo; }; #define PNFS_LAYOUT_MAXSIZE 4096 @@ -224,23 +224,23 @@ struct pnfs_layout_range { }; struct nfs4_layoutget_args { + struct nfs4_sequence_args seq_args; __u32 type; struct pnfs_layout_range range; __u64 minlength; __u32 maxcount; struct inode *inode; struct nfs_open_context *ctx; - struct nfs4_sequence_args seq_args; nfs4_stateid stateid; struct nfs4_layoutdriver_data layout; }; struct nfs4_layoutget_res { + struct nfs4_sequence_res seq_res; __u32 return_on_close; struct pnfs_layout_range range; __u32 type; nfs4_stateid stateid; - struct nfs4_sequence_res seq_res; struct nfs4_layoutdriver_data *layoutp; }; @@ -251,38 +251,38 @@ struct nfs4_layoutget { }; struct nfs4_getdevicelist_args { + struct nfs4_sequence_args seq_args; const struct nfs_fh *fh; u32 layoutclass; - struct nfs4_sequence_args seq_args; }; struct nfs4_getdevicelist_res { - struct pnfs_devicelist *devlist; struct nfs4_sequence_res seq_res; + struct pnfs_devicelist *devlist; }; struct nfs4_getdeviceinfo_args { - struct pnfs_device *pdev; struct nfs4_sequence_args seq_args; + struct pnfs_device *pdev; }; struct nfs4_getdeviceinfo_res { - struct pnfs_device *pdev; struct nfs4_sequence_res seq_res; + struct pnfs_device *pdev; }; struct nfs4_layoutcommit_args { + struct nfs4_sequence_args seq_args; nfs4_stateid stateid; __u64 lastbytewritten; struct inode *inode; const u32 *bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs4_layoutcommit_res { + struct nfs4_sequence_res seq_res; struct nfs_fattr *fattr; const struct nfs_server *server; - struct nfs4_sequence_res seq_res; int status; }; @@ -296,11 +296,11 @@ struct nfs4_layoutcommit_data { }; struct nfs4_layoutreturn_args { + struct nfs4_sequence_args seq_args; struct pnfs_layout_hdr *layout; struct inode *inode; nfs4_stateid stateid; __u32 layout_type; - struct nfs4_sequence_args seq_args; }; struct nfs4_layoutreturn_res { @@ -326,6 +326,7 @@ struct stateowner_id { * Arguments to the open call. */ struct nfs_openargs { + struct nfs4_sequence_args seq_args; const struct nfs_fh * fh; struct nfs_seqid * seqid; int open_flags; @@ -346,10 +347,10 @@ struct nfs_openargs { const u32 * bitmask; const u32 * open_bitmap; __u32 claim; - struct nfs4_sequence_args seq_args; }; struct nfs_openres { + struct nfs4_sequence_res seq_res; nfs4_stateid stateid; struct nfs_fh fh; struct nfs4_change_info cinfo; @@ -364,7 +365,6 @@ struct nfs_openres { __u32 attrset[NFS4_BITMAP_SIZE]; struct nfs4_string *owner; struct nfs4_string *group_owner; - struct nfs4_sequence_res seq_res; __u32 access_request; __u32 access_supported; __u32 access_result; @@ -388,20 +388,20 @@ struct nfs_open_confirmres { * Arguments to the close call. */ struct nfs_closeargs { + struct nfs4_sequence_args seq_args; struct nfs_fh * fh; nfs4_stateid * stateid; struct nfs_seqid * seqid; fmode_t fmode; const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs_closeres { + struct nfs4_sequence_res seq_res; nfs4_stateid stateid; struct nfs_fattr * fattr; struct nfs_seqid * seqid; const struct nfs_server *server; - struct nfs4_sequence_res seq_res; }; /* * * Arguments to the lock,lockt, and locku call. @@ -413,6 +413,7 @@ struct nfs_lowner { }; struct nfs_lock_args { + struct nfs4_sequence_args seq_args; struct nfs_fh * fh; struct file_lock * fl; struct nfs_seqid * lock_seqid; @@ -423,40 +424,39 @@ struct nfs_lock_args { unsigned char block : 1; unsigned char reclaim : 1; unsigned char new_lock_owner : 1; - struct nfs4_sequence_args seq_args; }; struct nfs_lock_res { + struct nfs4_sequence_res seq_res; nfs4_stateid stateid; struct nfs_seqid * lock_seqid; struct nfs_seqid * open_seqid; - struct nfs4_sequence_res seq_res; }; struct nfs_locku_args { + struct nfs4_sequence_args seq_args; struct nfs_fh * fh; struct file_lock * fl; struct nfs_seqid * seqid; nfs4_stateid * stateid; - struct nfs4_sequence_args seq_args; }; struct nfs_locku_res { + struct nfs4_sequence_res seq_res; nfs4_stateid stateid; struct nfs_seqid * seqid; - struct nfs4_sequence_res seq_res; }; struct nfs_lockt_args { + struct nfs4_sequence_args seq_args; struct nfs_fh * fh; struct file_lock * fl; struct nfs_lowner lock_owner; - struct nfs4_sequence_args seq_args; }; struct nfs_lockt_res { - struct file_lock * denied; /* LOCK, LOCKT failed */ struct nfs4_sequence_res seq_res; + struct file_lock * denied; /* LOCK, LOCKT failed */ }; struct nfs_release_lockowner_args { @@ -464,22 +464,23 @@ struct nfs_release_lockowner_args { }; struct nfs4_delegreturnargs { + struct nfs4_sequence_args seq_args; const struct nfs_fh *fhandle; const nfs4_stateid *stateid; const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs4_delegreturnres { + struct nfs4_sequence_res seq_res; struct nfs_fattr * fattr; const struct nfs_server *server; - struct nfs4_sequence_res seq_res; }; /* * Arguments to the read call. */ struct nfs_readargs { + struct nfs4_sequence_args seq_args; struct nfs_fh * fh; struct nfs_open_context *context; struct nfs_lock_context *lock_context; @@ -487,20 +488,20 @@ struct nfs_readargs { __u32 count; unsigned int pgbase; struct page ** pages; - struct nfs4_sequence_args seq_args; }; struct nfs_readres { + struct nfs4_sequence_res seq_res; struct nfs_fattr * fattr; __u32 count; int eof; - struct nfs4_sequence_res seq_res; }; /* * Arguments to the write call. */ struct nfs_writeargs { + struct nfs4_sequence_args seq_args; struct nfs_fh * fh; struct nfs_open_context *context; struct nfs_lock_context *lock_context; @@ -510,7 +511,6 @@ struct nfs_writeargs { unsigned int pgbase; struct page ** pages; const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs_write_verifier { @@ -523,65 +523,65 @@ struct nfs_writeverf { }; struct nfs_writeres { + struct nfs4_sequence_res seq_res; struct nfs_fattr * fattr; struct nfs_writeverf * verf; __u32 count; const struct nfs_server *server; - struct nfs4_sequence_res seq_res; }; /* * Arguments to the commit call. */ struct nfs_commitargs { + struct nfs4_sequence_args seq_args; struct nfs_fh *fh; __u64 offset; __u32 count; const u32 *bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs_commitres { + struct nfs4_sequence_res seq_res; struct nfs_fattr *fattr; struct nfs_writeverf *verf; const struct nfs_server *server; - struct nfs4_sequence_res seq_res; }; /* * Common arguments to the unlink call */ struct nfs_removeargs { + struct nfs4_sequence_args seq_args; const struct nfs_fh *fh; struct qstr name; - struct nfs4_sequence_args seq_args; }; struct nfs_removeres { + struct nfs4_sequence_res seq_res; const struct nfs_server *server; struct nfs_fattr *dir_attr; struct nfs4_change_info cinfo; - struct nfs4_sequence_res seq_res; }; /* * Common arguments to the rename call */ struct nfs_renameargs { + struct nfs4_sequence_args seq_args; const struct nfs_fh *old_dir; const struct nfs_fh *new_dir; const struct qstr *old_name; const struct qstr *new_name; - struct nfs4_sequence_args seq_args; }; struct nfs_renameres { + struct nfs4_sequence_res seq_res; const struct nfs_server *server; struct nfs4_change_info old_cinfo; struct nfs_fattr *old_fattr; struct nfs4_change_info new_cinfo; struct nfs_fattr *new_fattr; - struct nfs4_sequence_res seq_res; }; /* @@ -622,20 +622,20 @@ struct nfs_createargs { }; struct nfs_setattrargs { + struct nfs4_sequence_args seq_args; struct nfs_fh * fh; nfs4_stateid stateid; struct iattr * iap; const struct nfs_server * server; /* Needed for name mapping */ const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs_setaclargs { + struct nfs4_sequence_args seq_args; struct nfs_fh * fh; size_t acl_len; unsigned int acl_pgbase; struct page ** acl_pages; - struct nfs4_sequence_args seq_args; }; struct nfs_setaclres { @@ -643,27 +643,27 @@ struct nfs_setaclres { }; struct nfs_getaclargs { + struct nfs4_sequence_args seq_args; struct nfs_fh * fh; size_t acl_len; unsigned int acl_pgbase; struct page ** acl_pages; - struct nfs4_sequence_args seq_args; }; /* getxattr ACL interface flags */ #define NFS4_ACL_TRUNC 0x0001 /* ACL was truncated */ struct nfs_getaclres { + struct nfs4_sequence_res seq_res; size_t acl_len; size_t acl_data_offset; int acl_flags; struct page * acl_scratch; - struct nfs4_sequence_res seq_res; }; struct nfs_setattrres { + struct nfs4_sequence_res seq_res; struct nfs_fattr * fattr; const struct nfs_server * server; - struct nfs4_sequence_res seq_res; }; struct nfs_linkargs { @@ -828,21 +828,22 @@ struct nfs3_getaclres { typedef u64 clientid4; struct nfs4_accessargs { + struct nfs4_sequence_args seq_args; const struct nfs_fh * fh; const u32 * bitmask; u32 access; - struct nfs4_sequence_args seq_args; }; struct nfs4_accessres { + struct nfs4_sequence_res seq_res; const struct nfs_server * server; struct nfs_fattr * fattr; u32 supported; u32 access; - struct nfs4_sequence_res seq_res; }; struct nfs4_create_arg { + struct nfs4_sequence_args seq_args; u32 ftype; union { struct { @@ -859,88 +860,88 @@ struct nfs4_create_arg { const struct iattr * attrs; const struct nfs_fh * dir_fh; const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs4_create_res { + struct nfs4_sequence_res seq_res; const struct nfs_server * server; struct nfs_fh * fh; struct nfs_fattr * fattr; struct nfs4_change_info dir_cinfo; - struct nfs4_sequence_res seq_res; }; struct nfs4_fsinfo_arg { + struct nfs4_sequence_args seq_args; const struct nfs_fh * fh; const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs4_fsinfo_res { - struct nfs_fsinfo *fsinfo; struct nfs4_sequence_res seq_res; + struct nfs_fsinfo *fsinfo; }; struct nfs4_getattr_arg { + struct nfs4_sequence_args seq_args; const struct nfs_fh * fh; const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs4_getattr_res { + struct nfs4_sequence_res seq_res; const struct nfs_server * server; struct nfs_fattr * fattr; - struct nfs4_sequence_res seq_res; }; struct nfs4_link_arg { + struct nfs4_sequence_args seq_args; const struct nfs_fh * fh; const struct nfs_fh * dir_fh; const struct qstr * name; const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs4_link_res { + struct nfs4_sequence_res seq_res; const struct nfs_server * server; struct nfs_fattr * fattr; struct nfs4_change_info cinfo; struct nfs_fattr * dir_attr; - struct nfs4_sequence_res seq_res; }; struct nfs4_lookup_arg { + struct nfs4_sequence_args seq_args; const struct nfs_fh * dir_fh; const struct qstr * name; const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs4_lookup_res { + struct nfs4_sequence_res seq_res; const struct nfs_server * server; struct nfs_fattr * fattr; struct nfs_fh * fh; - struct nfs4_sequence_res seq_res; }; struct nfs4_lookup_root_arg { - const u32 * bitmask; struct nfs4_sequence_args seq_args; + const u32 * bitmask; }; struct nfs4_pathconf_arg { + struct nfs4_sequence_args seq_args; const struct nfs_fh * fh; const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs4_pathconf_res { - struct nfs_pathconf *pathconf; struct nfs4_sequence_res seq_res; + struct nfs_pathconf *pathconf; }; struct nfs4_readdir_arg { + struct nfs4_sequence_args seq_args; const struct nfs_fh * fh; u64 cookie; nfs4_verifier verifier; @@ -949,21 +950,20 @@ struct nfs4_readdir_arg { unsigned int pgbase; /* zero-copy data */ const u32 * bitmask; int plus; - struct nfs4_sequence_args seq_args; }; struct nfs4_readdir_res { + struct nfs4_sequence_res seq_res; nfs4_verifier verifier; unsigned int pgbase; - struct nfs4_sequence_res seq_res; }; struct nfs4_readlink { + struct nfs4_sequence_args seq_args; const struct nfs_fh * fh; unsigned int pgbase; unsigned int pglen; /* zero-copy data */ struct page ** pages; /* zero-copy data */ - struct nfs4_sequence_args seq_args; }; struct nfs4_readlink_res { @@ -989,28 +989,28 @@ struct nfs4_setclientid_res { }; struct nfs4_statfs_arg { + struct nfs4_sequence_args seq_args; const struct nfs_fh * fh; const u32 * bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs4_statfs_res { - struct nfs_fsstat *fsstat; struct nfs4_sequence_res seq_res; + struct nfs_fsstat *fsstat; }; struct nfs4_server_caps_arg { - struct nfs_fh *fhandle; struct nfs4_sequence_args seq_args; + struct nfs_fh *fhandle; }; struct nfs4_server_caps_res { + struct nfs4_sequence_res seq_res; u32 attr_bitmask[3]; u32 acl_bitmask; u32 has_links; u32 has_symlinks; u32 fh_expire_type; - struct nfs4_sequence_res seq_res; }; #define NFS4_PATHNAME_MAXCOMPONENTS 512 @@ -1036,16 +1036,16 @@ struct nfs4_fs_locations { }; struct nfs4_fs_locations_arg { + struct nfs4_sequence_args seq_args; const struct nfs_fh *dir_fh; const struct qstr *name; struct page *page; const u32 *bitmask; - struct nfs4_sequence_args seq_args; }; struct nfs4_fs_locations_res { - struct nfs4_fs_locations *fs_locations; struct nfs4_sequence_res seq_res; + struct nfs4_fs_locations *fs_locations; }; struct nfs4_secinfo_oid { @@ -1070,14 +1070,14 @@ struct nfs4_secinfo_flavors { }; struct nfs4_secinfo_arg { + struct nfs4_sequence_args seq_args; const struct nfs_fh *dir_fh; const struct qstr *name; - struct nfs4_sequence_args seq_args; }; struct nfs4_secinfo_res { - struct nfs4_secinfo_flavors *flavors; struct nfs4_sequence_res seq_res; + struct nfs4_secinfo_flavors *flavors; }; #endif /* CONFIG_NFS_V4 */ @@ -1157,9 +1157,9 @@ struct nfs41_create_session_res { }; struct nfs41_reclaim_complete_args { + struct nfs4_sequence_args seq_args; /* In the future extend to include curr_fh for use with migration */ unsigned char one_fs:1; - struct nfs4_sequence_args seq_args; }; struct nfs41_reclaim_complete_res { @@ -1169,28 +1169,28 @@ struct nfs41_reclaim_complete_res { #define SECINFO_STYLE_CURRENT_FH 0 #define SECINFO_STYLE_PARENT 1 struct nfs41_secinfo_no_name_args { - int style; struct nfs4_sequence_args seq_args; + int style; }; struct nfs41_test_stateid_args { - nfs4_stateid *stateid; struct nfs4_sequence_args seq_args; + nfs4_stateid *stateid; }; struct nfs41_test_stateid_res { - unsigned int status; struct nfs4_sequence_res seq_res; + unsigned int status; }; struct nfs41_free_stateid_args { - nfs4_stateid *stateid; struct nfs4_sequence_args seq_args; + nfs4_stateid *stateid; }; struct nfs41_free_stateid_res { - unsigned int status; struct nfs4_sequence_res seq_res; + unsigned int status; }; #else -- cgit v0.10.2 From b75ad4cda5a6cd3431b1c65c2739c5ebd2c4b9da Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 29 Nov 2012 17:27:47 -0500 Subject: NFSv4.1: Ensure smooth handover of slots from one task to the next waiting Currently, we see a lot of bouncing for the value of highest_used_slotid due to the fact that slots are getting freed, instead of getting instantly transmitted to the next waiting task. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 99d99a5..9922335 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -401,14 +401,15 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) if (tbl->highest_used_slotid > tbl->target_highest_slotid) send_new_highest_used_slotid = true; + if (nfs41_wake_and_assign_slot(tbl, res->sr_slot)) { + send_new_highest_used_slotid = false; + goto out_unlock; + } nfs4_free_slot(tbl, res->sr_slot); if (tbl->highest_used_slotid != NFS4_NO_SLOT) send_new_highest_used_slotid = false; - if (!nfs4_session_draining(session)) { - if (rpc_wake_up_next(&tbl->slot_tbl_waitq) != NULL) - send_new_highest_used_slotid = false; - } +out_unlock: spin_unlock(&tbl->slot_tbl_lock); res->sr_slot = NULL; if (send_new_highest_used_slotid) @@ -1465,6 +1466,7 @@ unlock_no_action: rcu_read_unlock(); out_no_action: task->tk_action = NULL; + nfs4_sequence_done(task, &data->o_res.seq_res); } static void nfs4_open_done(struct rpc_task *task, void *calldata) @@ -2135,6 +2137,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) if (!call_close) { /* Note: exit _without_ calling nfs4_close_done */ task->tk_action = NULL; + nfs4_sequence_done(task, &calldata->res.seq_res); goto out; } @@ -4384,6 +4387,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) { /* Note: exit _without_ running nfs4_locku_done */ task->tk_action = NULL; + nfs4_sequence_done(task, &calldata->res.seq_res); return; } calldata->timestamp = jiffies; diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c index 7011702..066cfa1 100644 --- a/fs/nfs/nfs4session.c +++ b/fs/nfs/nfs4session.c @@ -217,11 +217,65 @@ static void nfs4_destroy_slot_tables(struct nfs4_session *session) nfs4_shrink_slot_table(&session->bc_slot_table, 0); } +static bool nfs41_assign_slot(struct rpc_task *task, void *pslot) +{ + struct nfs4_sequence_args *args = task->tk_msg.rpc_argp; + struct nfs4_sequence_res *res = task->tk_msg.rpc_resp; + struct nfs4_slot *slot = pslot; + struct nfs4_slot_table *tbl = slot->table; + + if (nfs4_session_draining(tbl->session) && !args->sa_privileged) + return false; + slot->renewal_time = jiffies; + slot->generation = tbl->generation; + args->sa_slot = slot; + res->sr_slot = slot; + res->sr_status_flags = 0; + res->sr_status = 1; + return true; +} + +static bool __nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl, + struct nfs4_slot *slot) +{ + if (rpc_wake_up_first(&tbl->slot_tbl_waitq, nfs41_assign_slot, slot)) + return true; + return false; +} + +bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl, + struct nfs4_slot *slot) +{ + if (slot->slot_nr > tbl->max_slotid) + return false; + return __nfs41_wake_and_assign_slot(tbl, slot); +} + +static bool nfs41_try_wake_next_slot_table_entry(struct nfs4_slot_table *tbl) +{ + struct nfs4_slot *slot = nfs4_alloc_slot(tbl); + if (!IS_ERR(slot)) { + bool ret = __nfs41_wake_and_assign_slot(tbl, slot); + if (ret) + return ret; + nfs4_free_slot(tbl, slot); + } + return false; +} + +void nfs41_wake_slot_table(struct nfs4_slot_table *tbl) +{ + for (;;) { + if (!nfs41_try_wake_next_slot_table_entry(tbl)) + break; + } +} + /* Update the client's idea of target_highest_slotid */ static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, u32 target_highest_slotid) { - unsigned int max_slotid, i; + unsigned int max_slotid; if (tbl->target_highest_slotid == target_highest_slotid) return; @@ -229,9 +283,8 @@ static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, tbl->generation++; max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid); - for (i = tbl->max_slotid + 1; i <= max_slotid; i++) - rpc_wake_up_next(&tbl->slot_tbl_waitq); tbl->max_slotid = max_slotid; + nfs41_wake_slot_table(tbl); } void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index bdd14a6..7db7393 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h @@ -94,6 +94,10 @@ static inline bool nfs4_session_draining(struct nfs4_session *session) return !!test_bit(NFS4_SESSION_DRAINING, &session->session_state); } +bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl, + struct nfs4_slot *slot); +void nfs41_wake_slot_table(struct nfs4_slot_table *tbl); + /* * Determine if sessions are in use. */ diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 7d73df5..78e90a8 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -255,17 +255,13 @@ static void nfs4_end_drain_session(struct nfs_client *clp) { struct nfs4_session *ses = clp->cl_session; struct nfs4_slot_table *tbl; - unsigned int i; if (ses == NULL) return; tbl = &ses->fc_slot_table; if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { spin_lock(&tbl->slot_tbl_lock); - for (i = 0; i <= tbl->max_slotid; i++) { - if (rpc_wake_up_next(&tbl->slot_tbl_waitq) == NULL) - break; - } + nfs41_wake_slot_table(tbl); spin_unlock(&tbl->slot_tbl_lock); } } -- cgit v0.10.2 From c05eecf636101dd4347b2d8fa457626bf0088e0a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 30 Nov 2012 23:59:29 -0500 Subject: SUNRPC: Don't allow low priority tasks to pre-empt higher priority ones Currently, the priority queues attempt to be 'fair' to lower priority tasks by scheduling them after a certain number of higher priority tasks have run. The problem is that both the transport send queue and the NFSv4.1 session slot queue have strong ordering requirements. This patch therefore removes the fairness code in favour of strong ordering of task priorities. Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index dc0c3cc..b64f8eb 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -192,7 +192,6 @@ struct rpc_wait_queue { pid_t owner; /* process id of last task serviced */ unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */ unsigned char priority; /* current priority */ - unsigned char count; /* # task groups remaining serviced so far */ unsigned char nr; /* # tasks remaining for cookie */ unsigned short qlen; /* total # tasks waiting in queue */ struct rpc_timer timer_list; diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 1aefc9f..d17a704 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -98,6 +98,23 @@ __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task) list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list); } +static void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) +{ + queue->priority = priority; +} + +static void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid) +{ + queue->owner = pid; + queue->nr = RPC_BATCH_COUNT; +} + +static void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue) +{ + rpc_set_waitqueue_priority(queue, queue->maxpriority); + rpc_set_waitqueue_owner(queue, 0); +} + /* * Add new request to a priority queue. */ @@ -109,9 +126,11 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, struct rpc_task *t; INIT_LIST_HEAD(&task->u.tk_wait.links); - q = &queue->tasks[queue_priority]; if (unlikely(queue_priority > queue->maxpriority)) - q = &queue->tasks[queue->maxpriority]; + queue_priority = queue->maxpriority; + if (queue_priority > queue->priority) + rpc_set_waitqueue_priority(queue, queue_priority); + q = &queue->tasks[queue_priority]; list_for_each_entry(t, q, u.tk_wait.list) { if (t->tk_owner == task->tk_owner) { list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links); @@ -180,24 +199,6 @@ static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_tas task->tk_pid, queue, rpc_qname(queue)); } -static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) -{ - queue->priority = priority; - queue->count = 1 << (priority * 2); -} - -static inline void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid) -{ - queue->owner = pid; - queue->nr = RPC_BATCH_COUNT; -} - -static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue) -{ - rpc_set_waitqueue_priority(queue, queue->maxpriority); - rpc_set_waitqueue_owner(queue, 0); -} - static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues) { int i; @@ -464,8 +465,7 @@ static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *q /* * Check if we need to switch queues. */ - if (--queue->count) - goto new_owner; + goto new_owner; } /* -- cgit v0.10.2 From 1fa8064429d0acbf5bbf3c8a53f65679fdacc75e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 2 Dec 2012 13:54:59 -0500 Subject: NFSv4.1: Try to eliminate outliers when updating target_highest_slotid Look for sudden changes in the first and second derivatives in order to eliminate outlier changes to target_highest_slotid (which are due to out-of-order RPC replies). Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c index 066cfa1..ed5aa9f 100644 --- a/fs/nfs/nfs4session.c +++ b/fs/nfs/nfs4session.c @@ -178,6 +178,8 @@ static void nfs4_reset_slot_table(struct nfs4_slot_table *tbl, tbl->highest_used_slotid = NFS4_NO_SLOT; tbl->target_highest_slotid = server_highest_slotid; tbl->server_highest_slotid = server_highest_slotid; + tbl->d_target_highest_slotid = 0; + tbl->d2_target_highest_slotid = 0; tbl->max_slotid = server_highest_slotid; } @@ -292,6 +294,8 @@ void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, { spin_lock(&tbl->slot_tbl_lock); nfs41_set_target_slotid_locked(tbl, target_highest_slotid); + tbl->d_target_highest_slotid = 0; + tbl->d2_target_highest_slotid = 0; spin_unlock(&tbl->slot_tbl_lock); } @@ -307,16 +311,65 @@ static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, tbl->server_highest_slotid = highest_slotid; } +static s32 nfs41_derivative_target_slotid(s32 s1, s32 s2) +{ + s1 -= s2; + if (s1 == 0) + return 0; + if (s1 < 0) + return (s1 - 1) >> 1; + return (s1 + 1) >> 1; +} + +static int nfs41_sign_s32(s32 s1) +{ + if (s1 > 0) + return 1; + if (s1 < 0) + return -1; + return 0; +} + +static bool nfs41_same_sign_or_zero_s32(s32 s1, s32 s2) +{ + if (!s1 || !s2) + return true; + return nfs41_sign_s32(s1) == nfs41_sign_s32(s2); +} + +/* Try to eliminate outliers by checking for sharp changes in the + * derivatives and second derivatives + */ +static bool nfs41_is_outlier_target_slotid(struct nfs4_slot_table *tbl, + u32 new_target) +{ + s32 d_target, d2_target; + bool ret = true; + + d_target = nfs41_derivative_target_slotid(new_target, + tbl->target_highest_slotid); + d2_target = nfs41_derivative_target_slotid(d_target, + tbl->d_target_highest_slotid); + /* Is first derivative same sign? */ + if (nfs41_same_sign_or_zero_s32(d_target, tbl->d_target_highest_slotid)) + ret = false; + /* Is second derivative same sign? */ + if (nfs41_same_sign_or_zero_s32(d2_target, tbl->d2_target_highest_slotid)) + ret = false; + tbl->d_target_highest_slotid = d_target; + tbl->d2_target_highest_slotid = d2_target; + return ret; +} + void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, struct nfs4_slot *slot, struct nfs4_sequence_res *res) { spin_lock(&tbl->slot_tbl_lock); - if (tbl->generation != slot->generation) - goto out; - nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid); - nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); -out: + if (!nfs41_is_outlier_target_slotid(tbl, res->sr_target_highest_slotid)) + nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); + if (tbl->generation == slot->generation) + nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid); spin_unlock(&tbl->slot_tbl_lock); } diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index 7db7393..04f834c 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h @@ -38,6 +38,8 @@ struct nfs4_slot_table { * op for dynamic resizing */ u32 target_highest_slotid; /* Server max_slot target */ u32 server_highest_slotid; /* Server highest slotid */ + s32 d_target_highest_slotid; /* Derivative */ + s32 d2_target_highest_slotid; /* 2nd derivative */ unsigned long generation; /* Generation counter for target_highest_slotid */ struct completion complete; -- cgit v0.10.2 From cf66bb93e0f75e0a4ba1ec070692618fa028e994 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 3 Dec 2012 16:25:40 +0000 Subject: byteorder: allow arch to opt to use GCC intrinsics for byteswapping Since GCC 4.4, there have been __builtin_bswap32() and __builtin_bswap16() intrinsics. A __builtin_bswap16() came a little later (4.6 for PowerPC, 48 for other platforms). By using these instead of the inline assembler that most architectures have in their __arch_swabXX() macros, we let the compiler see what's actually happening. The resulting code should be at least as good, and much *better* in the cases where it can be combined with a nearby load or store, using a load-and-byteswap or store-and-byteswap instruction (e.g. lwbrx/stwbrx on PowerPC, movbe on Atom). When GCC is sufficiently recent *and* the architecture opts in to using the intrinsics by setting CONFIG_ARCH_USE_BUILTIN_BSWAP, they will be used in preference to the __arch_swabXX() macros. An architecture which does not set ARCH_USE_BUILTIN_BSWAP will continue to use its own hand-crafted macros. Signed-off-by: David Woodhouse Acked-by: H. Peter Anvin diff --git a/arch/Kconfig b/arch/Kconfig index 366ec06..c31416b 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -112,6 +112,25 @@ config HAVE_EFFICIENT_UNALIGNED_ACCESS See Documentation/unaligned-memory-access.txt for more information on the topic of unaligned memory accesses. +config ARCH_USE_BUILTIN_BSWAP + bool + help + Modern versions of GCC (since 4.4) have builtin functions + for handling byte-swapping. Using these, instead of the old + inline assembler that the architecture code provides in the + __arch_bswapXX() macros, allows the compiler to see what's + happening and offers more opportunity for optimisation. In + particular, the compiler will be able to combine the byteswap + with a nearby load or store and use load-and-swap or + store-and-swap instructions if the architecture has them. It + should almost *never* result in code which is worse than the + hand-coded assembler in . But just in case it + does, the use of the builtins is optional. + + Any architecture with load-and-swap or store-and-swap + instructions should set this. And it shouldn't hurt to set it + on architectures that don't have such instructions. + config HAVE_SYSCALL_WRAPPERS bool diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h index 412bc6c..dc16a85 100644 --- a/include/linux/compiler-gcc4.h +++ b/include/linux/compiler-gcc4.h @@ -63,3 +63,13 @@ #define __compiletime_warning(message) __attribute__((warning(message))) #define __compiletime_error(message) __attribute__((error(message))) #endif + +#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP +#if __GNUC_MINOR__ >= 4 +#define __HAVE_BUILTIN_BSWAP32__ +#define __HAVE_BUILTIN_BSWAP64__ +#endif +#if __GNUC_MINOR__ >= 8 || (defined(__powerpc__) && __GNUC_MINOR__ >= 6) +#define __HAVE_BUILTIN_BSWAP16__ +#endif +#endif diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h index d8e636e..973ce10 100644 --- a/include/linux/compiler-intel.h +++ b/include/linux/compiler-intel.h @@ -29,3 +29,10 @@ #endif #define uninitialized_var(x) x + +#ifndef __HAVE_BUILTIN_BSWAP16__ +/* icc has this, but it's called _bswap16 */ +#define __HAVE_BUILTIN_BSWAP16__ +#define __builtin_bswap16 _bswap16 +#endif + diff --git a/include/uapi/linux/swab.h b/include/uapi/linux/swab.h index e811474..0e011eb 100644 --- a/include/uapi/linux/swab.h +++ b/include/uapi/linux/swab.h @@ -45,7 +45,9 @@ static inline __attribute_const__ __u16 __fswab16(__u16 val) { -#ifdef __arch_swab16 +#ifdef __HAVE_BUILTIN_BSWAP16__ + return __builtin_bswap16(val); +#elif defined (__arch_swab16) return __arch_swab16(val); #else return ___constant_swab16(val); @@ -54,7 +56,9 @@ static inline __attribute_const__ __u16 __fswab16(__u16 val) static inline __attribute_const__ __u32 __fswab32(__u32 val) { -#ifdef __arch_swab32 +#ifdef __HAVE_BUILTIN_BSWAP32__ + return __builtin_bswap32(val); +#elif defined(__arch_swab32) return __arch_swab32(val); #else return ___constant_swab32(val); @@ -63,7 +67,9 @@ static inline __attribute_const__ __u32 __fswab32(__u32 val) static inline __attribute_const__ __u64 __fswab64(__u64 val) { -#ifdef __arch_swab64 +#ifdef __HAVE_BUILTIN_BSWAP64__ + return __builtin_bswap64(val); +#elif defined (__arch_swab64) return __arch_swab64(val); #elif defined(__SWAB_64_THRU_32__) __u32 h = val >> 32; -- cgit v0.10.2 From 417328c3f77187f5d8cc433627c25eb1063c1507 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 28 Nov 2012 15:12:07 +0100 Subject: pwm: Export of_pwm_xlate_with_flags() Drivers may want to use this function if they support any of the flags that can be passed via a third cell in the DT specifier. Since those drivers may be built as modules the symbol needs to be exported to make sure that it can be accessed. Signed-off-by: Thierry Reding diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 780cb6b..903138b 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -156,6 +156,7 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) return pwm; } +EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags); static struct pwm_device * of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) -- cgit v0.10.2 From 983290b0625628448ea8907243e3cbceda0a8d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Wed, 5 Dec 2012 16:34:41 +0100 Subject: pwm: i.MX: eliminate build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit compiling the i.MX pwm driver produces the following warning: |drivers/pwm/pwm-imx.c: In function 'imx_pwm_probe': |drivers/pwm/pwm-imx.c:281:7: warning: assignment discards qualifiers from pointer target type Apply a 'const' attribute to the affected variable declaration. Signed-off-by: Lothar Waßmann Acked-by: Sascha Hauer Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 8a5d3ae..fe3fbdb 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -235,7 +235,7 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(imx_pwm_dt_ids, &pdev->dev); - struct imx_pwm_data *data; + const struct imx_pwm_data *data; struct imx_chip *imx; struct resource *r; int ret = 0; -- cgit v0.10.2 From a9a18e0691228707230df660dd56364aebf6ea47 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Wed, 14 Nov 2012 12:58:13 +0100 Subject: pwm: lpc32xx: Fix the PWM polarity The duty cycles value goes from 1 (99% HIGH) to 256 (0% HIGH) but it is stored modulo 256 in the register as it is only 8 bits wide. Signed-off-by: Alban Bedel Acked-by: Alexandre Pereira da Silva Acked-by: Roland Stigge Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c index adb87f0..c9b2eb5 100644 --- a/drivers/pwm/pwm-lpc32xx.c +++ b/drivers/pwm/pwm-lpc32xx.c @@ -49,9 +49,24 @@ static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, c = 0; /* 0 set division by 256 */ period_cycles = c; + /* The duty-cycle value is as follows: + * + * DUTY-CYCLE HIGH LEVEL + * 1 99.9% + * 25 90.0% + * 128 50.0% + * 220 10.0% + * 255 0.1% + * 0 0.0% + * + * In other words, the register value is duty-cycle % 256 with + * duty-cycle in the range 1-256. + */ c = 256 * duty_ns; do_div(c, period_ns); - duty_cycles = c; + if (c > 255) + c = 255; + duty_cycles = 256 - c; writel(PWM_ENABLE | PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles), lpc32xx->base + (pwm->hwpwm << 2)); -- cgit v0.10.2 From 54b2a999a167510aa6eb54f49ef21a40946c88ba Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Wed, 14 Nov 2012 12:58:14 +0100 Subject: pwm: lpc32xx: Properly disable the clock on device removal A single clock is used for all PWMs meaning the clock's reference count might be between 0 and N when .remove() is called. Instead of a single clk_disable() call pwm_disable() on each PWM, to ensure that clk_disable() is called for each PWM that is still enabled. Signed-off-by: Alban Bedel Acked-by: Alexandre Pereira da Silva Acked-by: Roland Stigge Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c index c9b2eb5..971874b 100644 --- a/drivers/pwm/pwm-lpc32xx.c +++ b/drivers/pwm/pwm-lpc32xx.c @@ -136,8 +136,11 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev) static int __devexit lpc32xx_pwm_remove(struct platform_device *pdev) { struct lpc32xx_pwm_chip *lpc32xx = platform_get_drvdata(pdev); + unsigned int i; + + for (i = 0; i < lpc32xx->chip.npwm; i++) + pwm_disable(&lpc32xx->chip.pwms[i]); - clk_disable(lpc32xx->clk); return pwmchip_remove(&lpc32xx->chip); } -- cgit v0.10.2 From 8fc6d09dcbcdb252e8b029f2a26fe303cc4649ec Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Wed, 14 Nov 2012 12:58:15 +0100 Subject: pwm: lpc32xx: Set the chip base for dynamic allocation Doing so allows the base to be allocated dynamically at runtime and makes it easier for the chip to coexist with other PWM chips. Signed-off-by: Alban Bedel Acked-by: Alexandre Pereira da Silva Acked-by: Roland Stigge Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c index 971874b..81db1bd 100644 --- a/drivers/pwm/pwm-lpc32xx.c +++ b/drivers/pwm/pwm-lpc32xx.c @@ -121,6 +121,7 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev) lpc32xx->chip.dev = &pdev->dev; lpc32xx->chip.ops = &lpc32xx_pwm_ops; lpc32xx->chip.npwm = 2; + lpc32xx->chip.base = -1; ret = pwmchip_add(&lpc32xx->chip); if (ret < 0) { -- cgit v0.10.2 From ddf5eabd20c6cc2814fa2c00a1a033776fbc3e44 Mon Sep 17 00:00:00 2001 From: Yacine Belkadi Date: Tue, 27 Nov 2012 21:27:18 +0100 Subject: Kernel-doc: Convention: Use a "Return" section to describe return values Non-void functions should describe their return values in their kernel-doc comments. Currently, some don't, others do in various forms. For example: * Return the result. * Return: The result. * Returns the result. * Returns: the result. * Return Value: The result. * @return: the result. * This function returns the result. * It will return the result. Defining a convention would improve consistency of kernel-doc comments. It would also help scripts/kernel-doc identify the text describing the return value of a function. Thus allowing additional checks on the comments, and suitable highlighting in the generated docs (man pages, html, etc). So, as a convention, use a section named "Return" to describe the return value of a function. Signed-off-by: Yacine Belkadi Acked-by: Randy Dunlap Signed-off-by: Michal Marek diff --git a/Documentation/kernel-doc-nano-HOWTO.txt b/Documentation/kernel-doc-nano-HOWTO.txt index 3d8a977..99b57ab 100644 --- a/Documentation/kernel-doc-nano-HOWTO.txt +++ b/Documentation/kernel-doc-nano-HOWTO.txt @@ -64,6 +64,8 @@ Example kernel-doc function comment: * comment lines. * * The longer description can have multiple paragraphs. + * + * Return: Describe the return value of foobar. */ The short description following the subject can span multiple lines @@ -78,6 +80,8 @@ If a function parameter is "..." (varargs), it should be listed in kernel-doc notation as: * @...: description +The return value, if any, should be described in a dedicated section +named "Return". Example kernel-doc data structure comment. @@ -222,6 +226,9 @@ only a "*"). "section header:" names must be unique per function (or struct, union, typedef, enum). +Use the section header "Return" for sections describing the return value +of a function. + Avoid putting a spurious blank line after the function name, or else the description will be repeated! @@ -237,21 +244,21 @@ patterns, which are highlighted appropriately. NOTE 1: The multi-line descriptive text you provide does *not* recognize line breaks, so if you try to format some text nicely, as in: - Return codes + Return: 0 - cool 1 - invalid arg 2 - out of memory this will all run together and produce: - Return codes 0 - cool 1 - invalid arg 2 - out of memory + Return: 0 - cool 1 - invalid arg 2 - out of memory NOTE 2: If the descriptive text you provide has lines that begin with some phrase followed by a colon, each of those phrases will be taken as a new section heading, which means you should similarly try to avoid text like: - Return codes: + Return: 0: cool 1: invalid arg 2: out of memory -- cgit v0.10.2 From 9a52aeeb92853167a67225602b9783f3cf4e578e Mon Sep 17 00:00:00 2001 From: Yacine Belkadi Date: Tue, 27 Nov 2012 21:27:19 +0100 Subject: scripts/kernel-doc: check that non-void fcts describe their return value If a function has a return value, but its kernel-doc comment doesn't contain a "Return" section, then emit the following warning: Warning(file.h:129): No description found for return value of 'fct' Note: This check emits a lot of warnings at the moment, because many functions don't have a 'Return' doc section. So until the number of warnings goes sufficiently down, the check is only performed in verbose mode. Signed-off-by: Yacine Belkadi Acked-by: Randy Dunlap Signed-off-by: Michal Marek diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 46e7aff..28b7615 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -137,6 +137,8 @@ use strict; # should document the "Context:" of the function, e.g. whether the functions # can be called form interrupts. Unlike other sections you can end it with an # empty line. +# A non-void function should have a "Return:" section describing the return +# value(s). # Example-sections should contain the string EXAMPLE so that they are marked # appropriately in DocBook. # @@ -315,6 +317,7 @@ my $section_default = "Description"; # default section my $section_intro = "Introduction"; my $section = $section_default; my $section_context = "Context"; +my $section_return = "Return"; my $undescribed = "-- undescribed --"; @@ -2039,6 +2042,28 @@ sub check_sections($$$$$$) { } ## +# Checks the section describing the return value of a function. +sub check_return_section { + my $file = shift; + my $declaration_name = shift; + my $return_type = shift; + + # Ignore an empty return type (It's a macro) + # Ignore functions with a "void" return type. (But don't ignore "void *") + if (($return_type eq "") || ($return_type =~ /void\s*\w*\s*$/)) { + return; + } + + if (!defined($sections{$section_return}) || + $sections{$section_return} eq "") { + print STDERR "Warning(${file}:$.): " . + "No description found for return value of " . + "'$declaration_name'\n"; + ++$warnings; + } +} + +## # takes a function prototype and the name of the current file being # processed and spits out all the details stored in the global # arrays/hashes. @@ -2109,6 +2134,15 @@ sub dump_function($$) { my $prms = join " ", @parameterlist; check_sections($file, $declaration_name, "function", $sectcheck, $prms, ""); + # This check emits a lot of warnings at the moment, because many + # functions don't have a 'Return' doc section. So until the number + # of warnings goes sufficiently down, the check is only performed in + # verbose mode. + # TODO: always perform the check. + if ($verbose) { + check_return_section($file, $declaration_name, $return_type); + } + output_declaration($declaration_name, 'function', {'function' => $declaration_name, -- cgit v0.10.2 From 667b504a2c411e4d5915a6e2260a3857ba9f797a Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 5 Dec 2012 23:30:10 +0000 Subject: powerpc: mpc5200: Add a3m071 board support This patch adds the MPC5200B based a3m071 board. Signed-off-by: Stefan Roese Cc: Anatolij Gustschin Signed-off-by: Anatolij Gustschin diff --git a/arch/powerpc/boot/dts/a3m071.dts b/arch/powerpc/boot/dts/a3m071.dts new file mode 100644 index 0000000..877a28c --- /dev/null +++ b/arch/powerpc/boot/dts/a3m071.dts @@ -0,0 +1,144 @@ +/* + * a3m071 board Device Tree Source + * + * Copyright 2012 Stefan Roese + * + * Copyright (C) 2011 DENX Software Engineering GmbH + * Heiko Schocher + * + * Copyright (C) 2007 Semihalf + * Marian Balakowicz + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/include/ "mpc5200b.dtsi" + +/ { + model = "anonymous,a3m071"; + compatible = "anonymous,a3m071"; + + soc5200@f0000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc5200b-immr"; + ranges = <0 0xf0000000 0x0000c000>; + reg = <0xf0000000 0x00000100>; + bus-frequency = <0>; /* From boot loader */ + system-frequency = <0>; /* From boot loader */ + + timer@600 { + fsl,has-wdt; + }; + + spi@f00 { + status = "disabled"; + }; + + usb: usb@1000 { + status = "disabled"; + }; + + psc@2000 { + compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; + reg = <0x2000 0x100>; + interrupts = <2 1 0>; + }; + + psc@2200 { + status = "disabled"; + }; + + psc@2400 { + status = "disabled"; + }; + + psc@2600 { + status = "disabled"; + }; + + psc@2800 { + status = "disabled"; + }; + + psc@2c00 { // PSC6 + compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; + reg = <0x2c00 0x100>; + interrupts = <2 4 0>; + }; + + ethernet@3000 { + phy-handle = <&phy0>; + }; + + mdio@3000 { + phy0: ethernet-phy@3 { + reg = <0x03>; + }; + }; + + ata@3a00 { + status = "disabled"; + }; + + i2c@3d00 { + status = "disabled"; + }; + + i2c@3d40 { + status = "disabled"; + }; + }; + + localbus { + compatible = "fsl,mpc5200b-lpb","simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0xfc000000 0x02000000 + 3 0 0xe9000000 0x00080000 + 5 0 0xe8000000 0x00010000>; + + flash@0,0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0 0x0 0x02000000>; + compatible = "cfi-flash"; + bank-width = <2>; + partition@0x0 { + label = "u-boot"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition@0x00040000 { + label = "env"; + reg = <0x00040000 0x00020000>; + }; + partition@0x00060000 { + label = "dtb"; + reg = <0x00060000 0x00020000>; + }; + partition@0x00080000 { + label = "kernel"; + reg = <0x00080000 0x00500000>; + }; + partition@0x00580000 { + label = "root"; + reg = <0x00580000 0x00A80000>; + }; + }; + + fpga@3,0 { + compatible = "anonymous,a3m071-fpga"; + reg = <3 0x0 0x00080000 + 5 0x0 0x00010000>; + interrupts = <0 0 3>; /* level low */ + }; + }; + + pci@f0000d00 { + status = "disabled"; + }; +}; diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index 9cf3602..792a301 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -50,6 +50,7 @@ static void __init mpc5200_simple_setup_arch(void) /* list of the supported boards */ static const char *board[] __initdata = { + "anonymous,a3m071", "anonymous,a4m072", "anon,charon", "ifm,o2d", -- cgit v0.10.2 From 3a1f7041ddd59ec3aceb042892f811cc76e05288 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Fri, 7 Dec 2012 13:43:49 -0700 Subject: vfio: simplify kmalloc+copy_from_user to memdup_user Generated by: coccinelle/api/memdup_user.cocci Acked-by: Julia Lawall Reported-by: Fengguang Wu Signed-off-by: Alex Williamson diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 6c11994..a4dc21b 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -327,15 +327,10 @@ static long vfio_pci_ioctl(void *device_data, hdr.count > vfio_pci_get_irq_count(vdev, hdr.index)) return -EINVAL; - data = kmalloc(hdr.count * size, GFP_KERNEL); - if (!data) - return -ENOMEM; - - if (copy_from_user(data, (void __user *)(arg + minsz), - hdr.count * size)) { - kfree(data); - return -EFAULT; - } + data = memdup_user((void __user *)(arg + minsz), + hdr.count * size); + if (IS_ERR(data)) + return PTR_ERR(data); } mutex_lock(&vdev->igate); -- cgit v0.10.2 From 2007722a606bf9f195217f7afd2fbee4bc202c42 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 7 Dec 2012 13:43:50 -0700 Subject: vfio-pci: Re-order device reset Move the device reset to the end of our disable path, the device should already be stopped from pci_disable_device(). This also allows us to manipulate the save/restore to avoid the save/reset/restore + save/restore that we had before. Signed-off-by: Alex Williamson diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index a4dc21b..b179f5a 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -92,9 +92,10 @@ out: static void vfio_pci_disable(struct vfio_pci_device *vdev) { + struct pci_dev *pdev = vdev->pdev; int bar; - pci_disable_device(vdev->pdev); + pci_disable_device(pdev); vfio_pci_set_irqs_ioctl(vdev, VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, @@ -104,22 +105,40 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) vfio_config_free(vdev); - pci_reset_function(vdev->pdev); - - if (pci_load_and_free_saved_state(vdev->pdev, - &vdev->pci_saved_state) == 0) - pci_restore_state(vdev->pdev); - else - pr_info("%s: Couldn't reload %s saved state\n", - __func__, dev_name(&vdev->pdev->dev)); - for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) { if (!vdev->barmap[bar]) continue; - pci_iounmap(vdev->pdev, vdev->barmap[bar]); - pci_release_selected_regions(vdev->pdev, 1 << bar); + pci_iounmap(pdev, vdev->barmap[bar]); + pci_release_selected_regions(pdev, 1 << bar); vdev->barmap[bar] = NULL; } + + /* + * If we have saved state, restore it. If we can reset the device, + * even better. Resetting with current state seems better than + * nothing, but saving and restoring current state without reset + * is just busy work. + */ + if (pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state)) { + pr_info("%s: Couldn't reload %s saved state\n", + __func__, dev_name(&pdev->dev)); + + if (!vdev->reset_works) + return; + + pci_save_state(pdev); + } + + /* + * Disable INTx and MSI, presumably to avoid spurious interrupts + * during reset. Stolen from pci_reset_function() + */ + pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); + + if (vdev->reset_works) + __pci_reset_function(pdev); + + pci_restore_state(pdev); } static void vfio_pci_release(void *device_data) -- cgit v0.10.2 From 9df7b25ab71cee770826d1e7983eb8b6715543d6 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 7 Dec 2012 13:43:50 -0700 Subject: VFIO: unregister IOMMU notifier on error recovery path On error recovery path in function vfio_create_group(), it should unregister the IOMMU notifier for the new VFIO group. Otherwise it may cause invalid memory access later when handling bus notifications. Signed-off-by: Jiang Liu Signed-off-by: Alex Williamson diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 56097c6..3b7fa79 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -191,6 +191,17 @@ static void vfio_container_put(struct vfio_container *container) kref_put(&container->kref, vfio_container_release); } +static void vfio_group_unlock_and_free(struct vfio_group *group) +{ + mutex_unlock(&vfio.group_lock); + /* + * Unregister outside of lock. A spurious callback is harmless now + * that the group is no longer in vfio.group_list. + */ + iommu_group_unregister_notifier(group->iommu_group, &group->nb); + kfree(group); +} + /** * Group objects - create, release, get, put, search */ @@ -229,8 +240,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) minor = vfio_alloc_group_minor(group); if (minor < 0) { - mutex_unlock(&vfio.group_lock); - kfree(group); + vfio_group_unlock_and_free(group); return ERR_PTR(minor); } @@ -239,8 +249,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) if (tmp->iommu_group == iommu_group) { vfio_group_get(tmp); vfio_free_group_minor(minor); - mutex_unlock(&vfio.group_lock); - kfree(group); + vfio_group_unlock_and_free(group); return tmp; } } @@ -249,8 +258,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) group, "%d", iommu_group_id(iommu_group)); if (IS_ERR(dev)) { vfio_free_group_minor(minor); - mutex_unlock(&vfio.group_lock); - kfree(group); + vfio_group_unlock_and_free(group); return (struct vfio_group *)dev; /* ERR_PTR */ } @@ -274,16 +282,7 @@ static void vfio_group_release(struct kref *kref) device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor)); list_del(&group->vfio_next); vfio_free_group_minor(group->minor); - - mutex_unlock(&vfio.group_lock); - - /* - * Unregister outside of lock. A spurious callback is harmless now - * that the group is no longer in vfio.group_list. - */ - iommu_group_unregister_notifier(group->iommu_group, &group->nb); - - kfree(group); + vfio_group_unlock_and_free(group); } static void vfio_group_put(struct vfio_group *group) -- cgit v0.10.2 From de2b3eeafb555d7b623c9f34e399b39105ca527f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 7 Dec 2012 13:43:50 -0700 Subject: VFIO: use ACCESS_ONCE() to guard access to dev->driver Comments from dev_driver_string(), /* dev->driver can change to NULL underneath us because of unbinding, * so be careful about accessing it. */ So use ACCESS_ONCE() to guard access to dev->driver field. Signed-off-by: Jiang Liu Signed-off-by: Alex Williamson diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 3b7fa79..12c264d 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -465,8 +465,9 @@ static int vfio_dev_viable(struct device *dev, void *data) { struct vfio_group *group = data; struct vfio_device *device; + struct device_driver *drv = ACCESS_ONCE(dev->driver); - if (!dev->driver || vfio_whitelisted_driver(dev->driver)) + if (!drv || vfio_whitelisted_driver(drv)) return 0; device = vfio_group_get_device(group, dev); -- cgit v0.10.2 From 05bf3aac930752408bf38a3f070061fc5f1b9c73 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 7 Dec 2012 13:43:51 -0700 Subject: VFIO: fix out of order labels for error recovery in vfio_pci_init() The two labels for error recovery in function vfio_pci_init() is out of order, so fix it. Signed-off-by: Jiang Liu Signed-off-by: Alex Williamson diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index b179f5a..306b90c 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -576,9 +576,9 @@ static int __init vfio_pci_init(void) return 0; -out_virqfd: - vfio_pci_virqfd_exit(); out_driver: + vfio_pci_virqfd_exit(); +out_virqfd: vfio_pci_uninit_perm_bits(); return ret; } -- cgit v0.10.2 From 9a92c5091a42c565ede818fdf204c4f60004d0d8 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 7 Dec 2012 13:43:51 -0700 Subject: vfio-pci: Enable device before attempting reset Devices making use of PM reset are getting incorrectly identified as not supporting reset because pci_pm_reset() fails unless the device is in D0 power state. When first attached to vfio_pci devices are typically in an unknown power state. We can fix this by explicitly setting the power state or simply calling pci_enable_device() before attempting a pci_reset_function(). We need to enable the device anyway, so move this up in our vfio_pci_enable() function, which also simplifies the error path a bit. Note that pci_disable_device() does not explicitly set the power state, so there's no need to re-order vfio_pci_disable(). Signed-off-by: Alex Williamson diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 306b90c..b28e66c 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -43,6 +43,10 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev) u16 cmd; u8 msix_pos; + ret = pci_enable_device(pdev); + if (ret) + return ret; + vdev->reset_works = (pci_reset_function(pdev) == 0); pci_save_state(pdev); vdev->pci_saved_state = pci_store_saved_state(pdev); @@ -51,8 +55,11 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev) __func__, dev_name(&pdev->dev)); ret = vfio_config_init(vdev); - if (ret) - goto out; + if (ret) { + pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state); + pci_disable_device(pdev); + return ret; + } if (likely(!nointxmask)) vdev->pci_2_3 = pci_intx_mask_supported(pdev); @@ -77,17 +84,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev) } else vdev->msix_bar = 0xFF; - ret = pci_enable_device(pdev); - if (ret) - goto out; - - return ret; - -out: - kfree(vdev->pci_saved_state); - vdev->pci_saved_state = NULL; - vfio_config_free(vdev); - return ret; + return 0; } static void vfio_pci_disable(struct vfio_pci_device *vdev) -- cgit v0.10.2 From ad99ac2fa76b4a793ee801920f7501c8df6534d0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 3 Nov 2012 21:02:09 +0100 Subject: scripts/coccinelle/misc/warn.cocci: use WARN Use WARN(1,...) rather than printk followed by WARN(1). Signed-off-by: Julia Lawall Signed-off-by: Michal Marek diff --git a/scripts/coccinelle/misc/warn.cocci b/scripts/coccinelle/misc/warn.cocci new file mode 100644 index 0000000..fda8c35 --- /dev/null +++ b/scripts/coccinelle/misc/warn.cocci @@ -0,0 +1,109 @@ +/// Use WARN(1,...) rather than printk followed by WARN_ON(1) +/// +// Confidence: High +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual patch +virtual context +virtual org +virtual report + +@bad1@ +position p; +@@ + +printk(...); +printk@p(...); +WARN_ON(1); + +@r1 depends on context || report || org@ +position p != bad1.p; +@@ + + printk@p(...); +*WARN_ON(1); + +@script:python depends on org@ +p << r1.p; +@@ + +cocci.print_main("printk + WARN_ON can be just WARN",p) + +@script:python depends on report@ +p << r1.p; +@@ + +msg = "SUGGESTION: printk + WARN_ON can be just WARN" +coccilib.report.print_report(p[0],msg) + +@ok1 depends on patch@ +expression list es; +position p != bad1.p; +@@ + +-printk@p( ++WARN(1, + es); +-WARN_ON(1); + +@depends on patch@ +expression list ok1.es; +@@ + +if (...) +- { + WARN(1,es); +- } + +// -------------------------------------------------------------------- + +@bad2@ +position p; +@@ + +printk(...); +printk@p(...); +WARN_ON_ONCE(1); + +@r2 depends on context || report || org@ +position p != bad1.p; +@@ + + printk@p(...); +*WARN_ON_ONCE(1); + +@script:python depends on org@ +p << r2.p; +@@ + +cocci.print_main("printk + WARN_ON_ONCE can be just WARN_ONCE",p) + +@script:python depends on report@ +p << r2.p; +@@ + +msg = "SUGGESTION: printk + WARN_ON_ONCE can be just WARN_ONCE" +coccilib.report.print_report(p[0],msg) + +@ok2 depends on patch@ +expression list es; +position p != bad2.p; +@@ + +-printk@p( ++WARN_ONCE(1, + es); +-WARN_ON_ONCE(1); + +@depends on patch@ +expression list ok2.es; +@@ + +if (...) +- { + WARN_ONCE(1,es); +- } -- cgit v0.10.2 From bd1ee804af8bdf2fd5131234330615f8aecbd9ed Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 29 Oct 2012 11:23:02 +0000 Subject: kbuild: Do not remove vmlinux when cleaning external module Since commit 1f2bfbd00e466ff3489b2ca5cc75b1cccd14c123 "kbuild: link of vmlinux moved to a script" make clean with M= argument (so cleaning external module) removes vmlinux, System.map and couple of other files from the *main* kernel build directory! This not what was happening before and almost certainly not what one would expect. This patch moves makes the clean target of the script called only when !KBUILD_EXTMOD. Signed-off-by: Pawel Moll Cc: stable@vger.kernel.org [v3.5+] Signed-off-by: Michal Marek diff --git a/Makefile b/Makefile index 6744909..4781b53 100644 --- a/Makefile +++ b/Makefile @@ -1008,11 +1008,14 @@ clean: rm-dirs := $(CLEAN_DIRS) clean: rm-files := $(CLEAN_FILES) clean-dirs := $(addprefix _clean_, . $(vmlinux-alldirs) Documentation samples) -PHONY += $(clean-dirs) clean archclean +PHONY += $(clean-dirs) clean archclean vmlinuxclean $(clean-dirs): $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) -clean: archclean +vmlinuxclean: + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-vmlinux.sh clean + +clean: archclean vmlinuxclean # mrproper - Delete all generated files, including .config # @@ -1239,7 +1242,6 @@ scripts: ; endif # KBUILD_EXTMOD clean: $(clean-dirs) - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-vmlinux.sh clean $(call cmd,rmdirs) $(call cmd,rmfiles) @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \ -- cgit v0.10.2 From d06080cf08e6b59971959d9be3d0587c6e033292 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 7 Dec 2012 16:32:26 +0530 Subject: ASoC: tpa6130a2: Use devm_* APIs Converted to use devm_gpio_request and devm_regulator_get APIs. These are device managed and make error handling and cleanup a bit simpler. Cc: Peter Ujfalusi Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 565ff39..ec78073 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -398,7 +398,8 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, TPA6130A2_MUTE_L; if (data->power_gpio >= 0) { - ret = gpio_request(data->power_gpio, "tpa6130a2 enable"); + ret = devm_gpio_request(dev, data->power_gpio, + "tpa6130a2 enable"); if (ret < 0) { dev_err(dev, "Failed to request power GPIO (%d)\n", data->power_gpio); @@ -419,16 +420,16 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, break; } - data->supply = regulator_get(dev, regulator); + data->supply = devm_regulator_get(dev, regulator); if (IS_ERR(data->supply)) { ret = PTR_ERR(data->supply); dev_err(dev, "Failed to request supply: %d\n", ret); - goto err_regulator; + goto err_gpio; } ret = tpa6130a2_power(1); if (ret != 0) - goto err_power; + goto err_gpio; /* Read version */ @@ -440,15 +441,10 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, /* Disable the chip */ ret = tpa6130a2_power(0); if (ret != 0) - goto err_power; + goto err_gpio; return 0; -err_power: - regulator_put(data->supply); -err_regulator: - if (data->power_gpio >= 0) - gpio_free(data->power_gpio); err_gpio: tpa6130a2_client = NULL; @@ -457,14 +453,7 @@ err_gpio: static int __devexit tpa6130a2_remove(struct i2c_client *client) { - struct tpa6130a2_data *data = i2c_get_clientdata(client); - tpa6130a2_power(0); - - if (data->power_gpio >= 0) - gpio_free(data->power_gpio); - - regulator_put(data->supply); tpa6130a2_client = NULL; return 0; -- cgit v0.10.2 From 20154fd3706d603216f462854862203d231c6086 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 1 Dec 2012 14:24:40 +0100 Subject: asm-generic/mmu.h: Remove unused vmlist field from mm_context_t Nothing is using the vmlist field in mm_context_t anymore. It has been removed from the non-generic versions over 3 years ago 8feae1311 ("NOMMU: Make VMAs per MM as for MMU-mode linux"). Signed-off-by: Lars-Peter Clausen Signed-off-by: Arnd Bergmann diff --git a/include/asm-generic/mmu.h b/include/asm-generic/mmu.h index 4f4aa56..a67ae0a9 100644 --- a/include/asm-generic/mmu.h +++ b/include/asm-generic/mmu.h @@ -7,7 +7,6 @@ */ #ifndef __ASSEMBLY__ typedef struct { - struct vm_list_struct *vmlist; unsigned long end_brk; } mm_context_t; #endif -- cgit v0.10.2 From 9d2951bcd96ff2d5a88022ad3b4aebd6357d65d7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 1 Dec 2012 14:24:41 +0100 Subject: asm-generic/mmu.h: Add support for FDPIC No-MMU architectures often have support for FDPIC binaries. FDPIC support requires two additional fields in the mm_context_t struct. This patch adds these fields to the generic mm_context_t definition if support for FDPIC binaries is enabled. This allows to use the generic mmu.h for a few more architectures. Signed-off-by: Lars-Peter Clausen Signed-off-by: Arnd Bergmann diff --git a/include/asm-generic/mmu.h b/include/asm-generic/mmu.h index a67ae0a9..0ed3f1c 100644 --- a/include/asm-generic/mmu.h +++ b/include/asm-generic/mmu.h @@ -8,6 +8,11 @@ #ifndef __ASSEMBLY__ typedef struct { unsigned long end_brk; + +#ifdef CONFIG_BINFMT_ELF_FDPIC + unsigned long exec_fdpic_loadmap; + unsigned long interp_fdpic_loadmap; +#endif } mm_context_t; #endif -- cgit v0.10.2 From 9ab9da5ee2adc2b98ce7cc13a7f1cc900d2bee5a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 1 Dec 2012 14:24:42 +0100 Subject: c6x: Use generic asm/mmu.h c6x's asm/mmu.h is basically identical to asm-generic/mmu.h, so use it instead of the custom version. Signed-off-by: Lars-Peter Clausen Acked-by: Mark Salter Tested-by: Mark Salter Signed-off-by: Arnd Bergmann diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild index 112a496..3c8b660 100644 --- a/arch/c6x/include/asm/Kbuild +++ b/arch/c6x/include/asm/Kbuild @@ -25,6 +25,7 @@ generic-y += kdebug.h generic-y += kmap_types.h generic-y += local.h generic-y += mman.h +generic-y += mmu.h generic-y += mmu_context.h generic-y += msgbuf.h generic-y += param.h diff --git a/arch/c6x/include/asm/mmu.h b/arch/c6x/include/asm/mmu.h deleted file mode 100644 index 4467e77..0000000 --- a/arch/c6x/include/asm/mmu.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Port on Texas Instruments TMS320C6x architecture - * - * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated - * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef _ASM_C6X_MMU_H -#define _ASM_C6X_MMU_H - -typedef struct { - unsigned long end_brk; -#ifdef CONFIG_BINFMT_ELF_FDPIC - unsigned long exec_fdpic_loadmap; - unsigned long interp_fdpic_loadmap; -#endif -} mm_context_t; - -#endif /* _ASM_C6X_MMU_H */ -- cgit v0.10.2 From 0a2f505ee721f0b5480464673ca71520c0ac2eb6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 1 Dec 2012 14:24:43 +0100 Subject: h8300: Use generic asm/mmu.h h8300's asm/mmu.h is basically identical to asm-generic/mmu.h, so use it instead of the custom version. Signed-off-by: Lars-Peter Clausen Signed-off-by: Arnd Bergmann diff --git a/arch/h8300/include/asm/Kbuild b/arch/h8300/include/asm/Kbuild index 50bbf38..173de77 100644 --- a/arch/h8300/include/asm/Kbuild +++ b/arch/h8300/include/asm/Kbuild @@ -2,4 +2,5 @@ include include/asm-generic/Kbuild.asm generic-y += clkdev.h generic-y += exec.h +generic-y += mmu.h generic-y += module.h diff --git a/arch/h8300/include/asm/mmu.h b/arch/h8300/include/asm/mmu.h deleted file mode 100644 index 3130996..0000000 --- a/arch/h8300/include/asm/mmu.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __MMU_H -#define __MMU_H - -/* Copyright (C) 2002, David McCullough */ - -typedef struct { - unsigned long end_brk; -} mm_context_t; - -#endif -- cgit v0.10.2 From fb9de7ebc3a2eb7ddb83c92e288447a0c313bced Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 1 Dec 2012 14:24:44 +0100 Subject: xtensa: Use generic asm/mmu.h for nommu The nommu portion of mmu.h of the extensa platform is basically the same as the asm-generic mmu.h. So use it instead. Signed-off-by: Lars-Peter Clausen Acked-by: Chris Zankel Signed-off-by: Arnd Bergmann diff --git a/arch/xtensa/include/asm/mmu.h b/arch/xtensa/include/asm/mmu.h index 04890d6..8554b2c 100644 --- a/arch/xtensa/include/asm/mmu.h +++ b/arch/xtensa/include/asm/mmu.h @@ -12,7 +12,7 @@ #define _XTENSA_MMU_H #ifndef CONFIG_MMU -#include +#include #else /* Default "unsigned long" context */ diff --git a/arch/xtensa/include/asm/nommu.h b/arch/xtensa/include/asm/nommu.h deleted file mode 100644 index dce2c43..0000000 --- a/arch/xtensa/include/asm/nommu.h +++ /dev/null @@ -1,3 +0,0 @@ -typedef struct { - unsigned long end_brk; -} mm_context_t; -- cgit v0.10.2 From a3adb1432d7a3ad86bb17a1638e44414537e4118 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Dec 2012 18:30:51 +0100 Subject: ASoC: sigmadsp: Fix endianness conversion issue The 'addr' field of the sigma_action struct is stored as big endian in the firmware file. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 5be42bf..4068f24 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -225,7 +225,7 @@ EXPORT_SYMBOL(process_sigma_firmware); static int sigma_action_write_regmap(void *control_data, const struct sigma_action *sa, size_t len) { - return regmap_raw_write(control_data, le16_to_cpu(sa->addr), + return regmap_raw_write(control_data, be16_to_cpu(sa->addr), sa->payload, len - 2); } -- cgit v0.10.2 From a1ad500e369183796820bffb4012b876a8685219 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Fri, 7 Dec 2012 14:53:42 -0600 Subject: ASoC: cs42l73: Add DMIC's as DAPM inputs. Signed-off-by: Paul Handrigan Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 2c08c4c..4766795 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -589,6 +589,8 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { }; static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("DMICA"), + SND_SOC_DAPM_INPUT("DMICB"), SND_SOC_DAPM_INPUT("LINEINA"), SND_SOC_DAPM_INPUT("LINEINB"), SND_SOC_DAPM_INPUT("MIC1"), @@ -795,6 +797,8 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"ADC Left", NULL, "PGA Left"}, {"ADC Right", NULL, "PGA Right"}, + {"DMIC Left", NULL, "DMICA"}, + {"DMIC Right", NULL, "DMICB"}, {"Input Left Capture", "ADC Left Input", "ADC Left"}, {"Input Right Capture", "ADC Right Input", "ADC Right"}, -- cgit v0.10.2 From 41df0829cee9e4c4ba68de33b4ca26cb18ac8ed7 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Fri, 7 Dec 2012 14:53:43 -0600 Subject: ASoC: cs42l73: Add DAPM events for power down. Add power down delays between setting PDN and MCLKDIS for spk amp, spklo amp, and ear amp. Signed-off-by: Paul Handrigan Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 4766795..fb9b178 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -40,6 +40,7 @@ struct cs42l73_private { u32 sysclk; u8 mclksel; u32 mclk; + int shutdwn_delay; }; static const struct reg_default cs42l73_reg_defaults[] = { @@ -588,6 +589,57 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { SOC_ENUM("XSPOUT Mono/Stereo Select", xsp_output_mux_enum), }; +static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_POST_PMD: + /* 150 ms delay between setting PDN and MCLKDIS */ + priv->shutdwn_delay = 150; + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + +static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_POST_PMD: + /* 50 ms delay between setting PDN and MCLKDIS */ + if (priv->shutdwn_delay < 50) + priv->shutdwn_delay = 50; + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + + +static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_POST_PMD: + /* 30 ms delay between setting PDN and MCLKDIS */ + if (priv->shutdwn_delay < 30) + priv->shutdwn_delay = 30; + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_INPUT("DMICA"), SND_SOC_DAPM_INPUT("DMICB"), @@ -676,16 +728,20 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_PGA("SPK DAC", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ESL DAC", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SWITCH("HP Amp", CS42L73_PWRCTL3, 0, 1, - &hp_amp_ctl), + SND_SOC_DAPM_SWITCH_E("HP Amp", CS42L73_PWRCTL3, 0, 1, + &hp_amp_ctl, cs42l73_hp_amp_event, + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SWITCH("LO Amp", CS42L73_PWRCTL3, 1, 1, &lo_amp_ctl), - SND_SOC_DAPM_SWITCH("SPK Amp", CS42L73_PWRCTL3, 2, 1, - &spk_amp_ctl), - SND_SOC_DAPM_SWITCH("EAR Amp", CS42L73_PWRCTL3, 3, 1, - &ear_amp_ctl), - SND_SOC_DAPM_SWITCH("SPKLO Amp", CS42L73_PWRCTL3, 4, 1, - &spklo_amp_ctl), + SND_SOC_DAPM_SWITCH_E("SPK Amp", CS42L73_PWRCTL3, 2, 1, + &spk_amp_ctl, cs42l73_spklo_spk_amp_event, + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SWITCH_E("EAR Amp", CS42L73_PWRCTL3, 3, 1, + &ear_amp_ctl, cs42l73_ear_amp_event, + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SWITCH_E("SPKLO Amp", CS42L73_PWRCTL3, 4, 1, + &spklo_amp_ctl, cs42l73_spklo_spk_amp_event, + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_OUTPUT("HPOUTA"), SND_SOC_DAPM_OUTPUT("HPOUTB"), @@ -1171,6 +1227,14 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_OFF: snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); + if (cs42l73->shutdwn_delay > 0) { + mdelay(cs42l73->shutdwn_delay); + cs42l73->shutdwn_delay = 0; + } else { + mdelay(15); /* Min amount of time requred to power + * down. + */ + } snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1); break; } -- cgit v0.10.2 From 7f3dd4a8e31cdaed5f80f24b798cedcab644830b Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Fri, 7 Dec 2012 14:53:44 -0600 Subject: ASoC: cs42l73: Change VSPIN/VSPOUT to VSPINOUT Since VSP only has one power bit, only provide one DAPM widget. Signed-off-by: Paul Handrigan Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index fb9b178..dd0d9b2 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -658,9 +658,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { CS42L73_PWRCTL2, 3, 1), SND_SOC_DAPM_AIF_OUT("ASPOUTR", NULL, 0, CS42L73_PWRCTL2, 3, 1), - SND_SOC_DAPM_AIF_OUT("VSPOUTL", NULL, 0, - CS42L73_PWRCTL2, 4, 1), - SND_SOC_DAPM_AIF_OUT("VSPOUTR", NULL, 0, + SND_SOC_DAPM_AIF_OUT("VSPINOUT", NULL, 0, CS42L73_PWRCTL2, 4, 1), SND_SOC_DAPM_PGA("PGA Left", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -686,8 +684,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_MIXER("ASPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("XSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("XSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("VSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("VSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("VSP Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_AIF_IN("XSPINL", NULL, 0, CS42L73_PWRCTL2, 0, 1), @@ -703,7 +700,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("ASPINM", NULL, 0, CS42L73_PWRCTL2, 2, 1), - SND_SOC_DAPM_AIF_IN("VSPIN", NULL, 0, + SND_SOC_DAPM_AIF_IN("VSPINOUT", NULL, 0, CS42L73_PWRCTL2, 4, 1), SND_SOC_DAPM_MIXER("HL Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -763,7 +760,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"ESL DAC", "ESL-ASP Mono Volume", "ESL Mixer"}, {"ESL DAC", "ESL-XSP Mono Volume", "ESL Mixer"}, - {"ESL DAC", "ESL-VSP Mono Volume", "VSPIN"}, + {"ESL DAC", "ESL-VSP Mono Volume", "VSPINOUT"}, /* Loopback */ {"ESL DAC", "ESL-IP Mono Volume", "Input Left Capture"}, {"ESL DAC", "ESL-IP Mono Volume", "Input Right Capture"}, @@ -785,7 +782,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"SPK DAC", "SPK-ASP Mono Volume", "SPK Mixer"}, {"SPK DAC", "SPK-XSP Mono Volume", "SPK Mixer"}, - {"SPK DAC", "SPK-VSP Mono Volume", "VSPIN"}, + {"SPK DAC", "SPK-VSP Mono Volume", "VSPINOUT"}, /* Loopback */ {"SPK DAC", "SPK-IP Mono Volume", "Input Left Capture"}, {"SPK DAC", "SPK-IP Mono Volume", "Input Right Capture"}, @@ -828,8 +825,8 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"HL Right Mixer", NULL, "ASPINR"}, {"HL Left Mixer", NULL, "XSPINL"}, {"HL Right Mixer", NULL, "XSPINR"}, - {"HL Left Mixer", NULL, "VSPIN"}, - {"HL Right Mixer", NULL, "VSPIN"}, + {"HL Left Mixer", NULL, "VSPINOUT"}, + {"HL Right Mixer", NULL, "VSPINOUT"}, {"ASPINL", NULL, "ASP Playback"}, {"ASPINM", NULL, "ASP Playback"}, @@ -837,7 +834,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"XSPINL", NULL, "XSP Playback"}, {"XSPINM", NULL, "XSP Playback"}, {"XSPINR", NULL, "XSP Playback"}, - {"VSPIN", NULL, "VSP Playback"}, + {"VSPINOUT", NULL, "VSP Playback"}, /* Capture Paths */ {"MIC1", NULL, "MIC1 Bias"}, @@ -879,21 +876,18 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"XSPOUTR", NULL, "XSPR Output Mixer"}, /* Voice Capture */ - {"VSPL Output Mixer", NULL, "Input Left Capture"}, - {"VSPR Output Mixer", NULL, "Input Left Capture"}, + {"VSP Output Mixer", NULL, "Input Left Capture"}, + {"VSP Output Mixer", NULL, "Input Right Capture"}, - {"VSPOUTL", "VSP-IP Volume", "VSPL Output Mixer"}, - {"VSPOUTR", "VSP-IP Volume", "VSPR Output Mixer"}, + {"VSPINOUT", "VSP-IP Volume", "VSP Output Mixer"}, - {"VSPOUTL", NULL, "VSPL Output Mixer"}, - {"VSPOUTR", NULL, "VSPR Output Mixer"}, + {"VSPINOUT", NULL, "VSP Output Mixer"}, {"ASP Capture", NULL, "ASPOUTL"}, {"ASP Capture", NULL, "ASPOUTR"}, {"XSP Capture", NULL, "XSPOUTL"}, {"XSP Capture", NULL, "XSPOUTR"}, - {"VSP Capture", NULL, "VSPOUTL"}, - {"VSP Capture", NULL, "VSPOUTR"}, + {"VSP Capture", NULL, "VSPINOUT"}, }; struct cs42l73_mclk_div { -- cgit v0.10.2 From c871bd0b2e627ff387d0ff055d8175879c80d01f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 10 Dec 2012 16:19:52 +0900 Subject: ASoC: core: Fix splitting of log messages Don't wrap log messages over multiple lines, it makes them hard to grep for. Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cee37ee..0d42afb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4155,9 +4155,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, ret = of_property_read_string_index(np, propname, 2 * i, &routes[i].sink); if (ret) { - dev_err(card->dev, "ASoC: Property '%s' index %d" - " could not be read: %d\n", propname, 2 * i, - ret); + dev_err(card->dev, + "ASoC: Property '%s' index %d could not be read: %d\n", + propname, 2 * i, ret); kfree(routes); return -EINVAL; } @@ -4165,8 +4165,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, (2 * i) + 1, &routes[i].source); if (ret) { dev_err(card->dev, - "ASoC: Property '%s' index %d could not be" - " read: %d\n", propname, (2 * i) + 1, ret); + "ASoC: Property '%s' index %d could not be read: %d\n", + propname, (2 * i) + 1, ret); kfree(routes); return -EINVAL; } -- cgit v0.10.2 From 64575574f26d7969713ede9bde750c979da4037e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 28 Nov 2012 09:18:29 -0300 Subject: UBI: introduce helpers dbg_chk_{io, gen} With this patch code is a bit more readable and there's no generated code or functionality impact. Furthermore, this abstracts implementation details and will allow to change ubi_debug_info in a less invasive way. Signed-off-by: Ezequiel Garcia Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index 72fed30..c071d41 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -1448,7 +1448,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan) goto out_wl; #ifdef CONFIG_MTD_UBI_FASTMAP - if (ubi->fm && ubi->dbg->chk_gen) { + if (ubi->fm && ubi_dbg_chk_gen(ubi)) { struct ubi_attach_info *scan_ai; scan_ai = alloc_ai("ubi_ckh_aeb_slab_cache"); @@ -1498,7 +1498,7 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) struct ubi_ainf_peb *aeb, *last_aeb; uint8_t *buf; - if (!ubi->dbg->chk_gen) + if (!ubi_dbg_chk_gen(ubi)) return 0; /* diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 3dbc877..0add8d8 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -158,4 +158,13 @@ static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi) return 0; } +static inline int ubi_dbg_chk_io(const struct ubi_device *ubi) +{ + return ubi->dbg->chk_io; +} + +static inline int ubi_dbg_chk_gen(const struct ubi_device *ubi) +{ + return ubi->dbg->chk_gen; +} #endif /* !__UBI_DEBUG_H__ */ diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 78a1dcb..bf79def 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -1132,7 +1132,7 @@ static int self_check_not_bad(const struct ubi_device *ubi, int pnum) { int err; - if (!ubi->dbg->chk_io) + if (!ubi_dbg_chk_io(ubi)) return 0; err = ubi_io_is_bad(ubi, pnum); @@ -1159,7 +1159,7 @@ static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum, int err; uint32_t magic; - if (!ubi->dbg->chk_io) + if (!ubi_dbg_chk_io(ubi)) return 0; magic = be32_to_cpu(ec_hdr->magic); @@ -1197,7 +1197,7 @@ static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) uint32_t crc, hdr_crc; struct ubi_ec_hdr *ec_hdr; - if (!ubi->dbg->chk_io) + if (!ubi_dbg_chk_io(ubi)) return 0; ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); @@ -1241,7 +1241,7 @@ static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum, int err; uint32_t magic; - if (!ubi->dbg->chk_io) + if (!ubi_dbg_chk_io(ubi)) return 0; magic = be32_to_cpu(vid_hdr->magic); @@ -1282,7 +1282,7 @@ static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) struct ubi_vid_hdr *vid_hdr; void *p; - if (!ubi->dbg->chk_io) + if (!ubi_dbg_chk_io(ubi)) return 0; vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); @@ -1334,7 +1334,7 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum, void *buf1; loff_t addr = (loff_t)pnum * ubi->peb_size + offset; - if (!ubi->dbg->chk_io) + if (!ubi_dbg_chk_io(ubi)) return 0; buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL); @@ -1398,7 +1398,7 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) void *buf; loff_t addr = (loff_t)pnum * ubi->peb_size + offset; - if (!ubi->dbg->chk_io) + if (!ubi_dbg_chk_io(ubi)) return 0; buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL); diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 99ef8a1..8330703 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -847,7 +847,7 @@ static int self_check_volumes(struct ubi_device *ubi) { int i, err = 0; - if (!ubi->dbg->chk_gen) + if (!ubi_dbg_chk_gen(ubi)) return 0; for (i = 0; i < ubi->vtbl_slots; i++) { diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 926e3df..d77b1c1 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -858,7 +858,7 @@ out_free: */ static void self_vtbl_check(const struct ubi_device *ubi) { - if (!ubi->dbg->chk_gen) + if (!ubi_dbg_chk_gen(ubi)) return; if (vtbl_check(ubi, ubi->vtbl)) { diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index ae95517..c687538 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -2043,7 +2043,7 @@ static int self_check_ec(struct ubi_device *ubi, int pnum, int ec) long long read_ec; struct ubi_ec_hdr *ec_hdr; - if (!ubi->dbg->chk_gen) + if (!ubi_dbg_chk_gen(ubi)) return 0; ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); @@ -2083,7 +2083,7 @@ out_free: static int self_check_in_wl_tree(const struct ubi_device *ubi, struct ubi_wl_entry *e, struct rb_root *root) { - if (!ubi->dbg->chk_gen) + if (!ubi_dbg_chk_gen(ubi)) return 0; if (in_wl_tree(e, root)) @@ -2109,7 +2109,7 @@ static int self_check_in_pq(const struct ubi_device *ubi, struct ubi_wl_entry *p; int i; - if (!ubi->dbg->chk_gen) + if (!ubi_dbg_chk_gen(ubi)) return 0; for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i) -- cgit v0.10.2 From eab737722ed6a5638f6251e83f0d293c2ffe549f Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 28 Nov 2012 09:18:30 -0300 Subject: UBI: embed ubi_debug_info field in ubi_device struct ubi_debug_info struct was dynamically allocated which is always suboptimal, for it tends to fragment memory and make the code error-prone. Fix this by embedding it in ubi_device struct. Signed-off-by: Ezequiel Garcia Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index fb59604..a561335 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -985,14 +985,10 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, if (!ubi->fm_buf) goto out_free; #endif - err = ubi_debugging_init_dev(ubi); - if (err) - goto out_free; - err = ubi_attach(ubi, 0); if (err) { ubi_err("failed to attach mtd%d, error %d", mtd->index, err); - goto out_debugging; + goto out_free; } if (ubi->autoresize_vol_id != -1) { @@ -1059,8 +1055,6 @@ out_detach: ubi_wl_close(ubi); ubi_free_internal_volumes(ubi); vfree(ubi->vtbl); -out_debugging: - ubi_debugging_exit_dev(ubi); out_free: vfree(ubi->peb_buf); vfree(ubi->fm_buf); @@ -1138,7 +1132,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) ubi_free_internal_volumes(ubi); vfree(ubi->vtbl); put_mtd_device(ubi->mtd); - ubi_debugging_exit_dev(ubi); vfree(ubi->peb_buf); vfree(ubi->fm_buf); ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 26908a5..63cb1d7 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -217,32 +217,6 @@ void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req) pr_err("\t1st 16 characters of name: %s\n", nm); } -/** - * ubi_debugging_init_dev - initialize debugging for an UBI device. - * @ubi: UBI device description object - * - * This function initializes debugging-related data for UBI device @ubi. - * Returns zero in case of success and a negative error code in case of - * failure. - */ -int ubi_debugging_init_dev(struct ubi_device *ubi) -{ - ubi->dbg = kzalloc(sizeof(struct ubi_debug_info), GFP_KERNEL); - if (!ubi->dbg) - return -ENOMEM; - - return 0; -} - -/** - * ubi_debugging_exit_dev - free debugging data for an UBI device. - * @ubi: UBI device description object - */ -void ubi_debugging_exit_dev(struct ubi_device *ubi) -{ - kfree(ubi->dbg); -} - /* * Root directory for UBI stuff in debugfs. Contains sub-directories which * contain the stuff specific to particular UBI devices. @@ -295,7 +269,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf, ubi = ubi_get_device(ubi_num); if (!ubi) return -ENODEV; - d = ubi->dbg; + d = &ubi->dbg; if (dent == d->dfs_chk_gen) val = d->chk_gen; @@ -341,7 +315,7 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf, ubi = ubi_get_device(ubi_num); if (!ubi) return -ENODEV; - d = ubi->dbg; + d = &ubi->dbg; buf_size = min_t(size_t, count, (sizeof(buf) - 1)); if (copy_from_user(buf, user_buf, buf_size)) { @@ -398,7 +372,7 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi) unsigned long ubi_num = ubi->ubi_num; const char *fname; struct dentry *dent; - struct ubi_debug_info *d = ubi->dbg; + struct ubi_debug_info *d = &ubi->dbg; if (!IS_ENABLED(CONFIG_DEBUG_FS)) return 0; @@ -471,5 +445,5 @@ out: void ubi_debugfs_exit_dev(struct ubi_device *ubi) { if (IS_ENABLED(CONFIG_DEBUG_FS)) - debugfs_remove_recursive(ubi->dbg->dfs_dir); + debugfs_remove_recursive(ubi->dbg.dfs_dir); } diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 0add8d8..33f8f3b 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -60,51 +60,11 @@ void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type); void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req); int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len); -int ubi_debugging_init_dev(struct ubi_device *ubi); -void ubi_debugging_exit_dev(struct ubi_device *ubi); int ubi_debugfs_init(void); void ubi_debugfs_exit(void); int ubi_debugfs_init_dev(struct ubi_device *ubi); void ubi_debugfs_exit_dev(struct ubi_device *ubi); -/* - * The UBI debugfs directory name pattern and maximum name length (3 for "ubi" - * + 2 for the number plus 1 for the trailing zero byte. - */ -#define UBI_DFS_DIR_NAME "ubi%d" -#define UBI_DFS_DIR_LEN (3 + 2 + 1) - -/** - * struct ubi_debug_info - debugging information for an UBI device. - * - * @chk_gen: if UBI general extra checks are enabled - * @chk_io: if UBI I/O extra checks are enabled - * @disable_bgt: disable the background task for testing purposes - * @emulate_bitflips: emulate bit-flips for testing purposes - * @emulate_io_failures: emulate write/erase failures for testing purposes - * @dfs_dir_name: name of debugfs directory containing files of this UBI device - * @dfs_dir: direntry object of the UBI device debugfs directory - * @dfs_chk_gen: debugfs knob to enable UBI general extra checks - * @dfs_chk_io: debugfs knob to enable UBI I/O extra checks - * @dfs_disable_bgt: debugfs knob to disable the background task - * @dfs_emulate_bitflips: debugfs knob to emulate bit-flips - * @dfs_emulate_io_failures: debugfs knob to emulate write/erase failures - */ -struct ubi_debug_info { - unsigned int chk_gen:1; - unsigned int chk_io:1; - unsigned int disable_bgt:1; - unsigned int emulate_bitflips:1; - unsigned int emulate_io_failures:1; - char dfs_dir_name[UBI_DFS_DIR_LEN + 1]; - struct dentry *dfs_dir; - struct dentry *dfs_chk_gen; - struct dentry *dfs_chk_io; - struct dentry *dfs_disable_bgt; - struct dentry *dfs_emulate_bitflips; - struct dentry *dfs_emulate_io_failures; -}; - /** * ubi_dbg_is_bgt_disabled - if the background thread is disabled. * @ubi: UBI device description object @@ -114,7 +74,7 @@ struct ubi_debug_info { */ static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi) { - return ubi->dbg->disable_bgt; + return ubi->dbg.disable_bgt; } /** @@ -125,7 +85,7 @@ static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi) */ static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi) { - if (ubi->dbg->emulate_bitflips) + if (ubi->dbg.emulate_bitflips) return !(random32() % 200); return 0; } @@ -139,7 +99,7 @@ static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi) */ static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi) { - if (ubi->dbg->emulate_io_failures) + if (ubi->dbg.emulate_io_failures) return !(random32() % 500); return 0; } @@ -153,18 +113,18 @@ static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi) */ static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi) { - if (ubi->dbg->emulate_io_failures) + if (ubi->dbg.emulate_io_failures) return !(random32() % 400); return 0; } static inline int ubi_dbg_chk_io(const struct ubi_device *ubi) { - return ubi->dbg->chk_io; + return ubi->dbg.chk_io; } static inline int ubi_dbg_chk_gen(const struct ubi_device *ubi) { - return ubi->dbg->chk_gen; + return ubi->dbg.chk_gen; } #endif /* !__UBI_DEBUG_H__ */ diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 7d57469..8ea6297 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -85,6 +85,13 @@ #define UBI_UNKNOWN -1 /* + * The UBI debugfs directory name pattern and maximum name length (3 for "ubi" + * + 2 for the number plus 1 for the trailing zero byte. + */ +#define UBI_DFS_DIR_NAME "ubi%d" +#define UBI_DFS_DIR_LEN (3 + 2 + 1) + +/* * Error codes returned by the I/O sub-system. * * UBI_IO_FF: the read region of flash contains only 0xFFs @@ -342,6 +349,37 @@ struct ubi_volume_desc { struct ubi_wl_entry; /** + * struct ubi_debug_info - debugging information for an UBI device. + * + * @chk_gen: if UBI general extra checks are enabled + * @chk_io: if UBI I/O extra checks are enabled + * @disable_bgt: disable the background task for testing purposes + * @emulate_bitflips: emulate bit-flips for testing purposes + * @emulate_io_failures: emulate write/erase failures for testing purposes + * @dfs_dir_name: name of debugfs directory containing files of this UBI device + * @dfs_dir: direntry object of the UBI device debugfs directory + * @dfs_chk_gen: debugfs knob to enable UBI general extra checks + * @dfs_chk_io: debugfs knob to enable UBI I/O extra checks + * @dfs_disable_bgt: debugfs knob to disable the background task + * @dfs_emulate_bitflips: debugfs knob to emulate bit-flips + * @dfs_emulate_io_failures: debugfs knob to emulate write/erase failures + */ +struct ubi_debug_info { + unsigned int chk_gen:1; + unsigned int chk_io:1; + unsigned int disable_bgt:1; + unsigned int emulate_bitflips:1; + unsigned int emulate_io_failures:1; + char dfs_dir_name[UBI_DFS_DIR_LEN + 1]; + struct dentry *dfs_dir; + struct dentry *dfs_chk_gen; + struct dentry *dfs_chk_io; + struct dentry *dfs_disable_bgt; + struct dentry *dfs_emulate_bitflips; + struct dentry *dfs_emulate_io_failures; +}; + +/** * struct ubi_device - UBI device description structure * @dev: UBI device object to use the the Linux device model * @cdev: character device object to create character device @@ -545,7 +583,7 @@ struct ubi_device { struct mutex buf_mutex; struct mutex ckvol_mutex; - struct ubi_debug_info *dbg; + struct ubi_debug_info dbg; }; /** -- cgit v0.10.2 From ecfe57b796d4ccec7ea53783ca18a0ad48ad880b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 3 Dec 2012 10:22:35 +0100 Subject: mtd: bcm47xxnflash: writing support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 3314e92..37ffe56 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -461,13 +461,12 @@ config MTD_NAND_GPMI_NAND the GPMI. config MTD_NAND_BCM47XXNFLASH - tristate "R/O support for NAND flash on BCMA bus" + tristate "Support for NAND flash on BCM4706 BCMA bus" depends on BCMA_NFLASH help BCMA bus can have various flash memories attached, they are registered by bcma as platform devices. This enables driver for - NAND flash memories. For now only read mode for BCM4706 is - implemented. + NAND flash memories. For now only BCM4706 is supported. config MTD_NAND_PLATFORM tristate "Support for generic platform NAND driver" diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index ece343c..86c9a79 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -25,6 +25,7 @@ #define NCTL_CMD0 0x00010000 #define NCTL_CMD1W 0x00080000 #define NCTL_READ 0x00100000 +#define NCTL_WRITE 0x00200000 #define NCTL_SPECADDR 0x01000000 #define NCTL_READY 0x04000000 #define NCTL_ERR 0x08000000 @@ -132,6 +133,36 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, } } +static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + struct bcma_drv_cc *cc = b47n->cc; + + u32 ctlcode; + const u32 *data = (u32 *)buf; + int i; + + BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask); + /* Don't validate column using nand_chip->page_shift, it may be bigger + * when accessing OOB */ + + for (i = 0; i < len; i += 4, data++) { + bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data); + + ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE; + if (i == len - 4) /* Last read goes without that */ + ctlcode &= ~NCTL_CSA; + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) { + pr_err("%s ctl_cmd didn't work!\n", __func__); + return; + } + } + + b47n->curr_column += len; +} + /************************************************** * NAND chip ops **************************************************/ @@ -208,6 +239,36 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, if (page_addr != -1) b47n->curr_column += mtd->writesize; break; + case NAND_CMD_ERASE1: + bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, + b47n->curr_page_addr); + ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 | + NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8); + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) + pr_err("ERASE1 failed\n"); + break; + case NAND_CMD_ERASE2: + break; + case NAND_CMD_SEQIN: + /* Set page and column */ + bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR, + b47n->curr_column); + bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, + b47n->curr_page_addr); + + /* Prepare to write */ + ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000; + ctlcode |= NAND_CMD_SEQIN; + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) + pr_err("SEQIN failed\n"); + break; + case NAND_CMD_PAGEPROG: + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 | + NAND_CMD_PAGEPROG)) + pr_err("PAGEPROG failed\n"); + if (bcm47xxnflash_ops_bcm4706_poll(cc)) + pr_err("PAGEPROG not ready\n"); + break; default: pr_err("Command 0x%X unsupported\n", command); break; @@ -259,6 +320,21 @@ static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd, pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command); } +static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd, + const uint8_t *buf, int len) +{ + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + + switch (b47n->curr_command) { + case NAND_CMD_SEQIN: + bcm47xxnflash_ops_bcm4706_write(mtd, buf, len); + return; + } + + pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command); +} + /************************************************** * Init **************************************************/ @@ -278,6 +354,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; + b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ -- cgit v0.10.2 From 6c810f90140a3274181c4093d5dd4c88c6fff0b4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 29 Nov 2012 17:16:51 +0300 Subject: mtg: docg3: potential divide by zero in doc_write_oob() If we set oobdelta to zero then we will either return -EINVAL or hit a divide (modulus) by zero on the next line when we check "(ooblen % oobdelta)". It's better to just return -EINVAL here instead. Signed-off-by: Dan Carpenter Acked-by: Robert Jarzmik Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index d34d83b..8510ccb 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1440,7 +1440,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, oobdelta = mtd->ecclayout->oobavail; break; default: - oobdelta = 0; + return -EINVAL; } if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % oobdelta) || (ofs % DOC_LAYOUT_PAGE_SIZE)) -- cgit v0.10.2 From e58a66d84bceba314b03e37ec0764b9b1b9227d0 Mon Sep 17 00:00:00 2001 From: Anton Prins Date: Tue, 27 Nov 2012 16:38:16 +0100 Subject: mtd: physmap_of: error checking to prevent a NULL pointer dereference This patch solves a NULL pointer dereference, this may occur if the tuple is not mappable (jumps to continue in the for-loop). Out of the loop possible results are: - info->list_size == 0 if no of the tuples is mappable - info->list_size == 1 - info->list_size > 1 If no one of the supplied tuples is mappable (info->list_size == 0) and info->cmtd will not be set. But it is used in mtd_device_parse_register, OOPS! actually it should generate an error in this case! Signed-off-by: Anton Prins Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index cde8bf9..37cdc20 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -285,6 +285,7 @@ static int of_flash_probe(struct platform_device *dev) } err = 0; + info->cmtd = NULL; if (info->list_size == 1) { info->cmtd = info->list[0].mtd; } else if (info->list_size > 1) { @@ -293,9 +294,10 @@ static int of_flash_probe(struct platform_device *dev) */ info->cmtd = mtd_concat_create(mtd_list, info->list_size, dev_name(&dev->dev)); - if (info->cmtd == NULL) - err = -ENXIO; } + if (info->cmtd == NULL) + err = -ENXIO; + if (err) goto err_out; -- cgit v0.10.2 From 5346c27c5fed6b30aff35e1fcb595625097e646c Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 3 Dec 2012 10:31:40 -0300 Subject: mtd: nandsim: Introduce debugfs infrastructure It's more user friendly to report debug information and statistics through debugfs, than to use printing facilites. This patch introduces a very minimal debugfs infrastructure and moves eraseblock wear report to an entry located at: /sys/kernel/debug/nandsim/wear_report This means we can remove rptwear option and just let the user get the wear report when we needs to. Signed-off-by: Ezequiel Garcia Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index a932c48..2ab8274 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include /* Default simulator parameters values */ #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ @@ -105,7 +107,6 @@ static char *weakblocks = NULL; static char *weakpages = NULL; static unsigned int bitflips = 0; static char *gravepages = NULL; -static unsigned int rptwear = 0; static unsigned int overridesize = 0; static char *cache_file = NULL; static unsigned int bbt; @@ -130,7 +131,6 @@ module_param(weakblocks, charp, 0400); module_param(weakpages, charp, 0400); module_param(bitflips, uint, 0400); module_param(gravepages, charp, 0400); -module_param(rptwear, uint, 0400); module_param(overridesize, uint, 0400); module_param(cache_file, charp, 0400); module_param(bbt, uint, 0400); @@ -162,7 +162,6 @@ MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (z MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]" " separated by commas e.g. 1401:2 means page 1401" " can be read only twice before failing"); -MODULE_PARM_DESC(rptwear, "Number of erases between reporting wear, if not zero"); MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " "The size is specified in erase blocks and as the exponent of a power of two" " e.g. 5 means a size of 32 erase blocks"); @@ -286,6 +285,11 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " /* Maximum page cache pages needed to read or write a NAND page to the cache_file */ #define NS_MAX_HELD_PAGES 16 +struct nandsim_debug_info { + struct dentry *dfs_root; + struct dentry *dfs_wear_report; +}; + /* * A union to represent flash memory contents and flash buffer. */ @@ -365,6 +369,8 @@ struct nandsim { void *file_buf; struct page *held_pages[NS_MAX_HELD_PAGES]; int held_cnt; + + struct nandsim_debug_info dbg; }; /* @@ -442,11 +448,123 @@ static LIST_HEAD(grave_pages); static unsigned long *erase_block_wear = NULL; static unsigned int wear_eb_count = 0; static unsigned long total_wear = 0; -static unsigned int rptwear_cnt = 0; /* MTD structure for NAND controller */ static struct mtd_info *nsmtd; +static int nandsim_debugfs_show(struct seq_file *m, void *private) +{ + unsigned long wmin = -1, wmax = 0, avg; + unsigned long deciles[10], decile_max[10], tot = 0; + unsigned int i; + + /* Calc wear stats */ + for (i = 0; i < wear_eb_count; ++i) { + unsigned long wear = erase_block_wear[i]; + if (wear < wmin) + wmin = wear; + if (wear > wmax) + wmax = wear; + tot += wear; + } + + for (i = 0; i < 9; ++i) { + deciles[i] = 0; + decile_max[i] = (wmax * (i + 1) + 5) / 10; + } + deciles[9] = 0; + decile_max[9] = wmax; + for (i = 0; i < wear_eb_count; ++i) { + int d; + unsigned long wear = erase_block_wear[i]; + for (d = 0; d < 10; ++d) + if (wear <= decile_max[d]) { + deciles[d] += 1; + break; + } + } + avg = tot / wear_eb_count; + + /* Output wear report */ + seq_printf(m, "Total numbers of erases: %lu\n", tot); + seq_printf(m, "Number of erase blocks: %u\n", wear_eb_count); + seq_printf(m, "Average number of erases: %lu\n", avg); + seq_printf(m, "Maximum number of erases: %lu\n", wmax); + seq_printf(m, "Minimum number of erases: %lu\n", wmin); + for (i = 0; i < 10; ++i) { + unsigned long from = (i ? decile_max[i - 1] + 1 : 0); + if (from > decile_max[i]) + continue; + seq_printf(m, "Number of ebs with erase counts from %lu to %lu : %lu\n", + from, + decile_max[i], + deciles[i]); + } + + return 0; +} + +static int nandsim_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, nandsim_debugfs_show, inode->i_private); +} + +static const struct file_operations dfs_fops = { + .open = nandsim_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/** + * nandsim_debugfs_create - initialize debugfs + * @dev: nandsim device description object + * + * This function creates all debugfs files for UBI device @ubi. Returns zero in + * case of success and a negative error code in case of failure. + */ +static int nandsim_debugfs_create(struct nandsim *dev) +{ + struct nandsim_debug_info *dbg = &dev->dbg; + struct dentry *dent; + int err; + + if (!IS_ENABLED(CONFIG_DEBUG_FS)) + return 0; + + dent = debugfs_create_dir("nandsim", NULL); + if (IS_ERR_OR_NULL(dent)) { + int err = dent ? -ENODEV : PTR_ERR(dent); + + NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n", + err); + return err; + } + dbg->dfs_root = dent; + + dent = debugfs_create_file("wear_report", S_IRUSR, + dbg->dfs_root, dev, &dfs_fops); + if (IS_ERR_OR_NULL(dent)) + goto out_remove; + dbg->dfs_wear_report = dent; + + return 0; + +out_remove: + debugfs_remove_recursive(dbg->dfs_root); + err = dent ? PTR_ERR(dent) : -ENODEV; + return err; +} + +/** + * nandsim_debugfs_remove - destroy all debugfs files + */ +static void nandsim_debugfs_remove(struct nandsim *ns) +{ + if (IS_ENABLED(CONFIG_DEBUG_FS)) + debugfs_remove_recursive(ns->dbg.dfs_root); +} + /* * Allocate array of page pointers, create slab allocation for an array * and initialize the array by NULL pointers. @@ -911,8 +1029,6 @@ static int setup_wear_reporting(struct mtd_info *mtd) { size_t mem; - if (!rptwear) - return 0; wear_eb_count = div_u64(mtd->size, mtd->erasesize); mem = wear_eb_count * sizeof(unsigned long); if (mem / sizeof(unsigned long) != wear_eb_count) { @@ -929,64 +1045,18 @@ static int setup_wear_reporting(struct mtd_info *mtd) static void update_wear(unsigned int erase_block_no) { - unsigned long wmin = -1, wmax = 0, avg; - unsigned long deciles[10], decile_max[10], tot = 0; - unsigned int i; - if (!erase_block_wear) return; total_wear += 1; + /* + * TODO: Notify this through a debugfs entry, + * instead of showing an error message. + */ if (total_wear == 0) NS_ERR("Erase counter total overflow\n"); erase_block_wear[erase_block_no] += 1; if (erase_block_wear[erase_block_no] == 0) NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no); - rptwear_cnt += 1; - if (rptwear_cnt < rptwear) - return; - rptwear_cnt = 0; - /* Calc wear stats */ - for (i = 0; i < wear_eb_count; ++i) { - unsigned long wear = erase_block_wear[i]; - if (wear < wmin) - wmin = wear; - if (wear > wmax) - wmax = wear; - tot += wear; - } - for (i = 0; i < 9; ++i) { - deciles[i] = 0; - decile_max[i] = (wmax * (i + 1) + 5) / 10; - } - deciles[9] = 0; - decile_max[9] = wmax; - for (i = 0; i < wear_eb_count; ++i) { - int d; - unsigned long wear = erase_block_wear[i]; - for (d = 0; d < 10; ++d) - if (wear <= decile_max[d]) { - deciles[d] += 1; - break; - } - } - avg = tot / wear_eb_count; - /* Output wear report */ - NS_INFO("*** Wear Report ***\n"); - NS_INFO("Total numbers of erases: %lu\n", tot); - NS_INFO("Number of erase blocks: %u\n", wear_eb_count); - NS_INFO("Average number of erases: %lu\n", avg); - NS_INFO("Maximum number of erases: %lu\n", wmax); - NS_INFO("Minimum number of erases: %lu\n", wmin); - for (i = 0; i < 10; ++i) { - unsigned long from = (i ? decile_max[i - 1] + 1 : 0); - if (from > decile_max[i]) - continue; - NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n", - from, - decile_max[i], - deciles[i]); - } - NS_INFO("*** End of Wear Report ***\n"); } /* @@ -2330,6 +2400,9 @@ static int __init ns_init_module(void) if ((retval = setup_wear_reporting(nsmtd)) != 0) goto err_exit; + if ((retval = nandsim_debugfs_create(nand)) != 0) + goto err_exit; + if ((retval = init_nandsim(nsmtd)) != 0) goto err_exit; @@ -2369,6 +2442,7 @@ static void __exit ns_cleanup_module(void) struct nandsim *ns = ((struct nand_chip *)nsmtd->priv)->priv; int i; + nandsim_debugfs_remove(ns); free_nandsim(ns); /* Free nandsim private resources */ nand_release(nsmtd); /* Unregister driver */ for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) -- cgit v0.10.2 From c10d8ee3feaf725007e515b5f2972dffaa793f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Thu, 6 Dec 2012 08:42:27 +0100 Subject: mtd: mxc_nand: fix unbalanced clk_disable() in error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If nand_scan_ident() or nand_scan_tail() fails, the NAND chip may have been deselected and the clock already disabled. Thus, check 'clk_act' in the error path to decide whether the clock still needs to be disabled. This fixes a: |WARNING: at drivers/clk/clk.c:472 __clk_disable+0x3c/0x78() Signed-off-by: Lothar Waßmann Acked-by: Sascha Hauer Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 4aef6a3..ab0fe38 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1533,7 +1533,8 @@ static int mxcnd_probe(struct platform_device *pdev) return 0; escan: - clk_disable_unprepare(host->clk); + if (host->clk_act) + clk_disable_unprepare(host->clk); return err; } -- cgit v0.10.2 From 740bb0c4b0bbeb8970d62157685f6d4a261036a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Thu, 6 Dec 2012 08:42:28 +0100 Subject: mtd: mxc_nand: reorder part_probes to let cmdline override other sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cmdline is the easiest to change source of information. Thus let it take precedence over 'RedBoot' and 'ofpart'. This makes the mxc_nand driver to be in sync with all other NAND drivers that support 'cmdlinepart' partition parsing. Also change 'const char *' to 'const char const *' as advised by checkpatch.pl Signed-off-by: Lothar Waßmann Acked-by: Sascha Hauer Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index ab0fe38..9f10778 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -272,7 +272,8 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = { } }; -static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL }; +static const char const *part_probes[] = { + "cmdlinepart", "RedBoot", "ofpart", NULL }; static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size) { -- cgit v0.10.2 From 516d798f656614f59553b1ff3592c2c36102b684 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 10 Dec 2012 12:18:20 -0800 Subject: Input: matrix-keymap - provide a proper module license The matrix-keymap module is currently lacking a proper module license, add one so we don't have this module tainting the entire kernel. This issue has been present since commit 1932811f (Input: matrix-keymap - uninline and prepare for device tree support) Signed-off-by: Florian Fainelli CC: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c index 443ad64b..d88d9be 100644 --- a/drivers/input/matrix-keymap.c +++ b/drivers/input/matrix-keymap.c @@ -23,6 +23,7 @@ #include #include #include +#include #include static bool matrix_keypad_map_key(struct input_dev *input_dev, @@ -161,3 +162,5 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, return 0; } EXPORT_SYMBOL(matrix_keypad_build_keymap); + +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 9a9c6478a8b6ce8b6da6b6d1e15f365b505895cd Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 4 Dec 2012 14:29:27 +0300 Subject: nfsd: make NFSv4 recovery client tracking options per net Pointer to client tracking operations - client_tracking_ops - have to be containerized, because different environment can support different trackers (for example, legacy tracker currently is not suported in container). Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 964b554..fac4123c 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -35,6 +35,7 @@ #define SESSION_HASH_SIZE 512 struct cld_net; +struct nfsd4_client_tracking_ops; struct nfsd_net { struct cld_net *cld_net; @@ -87,6 +88,7 @@ struct nfsd_net { struct file *rec_file; bool in_grace; + struct nfsd4_client_tracking_ops *client_tracking_ops; time_t nfsd4_lease; time_t nfsd4_grace; diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 359793f..ba6fdd4 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -63,7 +63,6 @@ struct nfsd4_client_tracking_ops { /* Globals */ static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; -static struct nfsd4_client_tracking_ops *client_tracking_ops; static int nfs4_save_creds(const struct cred **original_creds) @@ -1262,17 +1261,18 @@ nfsd4_client_tracking_init(struct net *net) { int status; struct path path; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); /* just run the init if it the method is already decided */ - if (client_tracking_ops) + if (nn->client_tracking_ops) goto do_init; /* * First, try a UMH upcall. It should succeed or fail quickly, so * there's little harm in trying that first. */ - client_tracking_ops = &nfsd4_umh_tracking_ops; - status = client_tracking_ops->init(net); + nn->client_tracking_ops = &nfsd4_umh_tracking_ops; + status = nn->client_tracking_ops->init(net); if (!status) return status; @@ -1280,7 +1280,7 @@ nfsd4_client_tracking_init(struct net *net) * See if the recoverydir exists and is a directory. If it is, * then use the legacy ops. */ - client_tracking_ops = &nfsd4_legacy_tracking_ops; + nn->client_tracking_ops = &nfsd4_legacy_tracking_ops; status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path); if (!status) { status = S_ISDIR(path.dentry->d_inode->i_mode); @@ -1290,16 +1290,16 @@ nfsd4_client_tracking_init(struct net *net) } /* Finally, try to use nfsdcld */ - client_tracking_ops = &nfsd4_cld_tracking_ops; + nn->client_tracking_ops = &nfsd4_cld_tracking_ops; printk(KERN_WARNING "NFSD: the nfsdcld client tracking upcall will be " "removed in 3.10. Please transition to using " "nfsdcltrack.\n"); do_init: - status = client_tracking_ops->init(net); + status = nn->client_tracking_ops->init(net); if (status) { printk(KERN_WARNING "NFSD: Unable to initialize client " "recovery tracking! (%d)\n", status); - client_tracking_ops = NULL; + nn->client_tracking_ops = NULL; } return status; } @@ -1307,32 +1307,40 @@ do_init: void nfsd4_client_tracking_exit(struct net *net) { - if (client_tracking_ops) { - if (client_tracking_ops->exit) - client_tracking_ops->exit(net); - client_tracking_ops = NULL; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + if (nn->client_tracking_ops) { + if (nn->client_tracking_ops->exit) + nn->client_tracking_ops->exit(net); + nn->client_tracking_ops = NULL; } } void nfsd4_client_record_create(struct nfs4_client *clp) { - if (client_tracking_ops) - client_tracking_ops->create(clp); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + + if (nn->client_tracking_ops) + nn->client_tracking_ops->create(clp); } void nfsd4_client_record_remove(struct nfs4_client *clp) { - if (client_tracking_ops) - client_tracking_ops->remove(clp); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + + if (nn->client_tracking_ops) + nn->client_tracking_ops->remove(clp); } int nfsd4_client_record_check(struct nfs4_client *clp) { - if (client_tracking_ops) - return client_tracking_ops->check(clp); + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + + if (nn->client_tracking_ops) + return nn->client_tracking_ops->check(clp); return -EOPNOTSUPP; } @@ -1340,8 +1348,8 @@ nfsd4_client_record_check(struct nfs4_client *clp) void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time) { - if (client_tracking_ops) - client_tracking_ops->grace_done(nn, boot_time); + if (nn->client_tracking_ops) + nn->client_tracking_ops->grace_done(nn, boot_time); } static int -- cgit v0.10.2 From 756933ee8a75970ca7d8a10e922f5d44720457a4 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 4 Dec 2012 15:18:58 +0300 Subject: SUNRPC: remove redundant "linux/nsproxy.h" includes This is a cleanup patch. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index a70acae..109a67a 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index be301e1..529400d 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From 7007c90fb9fef593b4aeaeee57e6a6754276c97c Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Fri, 7 Dec 2012 15:40:55 -0500 Subject: nfsd: avoid permission checks on EXCLUSIVE_CREATE replay With NFSv4, if we create a file then open it we explicit avoid checking the permissions on the file during the open because the fact that we created it ensures we should be allow to open it (the create and the open should appear to be a single operation). However if the reply to an EXCLUSIVE create gets lots and the client resends the create, the current code will perform the permission check - because it doesn't realise that it did the open already.. This patch should fix this. Note that I haven't actually seen this cause a problem. I was just looking at the code trying to figure out a different EXCLUSIVE open related issue, and this looked wrong. (Fix confirmed with pynfs 4.0 test OPEN4--bfields) Cc: stable@kernel.org Signed-off-by: NeilBrown [bfields: use OWNER_OVERRIDE and update for 4.1] Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 87d24e5..1a0b1fd 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -195,6 +195,7 @@ static __be32 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) { struct svc_fh *resfh; + int accmode; __be32 status; resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); @@ -254,9 +255,10 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o /* set reply cache */ fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, &resfh->fh_handle); - if (!open->op_created) - status = do_open_permission(rqstp, resfh, open, - NFSD_MAY_NOP); + accmode = NFSD_MAY_NOP; + if (open->op_created) + accmode |= NFSD_MAY_OWNER_OVERRIDE; + status = do_open_permission(rqstp, resfh, open, accmode); set_change_info(&open->op_cinfo, current_fh); fh_dup2(current_fh, resfh); out: diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index b584205..0ef9b6b 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1471,13 +1471,19 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, case NFS3_CREATE_EXCLUSIVE: if ( dchild->d_inode->i_mtime.tv_sec == v_mtime && dchild->d_inode->i_atime.tv_sec == v_atime - && dchild->d_inode->i_size == 0 ) + && dchild->d_inode->i_size == 0 ) { + if (created) + *created = 1; break; + } case NFS4_CREATE_EXCLUSIVE4_1: if ( dchild->d_inode->i_mtime.tv_sec == v_mtime && dchild->d_inode->i_atime.tv_sec == v_atime - && dchild->d_inode->i_size == 0 ) + && dchild->d_inode->i_size == 0 ) { + if (created) + *created = 1; goto set_attr; + } /* fallthru */ case NFS3_CREATE_GUARDED: err = nfserr_exist; -- cgit v0.10.2 From f7fb86c6e639360ad9c253cec534819ef928a674 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 10 Dec 2012 12:19:04 +0300 Subject: nfsd: use "init_net" for portmapper There could be a situation, when NFSd was started in one network namespace, but stopped in another one. This will trigger kernel panic, because RPCBIND client is stored on per-net NFSd data, and will be NULL on NFSd shutdown. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index b34a67d8..9beace6 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -341,7 +340,7 @@ static int nfsd_get_default_max_blksize(void) int nfsd_create_serv(void) { int error; - struct net *net = current->nsproxy->net_ns; + struct net *net = &init_net; WARN_ON(!mutex_is_locked(&nfsd_mutex)); if (nfsd_serv) { -- cgit v0.10.2 From db6e182c17cb1a7069f7f8924721ce58ac05d9a3 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 10 Dec 2012 12:19:09 +0300 Subject: nfsd: pass net to nfsd_init_socks() Precursor patch. Hard-coded "init_net" will be replaced by proper one in future. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 9beace6..9fd8496 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -182,18 +182,18 @@ int nfsd_nrthreads(void) return rv; } -static int nfsd_init_socks(void) +static int nfsd_init_socks(struct net *net) { int error; if (!list_empty(&nfsd_serv->sv_permsocks)) return 0; - error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, NFS_PORT, + error = svc_create_xprt(nfsd_serv, "udp", net, PF_INET, NFS_PORT, SVC_SOCK_DEFAULTS); if (error < 0) return error; - error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, NFS_PORT, + error = svc_create_xprt(nfsd_serv, "tcp", net, PF_INET, NFS_PORT, SVC_SOCK_DEFAULTS); if (error < 0) return error; @@ -218,7 +218,7 @@ static int nfsd_startup(int nrservs) ret = nfsd_racache_init(2*nrservs); if (ret) return ret; - ret = nfsd_init_socks(); + ret = nfsd_init_socks(net); if (ret) goto out_racache; ret = lockd_up(net); -- cgit v0.10.2 From db42d1a76a8dfcaba7a2dc9c591fa4e231db22b3 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 10 Dec 2012 12:19:14 +0300 Subject: nfsd: pass net to nfsd_startup() and nfsd_shutdown() Precursor patch. Hard-coded "init_net" will be replaced by proper one in future. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 9fd8496..21cba3d 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -203,10 +203,9 @@ static int nfsd_init_socks(struct net *net) static bool nfsd_up = false; -static int nfsd_startup(int nrservs) +static int nfsd_startup(int nrservs, struct net *net) { int ret; - struct net *net = &init_net; if (nfsd_up) return 0; @@ -237,16 +236,14 @@ static int nfsd_startup(int nrservs) out_net_state: nfs4_state_shutdown(); out_lockd: - lockd_down(&init_net); + lockd_down(net); out_racache: nfsd_racache_shutdown(); return ret; } -static void nfsd_shutdown(void) +static void nfsd_shutdown(struct net *net) { - struct net *net = &init_net; - /* * write_ports can create the server without actually starting * any threads--if we get shut down before any threads are @@ -264,7 +261,7 @@ static void nfsd_shutdown(void) static void nfsd_last_thread(struct svc_serv *serv, struct net *net) { - nfsd_shutdown(); + nfsd_shutdown(net); svc_rpcb_cleanup(serv, net); @@ -468,7 +465,7 @@ nfsd_svc(int nrservs) nfsd_up_before = nfsd_up; - error = nfsd_startup(nrservs); + error = nfsd_startup(nrservs, net); if (error) goto out_destroy; error = svc_set_num_threads(nfsd_serv, NULL, nrservs); @@ -481,7 +478,7 @@ nfsd_svc(int nrservs) error = nfsd_serv->sv_nrthreads - 1; out_shutdown: if (error < 0 && !nfsd_up_before) - nfsd_shutdown(); + nfsd_shutdown(net); out_destroy: nfsd_destroy(net); /* Release server */ out: -- cgit v0.10.2 From 6777436b0f072fb20a025a73e9b67a35ad8a5451 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 10 Dec 2012 12:19:20 +0300 Subject: nfsd: pass net to nfsd_create_serv() Precursor patch. Hard-coded "init_net" will be replaced by proper one in future. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index e13cbdd..ae1d143 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -664,7 +664,7 @@ static ssize_t __write_ports_addfd(char *buf) if (err != 0 || fd < 0) return -EINVAL; - err = nfsd_create_serv(); + err = nfsd_create_serv(net); if (err != 0) return err; @@ -696,7 +696,7 @@ static ssize_t __write_ports_addxprt(char *buf) if (port < 1 || port > USHRT_MAX) return -EINVAL; - err = nfsd_create_serv(); + err = nfsd_create_serv(net); if (err != 0) return err; diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 5eea0f5..acddf71 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -103,7 +103,7 @@ enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; int nfsd_vers(int vers, enum vers_op change); int nfsd_minorversion(u32 minorversion, enum vers_op change); void nfsd_reset_versions(void); -int nfsd_create_serv(void); +int nfsd_create_serv(struct net *net); extern int nfsd_max_blksize; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 21cba3d..6448391 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -334,10 +334,9 @@ static int nfsd_get_default_max_blksize(void) return ret; } -int nfsd_create_serv(void) +int nfsd_create_serv(struct net *net) { int error; - struct net *net = &init_net; WARN_ON(!mutex_is_locked(&nfsd_mutex)); if (nfsd_serv) { @@ -459,7 +458,7 @@ nfsd_svc(int nrservs) if (nrservs == 0 && nfsd_serv == NULL) goto out; - error = nfsd_create_serv(); + error = nfsd_create_serv(net); if (error) goto out; -- cgit v0.10.2 From d41a9417cd89a69f58a26935034b4264a2d882d6 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 10 Dec 2012 12:19:25 +0300 Subject: nfsd: pass net to nfsd_svc() Precursor patch. Hard-coded "init_net" will be replaced by proper one in future. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index ae1d143..68e229c 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -396,6 +396,8 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) { char *mesg = buf; int rv; + struct net *net = &init_net; + if (size > 0) { int newthreads; rv = get_int(&mesg, &newthreads); @@ -403,7 +405,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) return rv; if (newthreads < 0) return -EINVAL; - rv = nfsd_svc(newthreads); + rv = nfsd_svc(newthreads, net); if (rv < 0) return rv; } else diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index acddf71..8226c1b 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -65,7 +65,7 @@ extern const struct seq_operations nfs_exports_op; /* * Function prototypes. */ -int nfsd_svc(int nrservs); +int nfsd_svc(int nrservs, struct net *net); int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); int nfsd_nrthreads(void); diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 6448391..f199b53 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -442,11 +442,10 @@ int nfsd_set_nrthreads(int n, int *nthreads) * this is the first time nrservs is nonzero. */ int -nfsd_svc(int nrservs) +nfsd_svc(int nrservs, struct net *net) { int error; bool nfsd_up_before; - struct net *net = &init_net; mutex_lock(&nfsd_mutex); dprintk("nfsd: creating service\n"); -- cgit v0.10.2 From 3938a0d5eb5effcc89c6909741403f4e6a37252d Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 10 Dec 2012 12:19:30 +0300 Subject: nfsd: pass net to nfsd_set_nrthreads() Precursor patch. Hard-coded "init_net" will be replaced by proper one in future. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 68e229c..58f0ae4 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -447,6 +447,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) int len; int npools; int *nthreads; + struct net *net = &init_net; mutex_lock(&nfsd_mutex); npools = nfsd_nrpools(); @@ -477,7 +478,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) if (nthreads[i] < 0) goto out_free; } - rv = nfsd_set_nrthreads(i, nthreads); + rv = nfsd_set_nrthreads(i, nthreads, net); if (rv) goto out_free; } diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 8226c1b..18f9996 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -71,7 +71,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); int nfsd_nrthreads(void); int nfsd_nrpools(void); int nfsd_get_nrthreads(int n, int *); -int nfsd_set_nrthreads(int n, int *); +int nfsd_set_nrthreads(int n, int *, struct net *); int nfsd_pool_stats_open(struct inode *, struct file *); int nfsd_pool_stats_release(struct inode *, struct file *); diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index f199b53..b144658 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -382,12 +382,11 @@ int nfsd_get_nrthreads(int n, int *nthreads) return 0; } -int nfsd_set_nrthreads(int n, int *nthreads) +int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) { int i = 0; int tot = 0; int err = 0; - struct net *net = &init_net; WARN_ON(!mutex_is_locked(&nfsd_mutex)); -- cgit v0.10.2 From 081603520b25f7b35ef63a363376a17c36ef74ed Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 10 Dec 2012 12:19:35 +0300 Subject: nfsd: pass net to __write_ports() and down Precursor patch. Hard-coded "init_net" will be replaced by proper one in future. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 58f0ae4..8536100 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -657,11 +657,10 @@ static ssize_t __write_ports_names(char *buf) * a socket of a supported family/protocol, and we use it as an * nfsd listener. */ -static ssize_t __write_ports_addfd(char *buf) +static ssize_t __write_ports_addfd(char *buf, struct net *net) { char *mesg = buf; int fd, err; - struct net *net = &init_net; err = get_int(&mesg, &fd); if (err != 0 || fd < 0) @@ -686,12 +685,11 @@ static ssize_t __write_ports_addfd(char *buf) * A transport listener is added by writing it's transport name and * a port number. */ -static ssize_t __write_ports_addxprt(char *buf) +static ssize_t __write_ports_addxprt(char *buf, struct net *net) { char transport[16]; struct svc_xprt *xprt; int port, err; - struct net *net = &init_net; if (sscanf(buf, "%15s %5u", transport, &port) != 2) return -EINVAL; @@ -727,16 +725,17 @@ out_err: return err; } -static ssize_t __write_ports(struct file *file, char *buf, size_t size) +static ssize_t __write_ports(struct file *file, char *buf, size_t size, + struct net *net) { if (size == 0) return __write_ports_names(buf); if (isdigit(buf[0])) - return __write_ports_addfd(buf); + return __write_ports_addfd(buf, net); if (isalpha(buf[0])) - return __write_ports_addxprt(buf); + return __write_ports_addxprt(buf, net); return -EINVAL; } @@ -787,9 +786,10 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) static ssize_t write_ports(struct file *file, char *buf, size_t size) { ssize_t rv; + struct net *net = &init_net; mutex_lock(&nfsd_mutex); - rv = __write_ports(file, buf, size); + rv = __write_ports(file, buf, size, net); mutex_unlock(&nfsd_mutex); return rv; } -- cgit v0.10.2 From 6ff50b3dea9a242b50642a703b513986bffb8ce9 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 6 Dec 2012 14:23:09 +0300 Subject: nfsd: move per-net startup code to separated function NFSd resources are partially per-net and partially globally used. This patch splits resources init and shutdown and moves per-net code to separated functions. Generic and per-net init and shutdown are called sequentially for a while. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index b144658..038348b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -203,6 +203,27 @@ static int nfsd_init_socks(struct net *net) static bool nfsd_up = false; +static int nfsd_startup_net(struct net *net) +{ + int ret; + + ret = nfsd_init_socks(net); + if (ret) + return ret; + ret = lockd_up(net); + if (ret) + return ret; + ret = nfs4_state_start_net(net); + if (ret) + goto out_lockd; + + return 0; + +out_lockd: + lockd_down(net); + return ret; +} + static int nfsd_startup(int nrservs, struct net *net) { int ret; @@ -217,31 +238,29 @@ static int nfsd_startup(int nrservs, struct net *net) ret = nfsd_racache_init(2*nrservs); if (ret) return ret; - ret = nfsd_init_socks(net); - if (ret) - goto out_racache; - ret = lockd_up(net); - if (ret) - goto out_racache; ret = nfs4_state_start(); if (ret) - goto out_lockd; - - ret = nfs4_state_start_net(net); + goto out_racache; + ret = nfsd_startup_net(net); if (ret) - goto out_net_state; + goto out_net; nfsd_up = true; return 0; -out_net_state: + +out_net: nfs4_state_shutdown(); -out_lockd: - lockd_down(net); out_racache: nfsd_racache_shutdown(); return ret; } +static void nfsd_shutdown_net(struct net *net) +{ + nfs4_state_shutdown_net(net); + lockd_down(net); +} + static void nfsd_shutdown(struct net *net) { /* @@ -252,9 +271,8 @@ static void nfsd_shutdown(struct net *net) */ if (!nfsd_up) return; - nfs4_state_shutdown_net(net); + nfsd_shutdown_net(net); nfs4_state_shutdown(); - lockd_down(net); nfsd_racache_shutdown(); nfsd_up = false; } -- cgit v0.10.2 From 2c2fe2909e124c32a34dbbb3ac129112524fc540 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 6 Dec 2012 14:23:14 +0300 Subject: nfsd: per-net NFSd up flag introduced This patch introduces introduces per-net "nfsd_net_up" boolean flag, which has the same purpose as general "nfsd_up" flag - skip init or shutdown of per-net resources in case of they are inited on shutted down respectively. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index fac4123c..543ac48 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -92,6 +92,8 @@ struct nfsd_net { time_t nfsd4_lease; time_t nfsd4_grace; + + bool nfsd_net_up; }; /* Simple check to find out if a given net was properly initialized */ diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 038348b..6e17efd 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -21,6 +21,7 @@ #include "nfsd.h" #include "cache.h" #include "vfs.h" +#include "netns.h" #define NFSDDBG_FACILITY NFSDDBG_SVC @@ -205,8 +206,12 @@ static bool nfsd_up = false; static int nfsd_startup_net(struct net *net) { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); int ret; + if (nn->nfsd_net_up) + return 0; + ret = nfsd_init_socks(net); if (ret) return ret; @@ -217,6 +222,7 @@ static int nfsd_startup_net(struct net *net) if (ret) goto out_lockd; + nn->nfsd_net_up = true; return 0; out_lockd: @@ -257,8 +263,14 @@ out_racache: static void nfsd_shutdown_net(struct net *net) { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + if (!nn->nfsd_net_up) + return; + nfs4_state_shutdown_net(net); lockd_down(net); + nn->nfsd_net_up = false; } static void nfsd_shutdown(struct net *net) -- cgit v0.10.2 From b9c0ef8571c6ae33465dcf41d496ce2ad783c49d Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 6 Dec 2012 14:23:19 +0300 Subject: nfsd: make NFSd service boot time per-net This is simple: an NFSd service can be started at different times in different network environments. So, its "boot time" has to be assigned per net. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 543ac48..3b283ea 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -94,6 +94,11 @@ struct nfsd_net { time_t nfsd4_grace; bool nfsd_net_up; + + /* + * Time of server startup + */ + struct timeval nfssvc_boot; }; /* Simple check to find out if a given net was properly initialized */ diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 43f46cd..2b8618d 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -7,8 +7,10 @@ */ #include +#include #include "xdr3.h" #include "auth.h" +#include "netns.h" #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -720,12 +722,14 @@ int nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_writeres *resp) { + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + p = encode_wcc_data(rqstp, p, &resp->fh); if (resp->status == 0) { *p++ = htonl(resp->count); *p++ = htonl(resp->committed); - *p++ = htonl(nfssvc_boot.tv_sec); - *p++ = htonl(nfssvc_boot.tv_usec); + *p++ = htonl(nn->nfssvc_boot.tv_sec); + *p++ = htonl(nn->nfssvc_boot.tv_usec); } return xdr_ressize_check(rqstp, p); } @@ -1082,11 +1086,13 @@ int nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p, struct nfsd3_commitres *resp) { + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + p = encode_wcc_data(rqstp, p, &resp->fh); /* Write verifier */ if (resp->status == 0) { - *p++ = htonl(nfssvc_boot.tv_sec); - *p++ = htonl(nfssvc_boot.tv_usec); + *p++ = htonl(nn->nfssvc_boot.tv_sec); + *p++ = htonl(nn->nfssvc_boot.tv_usec); } return xdr_ressize_check(rqstp, p); } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 1a0b1fd..bd67f4d 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -497,12 +497,13 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, &access->ac_supported); } -static void gen_boot_verifier(nfs4_verifier *verifier) +static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) { __be32 verf[2]; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); - verf[0] = (__be32)nfssvc_boot.tv_sec; - verf[1] = (__be32)nfssvc_boot.tv_usec; + verf[0] = (__be32)nn->nfssvc_boot.tv_sec; + verf[1] = (__be32)nn->nfssvc_boot.tv_usec; memcpy(verifier->data, verf, sizeof(verifier->data)); } @@ -510,7 +511,7 @@ static __be32 nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_commit *commit) { - gen_boot_verifier(&commit->co_verf); + gen_boot_verifier(&commit->co_verf, SVC_NET(rqstp)); return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, commit->co_count); } @@ -930,7 +931,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, cnt = write->wr_buflen; write->wr_how_written = write->wr_stable_how; - gen_boot_verifier(&write->wr_verifier); + gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp)); nvecs = fill_in_write_vector(rqstp->rq_vec, write); WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 18f9996..71ba60d 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -269,11 +269,6 @@ void nfsd_lockd_shutdown(void); /* Check for dir entries '.' and '..' */ #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) -/* - * Time of server startup - */ -extern struct timeval nfssvc_boot; - #ifdef CONFIG_NFSD_V4 /* before processing a COMPOUND operation, we have to check that there diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 6e17efd..40992cd 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -27,7 +27,6 @@ extern struct svc_program nfsd_program; static int nfsd(void *vrqstp); -struct timeval nfssvc_boot; /* * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members @@ -367,6 +366,7 @@ static int nfsd_get_default_max_blksize(void) int nfsd_create_serv(struct net *net) { int error; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); WARN_ON(!mutex_is_locked(&nfsd_mutex)); if (nfsd_serv) { @@ -388,7 +388,7 @@ int nfsd_create_serv(struct net *net) } set_max_drc(); - do_gettimeofday(&nfssvc_boot); /* record boot time */ + do_gettimeofday(&nn->nfssvc_boot); /* record boot time */ return 0; } -- cgit v0.10.2 From 9dd9845f084cda07ce00cca32a5ba8fbcbbfbcaf Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 6 Dec 2012 14:23:24 +0300 Subject: nfsd: make NFSd service structure allocated per net This patch makes main step in NFSd containerisation. There could be different approaches to how to make NFSd able to handle incoming RPC request from different network namespaces. The two main options are: 1) Share NFSd kthreads betwween all network namespaces. 2) Create separated pool of threads for each namespace. While first approach looks more flexible, second one is simpler and non-racy. This patch implements the second option. To make it possible to allocate separate pools of threads, we have to make it possible to allocate separate NFSd service structures per net. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 3b283ea..1051beb 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -99,6 +99,8 @@ struct nfsd_net { * Time of server startup */ struct timeval nfssvc_boot; + + struct svc_serv *nfsd_serv; }; /* Simple check to find out if a given net was properly initialized */ diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 16e954c..3d27f08 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -743,9 +743,12 @@ out_free: return NULL; } -static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize) +static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, + struct nfsd4_channel_attrs *req, + int numslots, int slotsize, + struct nfsd_net *nn) { - u32 maxrpc = nfsd_serv->sv_max_mesg; + u32 maxrpc = nn->nfsd_serv->sv_max_mesg; new->maxreqs = numslots; new->maxresp_cached = min_t(u32, req->maxresp_cached, @@ -883,7 +886,8 @@ void nfsd4_put_session(struct nfsd4_session *ses) spin_unlock(&nn->client_lock); } -static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) +static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan, + struct nfsd_net *nn) { struct nfsd4_session *new; int numslots, slotsize; @@ -904,7 +908,7 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan) nfsd4_put_drc_mem(slotsize, fchan->maxreqs); return NULL; } - init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize); + init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize, nn); return new; } @@ -1776,7 +1780,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, return nfserr_inval; if (check_forechannel_attrs(cr_ses->fore_channel)) return nfserr_toosmall; - new = alloc_session(&cr_ses->fore_channel); + new = alloc_session(&cr_ses->fore_channel, nn); if (!new) return nfserr_jukebox; status = nfserr_jukebox; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 8536100..7493428 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -409,7 +409,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) if (rv < 0) return rv; } else - rv = nfsd_nrthreads(); + rv = nfsd_nrthreads(net); return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); } @@ -450,7 +450,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) struct net *net = &init_net; mutex_lock(&nfsd_mutex); - npools = nfsd_nrpools(); + npools = nfsd_nrpools(net); if (npools == 0) { /* * NFS is shut down. The admin can start it by @@ -483,7 +483,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) goto out_free; } - rv = nfsd_get_nrthreads(npools, nthreads); + rv = nfsd_get_nrthreads(npools, nthreads, net); if (rv) goto out_free; @@ -510,11 +510,13 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) unsigned minor; ssize_t tlen = 0; char *sep; + struct net *net = &init_net; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); if (size>0) { - if (nfsd_serv) + if (nn->nfsd_serv) /* Cannot change versions without updating - * nfsd_serv->sv_xdrsize, and reallocing + * nn->nfsd_serv->sv_xdrsize, and reallocing * rq_argp and rq_resp */ return -EBUSY; @@ -645,11 +647,13 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) * Zero-length write. Return a list of NFSD's current listener * transports. */ -static ssize_t __write_ports_names(char *buf) +static ssize_t __write_ports_names(char *buf, struct net *net) { - if (nfsd_serv == NULL) + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + if (nn->nfsd_serv == NULL) return 0; - return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); + return svc_xprt_names(nn->nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); } /* @@ -661,6 +665,7 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net) { char *mesg = buf; int fd, err; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); err = get_int(&mesg, &fd); if (err != 0 || fd < 0) @@ -670,14 +675,14 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net) if (err != 0) return err; - err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); + err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); if (err < 0) { nfsd_destroy(net); return err; } /* Decrease the count, but don't shut down the service */ - nfsd_serv->sv_nrthreads--; + nn->nfsd_serv->sv_nrthreads--; return err; } @@ -690,6 +695,7 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net) char transport[16]; struct svc_xprt *xprt; int port, err; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); if (sscanf(buf, "%15s %5u", transport, &port) != 2) return -EINVAL; @@ -701,21 +707,21 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net) if (err != 0) return err; - err = svc_create_xprt(nfsd_serv, transport, net, + err = svc_create_xprt(nn->nfsd_serv, transport, net, PF_INET, port, SVC_SOCK_ANONYMOUS); if (err < 0) goto out_err; - err = svc_create_xprt(nfsd_serv, transport, net, + err = svc_create_xprt(nn->nfsd_serv, transport, net, PF_INET6, port, SVC_SOCK_ANONYMOUS); if (err < 0 && err != -EAFNOSUPPORT) goto out_close; /* Decrease the count, but don't shut down the service */ - nfsd_serv->sv_nrthreads--; + nn->nfsd_serv->sv_nrthreads--; return 0; out_close: - xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port); + xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port); if (xprt != NULL) { svc_close_xprt(xprt); svc_xprt_put(xprt); @@ -729,7 +735,7 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size, struct net *net) { if (size == 0) - return __write_ports_names(buf); + return __write_ports_names(buf, net); if (isdigit(buf[0])) return __write_ports_addfd(buf, net); @@ -821,6 +827,9 @@ int nfsd_max_blksize; static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) { char *mesg = buf; + struct net *net = &init_net; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + if (size > 0) { int bsize; int rv = get_int(&mesg, &bsize); @@ -835,7 +844,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) bsize = NFSSVC_MAXBLKSIZE; bsize &= ~(1024-1); mutex_lock(&nfsd_mutex); - if (nfsd_serv) { + if (nn->nfsd_serv) { mutex_unlock(&nfsd_mutex); return -EBUSY; } @@ -848,13 +857,14 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) } #ifdef CONFIG_NFSD_V4 -static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time) +static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, + time_t *time, struct nfsd_net *nn) { char *mesg = buf; int rv, i; if (size > 0) { - if (nfsd_serv) + if (nn->nfsd_serv) return -EBUSY; rv = get_int(&mesg, &i); if (rv) @@ -879,12 +889,13 @@ static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, tim return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time); } -static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time) +static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, + time_t *time, struct nfsd_net *nn) { ssize_t rv; mutex_lock(&nfsd_mutex); - rv = __nfsd4_write_time(file, buf, size, time); + rv = __nfsd4_write_time(file, buf, size, time, nn); mutex_unlock(&nfsd_mutex); return rv; } @@ -913,7 +924,7 @@ static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_ static ssize_t write_leasetime(struct file *file, char *buf, size_t size) { struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); - return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease); + return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn); } /** @@ -929,17 +940,18 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size) static ssize_t write_gracetime(struct file *file, char *buf, size_t size) { struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); - return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace); + return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn); } -static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) +static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size, + struct nfsd_net *nn) { char *mesg = buf; char *recdir; int len, status; if (size > 0) { - if (nfsd_serv) + if (nn->nfsd_serv) return -EBUSY; if (size > PATH_MAX || buf[size-1] != '\n') return -EINVAL; @@ -983,9 +995,10 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) { ssize_t rv; + struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); mutex_lock(&nfsd_mutex); - rv = __write_recoverydir(file, buf, size); + rv = __write_recoverydir(file, buf, size, nn); mutex_unlock(&nfsd_mutex); return rv; } diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 71ba60d..de23db2 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -55,7 +55,6 @@ extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; extern u32 nfsd_supported_minorversion; extern struct mutex nfsd_mutex; -extern struct svc_serv *nfsd_serv; extern spinlock_t nfsd_drc_lock; extern unsigned int nfsd_drc_max_mem; extern unsigned int nfsd_drc_mem_used; @@ -68,23 +67,14 @@ extern const struct seq_operations nfs_exports_op; int nfsd_svc(int nrservs, struct net *net); int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); -int nfsd_nrthreads(void); -int nfsd_nrpools(void); -int nfsd_get_nrthreads(int n, int *); +int nfsd_nrthreads(struct net *); +int nfsd_nrpools(struct net *); +int nfsd_get_nrthreads(int n, int *, struct net *); int nfsd_set_nrthreads(int n, int *, struct net *); int nfsd_pool_stats_open(struct inode *, struct file *); int nfsd_pool_stats_release(struct inode *, struct file *); -static inline void nfsd_destroy(struct net *net) -{ - int destroy = (nfsd_serv->sv_nrthreads == 1); - - if (destroy) - svc_shutdown_net(nfsd_serv, net); - svc_destroy(nfsd_serv); - if (destroy) - nfsd_serv = NULL; -} +void nfsd_destroy(struct net *net); #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) #ifdef CONFIG_NFSD_V2_ACL diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 40992cd..0e8622a 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -29,11 +29,11 @@ extern struct svc_program nfsd_program; static int nfsd(void *vrqstp); /* - * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members + * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members * of the svc_serv struct. In particular, ->sv_nrthreads but also to some * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt * - * If (out side the lock) nfsd_serv is non-NULL, then it must point to a + * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number * of nfsd threads must exist and each must listed in ->sp_all_threads in each * entry of ->sv_pools[]. @@ -51,7 +51,6 @@ static int nfsd(void *vrqstp); * nfsd_versions */ DEFINE_MUTEX(nfsd_mutex); -struct svc_serv *nfsd_serv; /* * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used. @@ -172,12 +171,14 @@ int nfsd_minorversion(u32 minorversion, enum vers_op change) */ #define NFSD_MAXSERVS 8192 -int nfsd_nrthreads(void) +int nfsd_nrthreads(struct net *net) { int rv = 0; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + mutex_lock(&nfsd_mutex); - if (nfsd_serv) - rv = nfsd_serv->sv_nrthreads; + if (nn->nfsd_serv) + rv = nn->nfsd_serv->sv_nrthreads; mutex_unlock(&nfsd_mutex); return rv; } @@ -185,15 +186,17 @@ int nfsd_nrthreads(void) static int nfsd_init_socks(struct net *net) { int error; - if (!list_empty(&nfsd_serv->sv_permsocks)) + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + if (!list_empty(&nn->nfsd_serv->sv_permsocks)) return 0; - error = svc_create_xprt(nfsd_serv, "udp", net, PF_INET, NFS_PORT, + error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT, SVC_SOCK_DEFAULTS); if (error < 0) return error; - error = svc_create_xprt(nfsd_serv, "tcp", net, PF_INET, NFS_PORT, + error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT, SVC_SOCK_DEFAULTS); if (error < 0) return error; @@ -369,21 +372,21 @@ int nfsd_create_serv(struct net *net) struct nfsd_net *nn = net_generic(net, nfsd_net_id); WARN_ON(!mutex_is_locked(&nfsd_mutex)); - if (nfsd_serv) { - svc_get(nfsd_serv); + if (nn->nfsd_serv) { + svc_get(nn->nfsd_serv); return 0; } if (nfsd_max_blksize == 0) nfsd_max_blksize = nfsd_get_default_max_blksize(); nfsd_reset_versions(); - nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, + nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, nfsd_last_thread, nfsd, THIS_MODULE); - if (nfsd_serv == NULL) + if (nn->nfsd_serv == NULL) return -ENOMEM; - error = svc_bind(nfsd_serv, net); + error = svc_bind(nn->nfsd_serv, net); if (error < 0) { - svc_destroy(nfsd_serv); + svc_destroy(nn->nfsd_serv); return error; } @@ -392,39 +395,55 @@ int nfsd_create_serv(struct net *net) return 0; } -int nfsd_nrpools(void) +int nfsd_nrpools(struct net *net) { - if (nfsd_serv == NULL) + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + if (nn->nfsd_serv == NULL) return 0; else - return nfsd_serv->sv_nrpools; + return nn->nfsd_serv->sv_nrpools; } -int nfsd_get_nrthreads(int n, int *nthreads) +int nfsd_get_nrthreads(int n, int *nthreads, struct net *net) { int i = 0; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); - if (nfsd_serv != NULL) { - for (i = 0; i < nfsd_serv->sv_nrpools && i < n; i++) - nthreads[i] = nfsd_serv->sv_pools[i].sp_nrthreads; + if (nn->nfsd_serv != NULL) { + for (i = 0; i < nn->nfsd_serv->sv_nrpools && i < n; i++) + nthreads[i] = nn->nfsd_serv->sv_pools[i].sp_nrthreads; } return 0; } +void nfsd_destroy(struct net *net) +{ + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + int destroy = (nn->nfsd_serv->sv_nrthreads == 1); + + if (destroy) + svc_shutdown_net(nn->nfsd_serv, net); + svc_destroy(nn->nfsd_serv); + if (destroy) + nn->nfsd_serv = NULL; +} + int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) { int i = 0; int tot = 0; int err = 0; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); WARN_ON(!mutex_is_locked(&nfsd_mutex)); - if (nfsd_serv == NULL || n <= 0) + if (nn->nfsd_serv == NULL || n <= 0) return 0; - if (n > nfsd_serv->sv_nrpools) - n = nfsd_serv->sv_nrpools; + if (n > nn->nfsd_serv->sv_nrpools) + n = nn->nfsd_serv->sv_nrpools; /* enforce a global maximum number of threads */ tot = 0; @@ -454,9 +473,9 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) nthreads[0] = 1; /* apply the new numbers */ - svc_get(nfsd_serv); + svc_get(nn->nfsd_serv); for (i = 0; i < n; i++) { - err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i], + err = svc_set_num_threads(nn->nfsd_serv, &nn->nfsd_serv->sv_pools[i], nthreads[i]); if (err) break; @@ -475,6 +494,7 @@ nfsd_svc(int nrservs, struct net *net) { int error; bool nfsd_up_before; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); mutex_lock(&nfsd_mutex); dprintk("nfsd: creating service\n"); @@ -483,7 +503,7 @@ nfsd_svc(int nrservs, struct net *net) if (nrservs > NFSD_MAXSERVS) nrservs = NFSD_MAXSERVS; error = 0; - if (nrservs == 0 && nfsd_serv == NULL) + if (nrservs == 0 && nn->nfsd_serv == NULL) goto out; error = nfsd_create_serv(net); @@ -495,14 +515,14 @@ nfsd_svc(int nrservs, struct net *net) error = nfsd_startup(nrservs, net); if (error) goto out_destroy; - error = svc_set_num_threads(nfsd_serv, NULL, nrservs); + error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs); if (error) goto out_shutdown; - /* We are holding a reference to nfsd_serv which + /* We are holding a reference to nn->nfsd_serv which * we don't want to count in the return value, * so subtract 1 */ - error = nfsd_serv->sv_nrthreads - 1; + error = nn->nfsd_serv->sv_nrthreads - 1; out_shutdown: if (error < 0 && !nfsd_up_before) nfsd_shutdown(net); @@ -681,14 +701,17 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) int nfsd_pool_stats_open(struct inode *inode, struct file *file) { int ret; + struct net *net = &init_net; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + mutex_lock(&nfsd_mutex); - if (nfsd_serv == NULL) { + if (nn->nfsd_serv == NULL) { mutex_unlock(&nfsd_mutex); return -ENODEV; } /* bump up the psudo refcount while traversing */ - svc_get(nfsd_serv); - ret = svc_pool_stats_open(nfsd_serv, file); + svc_get(nn->nfsd_serv); + ret = svc_pool_stats_open(nn->nfsd_serv, file); mutex_unlock(&nfsd_mutex); return ret; } -- cgit v0.10.2 From bda9cac1db8ab044e9edbfe5730283016b67d451 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 6 Dec 2012 14:23:29 +0300 Subject: nfsd: introduce helpers for generic resources init and shutdown NFSd have per-net resources and resources, used globally. Let's move generic resources init and shutdown to separated functions since they are going to be allocated on first NFSd service start and destroyed after last NFSd service shutdown. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 0e8622a..f9d147f 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -206,6 +206,37 @@ static int nfsd_init_socks(struct net *net) static bool nfsd_up = false; +static int nfsd_startup_generic(int nrservs) +{ + int ret; + + if (nfsd_up) + return 0; + + /* + * Readahead param cache - will no-op if it already exists. + * (Note therefore results will be suboptimal if number of + * threads is modified after nfsd start.) + */ + ret = nfsd_racache_init(2*nrservs); + if (ret) + return ret; + ret = nfs4_state_start(); + if (ret) + goto out_racache; + return 0; + +out_racache: + nfsd_racache_shutdown(); + return ret; +} + +static void nfsd_shutdown_generic(void) +{ + nfs4_state_shutdown(); + nfsd_racache_shutdown(); +} + static int nfsd_startup_net(struct net *net) { struct nfsd_net *nn = net_generic(net, nfsd_net_id); @@ -236,19 +267,9 @@ static int nfsd_startup(int nrservs, struct net *net) { int ret; - if (nfsd_up) - return 0; - /* - * Readahead param cache - will no-op if it already exists. - * (Note therefore results will be suboptimal if number of - * threads is modified after nfsd start.) - */ - ret = nfsd_racache_init(2*nrservs); + ret = nfsd_startup_generic(nrservs); if (ret) return ret; - ret = nfs4_state_start(); - if (ret) - goto out_racache; ret = nfsd_startup_net(net); if (ret) goto out_net; @@ -257,9 +278,7 @@ static int nfsd_startup(int nrservs, struct net *net) return 0; out_net: - nfs4_state_shutdown(); -out_racache: - nfsd_racache_shutdown(); + nfsd_shutdown_generic(); return ret; } @@ -286,8 +305,7 @@ static void nfsd_shutdown(struct net *net) if (!nfsd_up) return; nfsd_shutdown_net(net); - nfs4_state_shutdown(); - nfsd_racache_shutdown(); + nfsd_shutdown_generic(); nfsd_up = false; } -- cgit v0.10.2 From 903d9bf0edebc9d9f06df125ab2bd57b4aa4e78e Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 6 Dec 2012 14:23:34 +0300 Subject: nfsd: simplify NFSv4 state init and shutdown This patch moves nfsd_startup_generic() and nfsd_shutdown_generic() calls to nfsd_startup_net() and nfsd_shutdown_net() respectively, which allows us to call nfsd_startup_net() instead of nfsd_startup() and makes the code look clearer. It also modifies nfsd_svc() and nfsd_shutdown() to check nn->nfsd_net_up instead of global nfsd_up. The latter is now used only for generic resources shutdown and is currently useless. It will replaced by NFSd users counter later in this series. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index f9d147f..0c87b4e 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -235,9 +235,10 @@ static void nfsd_shutdown_generic(void) { nfs4_state_shutdown(); nfsd_racache_shutdown(); + nfsd_up = false; } -static int nfsd_startup_net(struct net *net) +static int nfsd_startup_net(int nrservs, struct net *net) { struct nfsd_net *nn = net_generic(net, nfsd_net_id); int ret; @@ -245,39 +246,26 @@ static int nfsd_startup_net(struct net *net) if (nn->nfsd_net_up) return 0; - ret = nfsd_init_socks(net); + ret = nfsd_startup_generic(nrservs); if (ret) return ret; + ret = nfsd_init_socks(net); + if (ret) + goto out_socks; ret = lockd_up(net); if (ret) - return ret; + goto out_socks; ret = nfs4_state_start_net(net); if (ret) goto out_lockd; nn->nfsd_net_up = true; + nfsd_up = true; return 0; out_lockd: lockd_down(net); - return ret; -} - -static int nfsd_startup(int nrservs, struct net *net) -{ - int ret; - - ret = nfsd_startup_generic(nrservs); - if (ret) - return ret; - ret = nfsd_startup_net(net); - if (ret) - goto out_net; - - nfsd_up = true; - return 0; - -out_net: +out_socks: nfsd_shutdown_generic(); return ret; } @@ -286,27 +274,25 @@ static void nfsd_shutdown_net(struct net *net) { struct nfsd_net *nn = net_generic(net, nfsd_net_id); - if (!nn->nfsd_net_up) - return; - nfs4_state_shutdown_net(net); lockd_down(net); nn->nfsd_net_up = false; + nfsd_shutdown_generic(); } static void nfsd_shutdown(struct net *net) { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + /* * write_ports can create the server without actually starting * any threads--if we get shut down before any threads are * started, then nfsd_last_thread will be run before any of this * other initialization has been done. */ - if (!nfsd_up) + if (!nn->nfsd_net_up) return; nfsd_shutdown_net(net); - nfsd_shutdown_generic(); - nfsd_up = false; } static void nfsd_last_thread(struct svc_serv *serv, struct net *net) @@ -528,9 +514,9 @@ nfsd_svc(int nrservs, struct net *net) if (error) goto out; - nfsd_up_before = nfsd_up; + nfsd_up_before = nn->nfsd_net_up; - error = nfsd_startup(nrservs, net); + error = nfsd_startup_net(nrservs, net); if (error) goto out_destroy; error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs); -- cgit v0.10.2 From 4539f14981ce02d48b212786a41c8bcfb62851b4 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 6 Dec 2012 14:23:39 +0300 Subject: nfsd: replace boolean nfsd_up flag by users counter Since we have generic NFSd resurces, we have to introduce some way how to allocate and destroy those resources on first per-net NFSd start and on last per-net NFSd stop respectively. This patch replaces global boolean nfsd_up flag (which is unused now) by users counter and use it to determine either we need to allocate generic resources or destroy them. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 0c87b4e..5bb4a33 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -204,13 +204,13 @@ static int nfsd_init_socks(struct net *net) return 0; } -static bool nfsd_up = false; +static int nfsd_users = 0; static int nfsd_startup_generic(int nrservs) { int ret; - if (nfsd_up) + if (nfsd_users++) return 0; /* @@ -233,9 +233,11 @@ out_racache: static void nfsd_shutdown_generic(void) { + if (--nfsd_users) + return; + nfs4_state_shutdown(); nfsd_racache_shutdown(); - nfsd_up = false; } static int nfsd_startup_net(int nrservs, struct net *net) @@ -260,7 +262,6 @@ static int nfsd_startup_net(int nrservs, struct net *net) goto out_lockd; nn->nfsd_net_up = true; - nfsd_up = true; return 0; out_lockd: -- cgit v0.10.2 From 541e864f00d0062c98c1e743265b0a60cada3755 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 6 Dec 2012 14:23:44 +0300 Subject: nfsd: simplify service shutdown Function nfsd_shutdown is called from two places: nfsd_last_thread (when last kernel thread is exiting) and nfsd_svc (in case of kthreads starting error). When calling from nfsd_svc(), we can be sure that per-net resources are allocated, so we don't need to check per-net nfsd_net_up boolean flag. This allows us to remove nfsd_shutdown function at all and move check for per-net nfsd_net_up boolean flag to nfsd_last_thread. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 5bb4a33..2cfd9c6 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -281,7 +281,7 @@ static void nfsd_shutdown_net(struct net *net) nfsd_shutdown_generic(); } -static void nfsd_shutdown(struct net *net) +static void nfsd_last_thread(struct svc_serv *serv, struct net *net) { struct nfsd_net *nn = net_generic(net, nfsd_net_id); @@ -294,11 +294,6 @@ static void nfsd_shutdown(struct net *net) if (!nn->nfsd_net_up) return; nfsd_shutdown_net(net); -} - -static void nfsd_last_thread(struct svc_serv *serv, struct net *net) -{ - nfsd_shutdown(net); svc_rpcb_cleanup(serv, net); @@ -530,7 +525,7 @@ nfsd_svc(int nrservs, struct net *net) error = nn->nfsd_serv->sv_nrthreads - 1; out_shutdown: if (error < 0 && !nfsd_up_before) - nfsd_shutdown(net); + nfsd_shutdown_net(net); out_destroy: nfsd_destroy(net); /* Release server */ out: -- cgit v0.10.2 From 88c47666171989ed4c5b1a5687df09511e8c5e35 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Thu, 6 Dec 2012 18:34:42 +0300 Subject: nfsd: pass proper net to nfsd_destroy() from NFSd kthreads Since NFSd service is per-net now, we have to pass proper network context in nfsd_shutdown() from NFSd kthreads. The simplest way I found is to get proper net from one of transports with permanent sockets. Signed-off-by: Stanislav Kinsbursky Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 2cfd9c6..cee62ab 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -541,6 +541,8 @@ static int nfsd(void *vrqstp) { struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; + struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list); + struct net *net = perm_sock->xpt_net; int err; /* Lock module and set up kernel thread */ @@ -605,7 +607,7 @@ out: /* Release the thread */ svc_exit_thread(rqstp); - nfsd_destroy(&init_net); + nfsd_destroy(net); /* Release module */ mutex_unlock(&nfsd_mutex); -- cgit v0.10.2 From 0a5c33e23c4d781ecc815002c54f1f91012c703d Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Fri, 7 Dec 2012 16:17:28 -0500 Subject: NFSD: Pass correct buffer size to rpc_ntop I honestly have no idea where I got 129 from, but it's a much bigger value than the actual buffer size (INET6_ADDRSTRLEN). Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 96ffdf5..7a7b079 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -79,7 +79,7 @@ static void nfsd_inject_set_client(struct nfsd_fault_inject_op *op, clp = nfsd_find_client(addr, addr_size); if (clp) { count = op->forget(clp, 0); - rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, 129); + rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); printk(KERN_INFO "NFSD [%s]: Client %s had %llu state object(s)\n", op->file, buf, count); } nfs4_unlock_state(); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3d27f08..8e25551 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4623,7 +4623,7 @@ u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) u64 nfsd_print_client(struct nfs4_client *clp, u64 num) { char buf[INET6_ADDRSTRLEN]; - rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, 129); + rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); printk(KERN_INFO "NFS Client: %s\n", buf); return 1; } @@ -4632,7 +4632,7 @@ static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, const char *type) { char buf[INET6_ADDRSTRLEN]; - rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, 129); + rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); } -- cgit v0.10.2 From 18d9a2ca2ea1aa963a077fb49e7efcc3b0237a9b Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Fri, 7 Dec 2012 16:17:29 -0500 Subject: NFSD: Correct the size calculation in fault_inject_write If len == 0 we end up with size = (0 - 1), which could cause bad things to happen in copy_from_user(). Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 7a7b079..e761ee9 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -122,7 +122,7 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { char write_buf[INET6_ADDRSTRLEN]; - size_t size = min(sizeof(write_buf), len) - 1; + size_t size = min(sizeof(write_buf) - 1, len); struct net *net = current->nsproxy->net_ns; struct sockaddr_storage sa; u64 val; -- cgit v0.10.2 From 1f3c9907b8037de7b9635b0b471572ea8758bcd1 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 11 Dec 2012 13:09:00 +1100 Subject: md: removed unused variable in calc_sb_1_csm. 'i' is unused. NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index 6120071..89dbd44 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1414,12 +1414,11 @@ static __le32 calc_sb_1_csum(struct mdp_superblock_1 * sb) unsigned long long newcsum; int size = 256 + le32_to_cpu(sb->max_dev)*2; __le32 *isuper = (__le32*)sb; - int i; disk_csum = sb->sb_csum; sb->sb_csum = 0; newcsum = 0; - for (i=0; size>=4; size -= 4 ) + for (; size >= 4; size -= 4) newcsum += le32_to_cpu(*isuper++); if (size == 2) -- cgit v0.10.2 From a7a3f08dc24690ae00c75cfe4b4701a970dd0155 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 11 Dec 2012 13:35:54 +1100 Subject: md: close race between removing and adding a device. When we remove a device from an md array, the final removal of the "dev-XX" sys entry is run asynchronously. If we then re-add that device immediately before the worker thread gets to run, we can end up trying to add the "dev-XX" sysfs entry back before it has been removed. So in both places where we add a device, call flush_workqueue(md_misc_wq); before taking the md lock (as holding the md lock can prevent removal to complete). Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index 89dbd44..8b0e3d2 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4752,6 +4752,8 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, } mddev_get(mddev); spin_unlock(&all_mddevs_lock); + if (entry->store == new_dev_store) + flush_workqueue(md_misc_wq); rv = mddev_lock(mddev); if (!rv) { rv = entry->store(mddev, page, length); @@ -6397,6 +6399,10 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, goto abort; } + if (cmd == ADD_NEW_DISK) + /* need to ensure md_delayed_delete() has completed */ + flush_workqueue(md_misc_wq); + err = mddev_lock(mddev); if (err) { printk(KERN_INFO -- cgit v0.10.2 From c02c0aeb6c728e5ad705dba86784bd553cb6f059 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 11 Dec 2012 13:39:21 +1100 Subject: md.c: re-indent various 'switch' statements. Intent was unnecessarily deep. Also change one 'switch' which has a single case element, into an 'if'. Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index 8b0e3d2..520056a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6347,24 +6347,23 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, * Commands dealing with the RAID driver but not any * particular array: */ - switch (cmd) - { - case RAID_VERSION: - err = get_version(argp); - goto done; + switch (cmd) { + case RAID_VERSION: + err = get_version(argp); + goto done; - case PRINT_RAID_DEBUG: - err = 0; - md_print_devices(); - goto done; + case PRINT_RAID_DEBUG: + err = 0; + md_print_devices(); + goto done; #ifndef MODULE - case RAID_AUTORUN: - err = 0; - autostart_arrays(arg); - goto done; + case RAID_AUTORUN: + err = 0; + autostart_arrays(arg); + goto done; #endif - default:; + default:; } /* @@ -6411,50 +6410,44 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, goto abort; } - switch (cmd) - { - case SET_ARRAY_INFO: - { - mdu_array_info_t info; - if (!arg) - memset(&info, 0, sizeof(info)); - else if (copy_from_user(&info, argp, sizeof(info))) { - err = -EFAULT; - goto abort_unlock; - } - if (mddev->pers) { - err = update_array_info(mddev, &info); - if (err) { - printk(KERN_WARNING "md: couldn't update" - " array info. %d\n", err); - goto abort_unlock; - } - goto done_unlock; - } - if (!list_empty(&mddev->disks)) { - printk(KERN_WARNING - "md: array %s already has disks!\n", - mdname(mddev)); - err = -EBUSY; - goto abort_unlock; - } - if (mddev->raid_disks) { - printk(KERN_WARNING - "md: array %s already initialised!\n", - mdname(mddev)); - err = -EBUSY; - goto abort_unlock; - } - err = set_array_info(mddev, &info); - if (err) { - printk(KERN_WARNING "md: couldn't set" - " array info. %d\n", err); - goto abort_unlock; - } + if (cmd == SET_ARRAY_INFO) { + mdu_array_info_t info; + if (!arg) + memset(&info, 0, sizeof(info)); + else if (copy_from_user(&info, argp, sizeof(info))) { + err = -EFAULT; + goto abort_unlock; + } + if (mddev->pers) { + err = update_array_info(mddev, &info); + if (err) { + printk(KERN_WARNING "md: couldn't update" + " array info. %d\n", err); + goto abort_unlock; } goto done_unlock; - - default:; + } + if (!list_empty(&mddev->disks)) { + printk(KERN_WARNING + "md: array %s already has disks!\n", + mdname(mddev)); + err = -EBUSY; + goto abort_unlock; + } + if (mddev->raid_disks) { + printk(KERN_WARNING + "md: array %s already initialised!\n", + mdname(mddev)); + err = -EBUSY; + goto abort_unlock; + } + err = set_array_info(mddev, &info); + if (err) { + printk(KERN_WARNING "md: couldn't set" + " array info. %d\n", err); + goto abort_unlock; + } + goto done_unlock; } /* @@ -6473,52 +6466,51 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, /* * Commands even a read-only array can execute: */ - switch (cmd) - { - case GET_BITMAP_FILE: - err = get_bitmap_file(mddev, argp); - goto done_unlock; + switch (cmd) { + case GET_BITMAP_FILE: + err = get_bitmap_file(mddev, argp); + goto done_unlock; - case RESTART_ARRAY_RW: - err = restart_array(mddev); - goto done_unlock; + case RESTART_ARRAY_RW: + err = restart_array(mddev); + goto done_unlock; - case STOP_ARRAY: - err = do_md_stop(mddev, 0, bdev); - goto done_unlock; + case STOP_ARRAY: + err = do_md_stop(mddev, 0, bdev); + goto done_unlock; - case STOP_ARRAY_RO: - err = md_set_readonly(mddev, bdev); - goto done_unlock; + case STOP_ARRAY_RO: + err = md_set_readonly(mddev, bdev); + goto done_unlock; - case BLKROSET: - if (get_user(ro, (int __user *)(arg))) { - err = -EFAULT; - goto done_unlock; - } - err = -EINVAL; + case BLKROSET: + if (get_user(ro, (int __user *)(arg))) { + err = -EFAULT; + goto done_unlock; + } + err = -EINVAL; - /* if the bdev is going readonly the value of mddev->ro - * does not matter, no writes are coming - */ - if (ro) - goto done_unlock; + /* if the bdev is going readonly the value of mddev->ro + * does not matter, no writes are coming + */ + if (ro) + goto done_unlock; - /* are we are already prepared for writes? */ - if (mddev->ro != 1) - goto done_unlock; + /* are we are already prepared for writes? */ + if (mddev->ro != 1) + goto done_unlock; - /* transitioning to readauto need only happen for - * arrays that call md_write_start - */ - if (mddev->pers) { - err = restart_array(mddev); - if (err == 0) { - mddev->ro = 2; - set_disk_ro(mddev->gendisk, 0); - } + /* transitioning to readauto need only happen for + * arrays that call md_write_start + */ + if (mddev->pers) { + err = restart_array(mddev); + if (err == 0) { + mddev->ro = 2; + set_disk_ro(mddev->gendisk, 0); } - goto done_unlock; + } + goto done_unlock; } /* @@ -6540,37 +6532,36 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, } } - switch (cmd) + switch (cmd) { + case ADD_NEW_DISK: { - case ADD_NEW_DISK: - { - mdu_disk_info_t info; - if (copy_from_user(&info, argp, sizeof(info))) - err = -EFAULT; - else - err = add_new_disk(mddev, &info); - goto done_unlock; - } + mdu_disk_info_t info; + if (copy_from_user(&info, argp, sizeof(info))) + err = -EFAULT; + else + err = add_new_disk(mddev, &info); + goto done_unlock; + } - case HOT_REMOVE_DISK: - err = hot_remove_disk(mddev, new_decode_dev(arg)); - goto done_unlock; + case HOT_REMOVE_DISK: + err = hot_remove_disk(mddev, new_decode_dev(arg)); + goto done_unlock; - case HOT_ADD_DISK: - err = hot_add_disk(mddev, new_decode_dev(arg)); - goto done_unlock; + case HOT_ADD_DISK: + err = hot_add_disk(mddev, new_decode_dev(arg)); + goto done_unlock; - case RUN_ARRAY: - err = do_md_run(mddev); - goto done_unlock; + case RUN_ARRAY: + err = do_md_run(mddev); + goto done_unlock; - case SET_BITMAP_FILE: - err = set_bitmap_file(mddev, (int)arg); - goto done_unlock; + case SET_BITMAP_FILE: + err = set_bitmap_file(mddev, (int)arg); + goto done_unlock; - default: - err = -EINVAL; - goto abort_unlock; + default: + err = -EINVAL; + goto abort_unlock; } done_unlock: -- cgit v0.10.2 From 98e4da8ca301e062d79ae168c67e56f3c3de3ce4 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:05:42 +0900 Subject: f2fs: add document This adds a document describing the mount options, proc entries, usage, and design of Flash-Friendly File System, namely F2FS. Signed-off-by: Jaegeuk Kim diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 8c624a1..ce5fd46 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX @@ -48,6 +48,8 @@ ext4.txt - info, mount options and specifications for the Ext4 filesystem. files.txt - info on file management in the Linux kernel. +f2fs.txt + - info and mount options for the F2FS filesystem. fuse.txt - info on the Filesystem in User SpacE including mount options. gfs2.txt diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt new file mode 100644 index 0000000..6ce5407 --- /dev/null +++ b/Documentation/filesystems/f2fs.txt @@ -0,0 +1,417 @@ +================================================================================ +WHAT IS Flash-Friendly File System (F2FS)? +================================================================================ + +NAND flash memory-based storage devices, such as SSD, eMMC, and SD cards, have +been equipped on a variety systems ranging from mobile to server systems. Since +they are known to have different characteristics from the conventional rotating +disks, a file system, an upper layer to the storage device, should adapt to the +changes from the sketch in the design level. + +F2FS is a file system exploiting NAND flash memory-based storage devices, which +is based on Log-structured File System (LFS). The design has been focused on +addressing the fundamental issues in LFS, which are snowball effect of wandering +tree and high cleaning overhead. + +Since a NAND flash memory-based storage device shows different characteristic +according to its internal geometry or flash memory management scheme, namely FTL, +F2FS and its tools support various parameters not only for configuring on-disk +layout, but also for selecting allocation and cleaning algorithms. + +The file system formatting tool, "mkfs.f2fs", is available from the following +download page: http://sourceforge.net/projects/f2fs-tools/ + +================================================================================ +BACKGROUND AND DESIGN ISSUES +================================================================================ + +Log-structured File System (LFS) +-------------------------------- +"A log-structured file system writes all modifications to disk sequentially in +a log-like structure, thereby speeding up both file writing and crash recovery. +The log is the only structure on disk; it contains indexing information so that +files can be read back from the log efficiently. In order to maintain large free +areas on disk for fast writing, we divide the log into segments and use a +segment cleaner to compress the live information from heavily fragmented +segments." from Rosenblum, M. and Ousterhout, J. K., 1992, "The design and +implementation of a log-structured file system", ACM Trans. Computer Systems +10, 1, 26–52. + +Wandering Tree Problem +---------------------- +In LFS, when a file data is updated and written to the end of log, its direct +pointer block is updated due to the changed location. Then the indirect pointer +block is also updated due to the direct pointer block update. In this manner, +the upper index structures such as inode, inode map, and checkpoint block are +also updated recursively. This problem is called as wandering tree problem [1], +and in order to enhance the performance, it should eliminate or relax the update +propagation as much as possible. + +[1] Bityutskiy, A. 2005. JFFS3 design issues. http://www.linux-mtd.infradead.org/ + +Cleaning Overhead +----------------- +Since LFS is based on out-of-place writes, it produces so many obsolete blocks +scattered across the whole storage. In order to serve new empty log space, it +needs to reclaim these obsolete blocks seamlessly to users. This job is called +as a cleaning process. + +The process consists of three operations as follows. +1. A victim segment is selected through referencing segment usage table. +2. It loads parent index structures of all the data in the victim identified by + segment summary blocks. +3. It checks the cross-reference between the data and its parent index structure. +4. It moves valid data selectively. + +This cleaning job may cause unexpected long delays, so the most important goal +is to hide the latencies to users. And also definitely, it should reduce the +amount of valid data to be moved, and move them quickly as well. + +================================================================================ +KEY FEATURES +================================================================================ + +Flash Awareness +--------------- +- Enlarge the random write area for better performance, but provide the high + spatial locality +- Align FS data structures to the operational units in FTL as best efforts + +Wandering Tree Problem +---------------------- +- Use a term, “node”, that represents inodes as well as various pointer blocks +- Introduce Node Address Table (NAT) containing the locations of all the “node” + blocks; this will cut off the update propagation. + +Cleaning Overhead +----------------- +- Support a background cleaning process +- Support greedy and cost-benefit algorithms for victim selection policies +- Support multi-head logs for static/dynamic hot and cold data separation +- Introduce adaptive logging for efficient block allocation + +================================================================================ +MOUNT OPTIONS +================================================================================ + +background_gc_off Turn off cleaning operations, namely garbage collection, + triggered in background when I/O subsystem is idle. +disable_roll_forward Disable the roll-forward recovery routine +discard Issue discard/TRIM commands when a segment is cleaned. +no_heap Disable heap-style segment allocation which finds free + segments for data from the beginning of main area, while + for node from the end of main area. +nouser_xattr Disable Extended User Attributes. Note: xattr is enabled + by default if CONFIG_F2FS_FS_XATTR is selected. +noacl Disable POSIX Access Control List. Note: acl is enabled + by default if CONFIG_F2FS_FS_POSIX_ACL is selected. +active_logs=%u Support configuring the number of active logs. In the + current design, f2fs supports only 2, 4, and 6 logs. + Default number is 6. +disable_ext_identify Disable the extension list configured by mkfs, so f2fs + does not aware of cold files such as media files. + +================================================================================ +DEBUGFS ENTRIES +================================================================================ + +/sys/kernel/debug/f2fs/ contains information about all the partitions mounted as +f2fs. Each file shows the whole f2fs information. + +/sys/kernel/debug/f2fs/status includes: + - major file system information managed by f2fs currently + - average SIT information about whole segments + - current memory footprint consumed by f2fs. + +================================================================================ +USAGE +================================================================================ + +1. Download userland tools and compile them. + +2. Skip, if f2fs was compiled statically inside kernel. + Otherwise, insert the f2fs.ko module. + # insmod f2fs.ko + +3. Create a directory trying to mount + # mkdir /mnt/f2fs + +4. Format the block device, and then mount as f2fs + # mkfs.f2fs -l label /dev/block_device + # mount -t f2fs /dev/block_device /mnt/f2fs + +Format options +-------------- +-l [label] : Give a volume label, up to 256 unicode name. +-a [0 or 1] : Split start location of each area for heap-based allocation. + 1 is set by default, which performs this. +-o [int] : Set overprovision ratio in percent over volume size. + 5 is set by default. +-s [int] : Set the number of segments per section. + 1 is set by default. +-z [int] : Set the number of sections per zone. + 1 is set by default. +-e [str] : Set basic extension list. e.g. "mp3,gif,mov" + +================================================================================ +DESIGN +================================================================================ + +On-disk Layout +-------------- + +F2FS divides the whole volume into a number of segments, each of which is fixed +to 2MB in size. A section is composed of consecutive segments, and a zone +consists of a set of sections. By default, section and zone sizes are set to one +segment size identically, but users can easily modify the sizes by mkfs. + +F2FS splits the entire volume into six areas, and all the areas except superblock +consists of multiple segments as described below. + + align with the zone size <-| + |-> align with the segment size + _________________________________________________________________________ + | | | Node | Segment | Segment | | + | Superblock | Checkpoint | Address | Info. | Summary | Main | + | (SB) | (CP) | Table (NAT) | Table (SIT) | Area (SSA) | | + |____________|_____2______|______N______|______N______|______N_____|__N___| + . . + . . + . . + ._________________________________________. + |_Segment_|_..._|_Segment_|_..._|_Segment_| + . . + ._________._________ + |_section_|__...__|_ + . . + .________. + |__zone__| + +- Superblock (SB) + : It is located at the beginning of the partition, and there exist two copies + to avoid file system crash. It contains basic partition information and some + default parameters of f2fs. + +- Checkpoint (CP) + : It contains file system information, bitmaps for valid NAT/SIT sets, orphan + inode lists, and summary entries of current active segments. + +- Node Address Table (NAT) + : It is composed of a block address table for all the node blocks stored in + Main area. + +- Segment Information Table (SIT) + : It contains segment information such as valid block count and bitmap for the + validity of all the blocks. + +- Segment Summary Area (SSA) + : It contains summary entries which contains the owner information of all the + data and node blocks stored in Main area. + +- Main Area + : It contains file and directory data including their indices. + +In order to avoid misalignment between file system and flash-based storage, F2FS +aligns the start block address of CP with the segment size. Also, it aligns the +start block address of Main area with the zone size by reserving some segments +in SSA area. + +Reference the following survey for additional technical details. +https://wiki.linaro.org/WorkingGroups/Kernel/Projects/FlashCardSurvey + +File System Metadata Structure +------------------------------ + +F2FS adopts the checkpointing scheme to maintain file system consistency. At +mount time, F2FS first tries to find the last valid checkpoint data by scanning +CP area. In order to reduce the scanning time, F2FS uses only two copies of CP. +One of them always indicates the last valid data, which is called as shadow copy +mechanism. In addition to CP, NAT and SIT also adopt the shadow copy mechanism. + +For file system consistency, each CP points to which NAT and SIT copies are +valid, as shown as below. + + +--------+----------+---------+ + | CP | NAT | SIT | + +--------+----------+---------+ + . . . . + . . . . + . . . . + +-------+-------+--------+--------+--------+--------+ + | CP #0 | CP #1 | NAT #0 | NAT #1 | SIT #0 | SIT #1 | + +-------+-------+--------+--------+--------+--------+ + | ^ ^ + | | | + `----------------------------------------' + +Index Structure +--------------- + +The key data structure to manage the data locations is a "node". Similar to +traditional file structures, F2FS has three types of node: inode, direct node, +indirect node. F2FS assigns 4KB to an inode block which contains 929 data block +indices, two direct node pointers, two indirect node pointers, and one double +indirect node pointer as described below. One direct node block contains 1018 +data blocks, and one indirect node block contains also 1018 node blocks. Thus, +one inode block (i.e., a file) covers: + + 4KB * (923 + 2 * 1018 + 2 * 1018 * 1018 + 1018 * 1018 * 1018) := 3.94TB. + + Inode block (4KB) + |- data (923) + |- direct node (2) + | `- data (1018) + |- indirect node (2) + | `- direct node (1018) + | `- data (1018) + `- double indirect node (1) + `- indirect node (1018) + `- direct node (1018) + `- data (1018) + +Note that, all the node blocks are mapped by NAT which means the location of +each node is translated by the NAT table. In the consideration of the wandering +tree problem, F2FS is able to cut off the propagation of node updates caused by +leaf data writes. + +Directory Structure +------------------- + +A directory entry occupies 11 bytes, which consists of the following attributes. + +- hash hash value of the file name +- ino inode number +- len the length of file name +- type file type such as directory, symlink, etc + +A dentry block consists of 214 dentry slots and file names. Therein a bitmap is +used to represent whether each dentry is valid or not. A dentry block occupies +4KB with the following composition. + + Dentry Block(4 K) = bitmap (27 bytes) + reserved (3 bytes) + + dentries(11 * 214 bytes) + file name (8 * 214 bytes) + + [Bucket] + +--------------------------------+ + |dentry block 1 | dentry block 2 | + +--------------------------------+ + . . + . . + . [Dentry Block Structure: 4KB] . + +--------+----------+----------+------------+ + | bitmap | reserved | dentries | file names | + +--------+----------+----------+------------+ + [Dentry Block: 4KB] . . + . . + . . + +------+------+-----+------+ + | hash | ino | len | type | + +------+------+-----+------+ + [Dentry Structure: 11 bytes] + +F2FS implements multi-level hash tables for directory structure. Each level has +a hash table with dedicated number of hash buckets as shown below. Note that +"A(2B)" means a bucket includes 2 data blocks. + +---------------------- +A : bucket +B : block +N : MAX_DIR_HASH_DEPTH +---------------------- + +level #0 | A(2B) + | +level #1 | A(2B) - A(2B) + | +level #2 | A(2B) - A(2B) - A(2B) - A(2B) + . | . . . . +level #N/2 | A(2B) - A(2B) - A(2B) - A(2B) - A(2B) - ... - A(2B) + . | . . . . +level #N | A(4B) - A(4B) - A(4B) - A(4B) - A(4B) - ... - A(4B) + +The number of blocks and buckets are determined by, + + ,- 2, if n < MAX_DIR_HASH_DEPTH / 2, + # of blocks in level #n = | + `- 4, Otherwise + + ,- 2^n, if n < MAX_DIR_HASH_DEPTH / 2, + # of buckets in level #n = | + `- 2^((MAX_DIR_HASH_DEPTH / 2) - 1), Otherwise + +When F2FS finds a file name in a directory, at first a hash value of the file +name is calculated. Then, F2FS scans the hash table in level #0 to find the +dentry consisting of the file name and its inode number. If not found, F2FS +scans the next hash table in level #1. In this way, F2FS scans hash tables in +each levels incrementally from 1 to N. In each levels F2FS needs to scan only +one bucket determined by the following equation, which shows O(log(# of files)) +complexity. + + bucket number to scan in level #n = (hash value) % (# of buckets in level #n) + +In the case of file creation, F2FS finds empty consecutive slots that cover the +file name. F2FS searches the empty slots in the hash tables of whole levels from +1 to N in the same way as the lookup operation. + +The following figure shows an example of two cases holding children. + --------------> Dir <-------------- + | | + child child + + child - child [hole] - child + + child - child - child [hole] - [hole] - child + + Case 1: Case 2: + Number of children = 6, Number of children = 3, + File size = 7 File size = 7 + +Default Block Allocation +------------------------ + +At runtime, F2FS manages six active logs inside "Main" area: Hot/Warm/Cold node +and Hot/Warm/Cold data. + +- Hot node contains direct node blocks of directories. +- Warm node contains direct node blocks except hot node blocks. +- Cold node contains indirect node blocks +- Hot data contains dentry blocks +- Warm data contains data blocks except hot and cold data blocks +- Cold data contains multimedia data or migrated data blocks + +LFS has two schemes for free space management: threaded log and copy-and-compac- +tion. The copy-and-compaction scheme which is known as cleaning, is well-suited +for devices showing very good sequential write performance, since free segments +are served all the time for writing new data. However, it suffers from cleaning +overhead under high utilization. Contrarily, the threaded log scheme suffers +from random writes, but no cleaning process is needed. F2FS adopts a hybrid +scheme where the copy-and-compaction scheme is adopted by default, but the +policy is dynamically changed to the threaded log scheme according to the file +system status. + +In order to align F2FS with underlying flash-based storage, F2FS allocates a +segment in a unit of section. F2FS expects that the section size would be the +same as the unit size of garbage collection in FTL. Furthermore, with respect +to the mapping granularity in FTL, F2FS allocates each section of the active +logs from different zones as much as possible, since FTL can write the data in +the active logs into one allocation unit according to its mapping granularity. + +Cleaning process +---------------- + +F2FS does cleaning both on demand and in the background. On-demand cleaning is +triggered when there are not enough free segments to serve VFS calls. Background +cleaner is operated by a kernel thread, and triggers the cleaning job when the +system is idle. + +F2FS supports two victim selection policies: greedy and cost-benefit algorithms. +In the greedy algorithm, F2FS selects a victim segment having the smallest number +of valid blocks. In the cost-benefit algorithm, F2FS selects a victim segment +according to the segment age and the number of valid blocks in order to address +log block thrashing problem in the greedy algorithm. F2FS adopts the greedy +algorithm for on-demand cleaner, while background cleaner adopts cost-benefit +algorithm. + +In order to identify whether the data in the victim segment are valid or not, +F2FS manages a bitmap. Each bit represents the validity of a block, and the +bitmap is composed of a bit stream covering whole blocks in main area. -- cgit v0.10.2 From dd31866b0d55c9b70722ebad6ccd643223d9269e Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:06:26 +0900 Subject: f2fs: add on-disk layout This adds a header file describing the on-disk layout of f2fs. Signed-off-by: Changman Lee Signed-off-by: Chul Lee Signed-off-by: Jaegeuk Kim diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h new file mode 100644 index 0000000..1429ece --- /dev/null +++ b/include/linux/f2fs_fs.h @@ -0,0 +1,410 @@ +/** + * include/linux/f2fs_fs.h + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _LINUX_F2FS_FS_H +#define _LINUX_F2FS_FS_H + +#include +#include + +#define F2FS_SUPER_OFFSET 1024 /* byte-size offset */ +#define F2FS_LOG_SECTOR_SIZE 9 /* 9 bits for 512 byte */ +#define F2FS_LOG_SECTORS_PER_BLOCK 3 /* 4KB: F2FS_BLKSIZE */ +#define F2FS_BLKSIZE 4096 /* support only 4KB block */ +#define F2FS_MAX_EXTENSION 64 /* # of extension entries */ + +#define NULL_ADDR 0x0U +#define NEW_ADDR -1U + +#define F2FS_ROOT_INO(sbi) (sbi->root_ino_num) +#define F2FS_NODE_INO(sbi) (sbi->node_ino_num) +#define F2FS_META_INO(sbi) (sbi->meta_ino_num) + +/* This flag is used by node and meta inodes, and by recovery */ +#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO) + +/* + * For further optimization on multi-head logs, on-disk layout supports maximum + * 16 logs by default. The number, 16, is expected to cover all the cases + * enoughly. The implementaion currently uses no more than 6 logs. + * Half the logs are used for nodes, and the other half are used for data. + */ +#define MAX_ACTIVE_LOGS 16 +#define MAX_ACTIVE_NODE_LOGS 8 +#define MAX_ACTIVE_DATA_LOGS 8 + +/* + * For superblock + */ +struct f2fs_super_block { + __le32 magic; /* Magic Number */ + __le16 major_ver; /* Major Version */ + __le16 minor_ver; /* Minor Version */ + __le32 log_sectorsize; /* log2 sector size in bytes */ + __le32 log_sectors_per_block; /* log2 # of sectors per block */ + __le32 log_blocksize; /* log2 block size in bytes */ + __le32 log_blocks_per_seg; /* log2 # of blocks per segment */ + __le32 segs_per_sec; /* # of segments per section */ + __le32 secs_per_zone; /* # of sections per zone */ + __le32 checksum_offset; /* checksum offset inside super block */ + __le64 block_count; /* total # of user blocks */ + __le32 section_count; /* total # of sections */ + __le32 segment_count; /* total # of segments */ + __le32 segment_count_ckpt; /* # of segments for checkpoint */ + __le32 segment_count_sit; /* # of segments for SIT */ + __le32 segment_count_nat; /* # of segments for NAT */ + __le32 segment_count_ssa; /* # of segments for SSA */ + __le32 segment_count_main; /* # of segments for main area */ + __le32 segment0_blkaddr; /* start block address of segment 0 */ + __le32 cp_blkaddr; /* start block address of checkpoint */ + __le32 sit_blkaddr; /* start block address of SIT */ + __le32 nat_blkaddr; /* start block address of NAT */ + __le32 ssa_blkaddr; /* start block address of SSA */ + __le32 main_blkaddr; /* start block address of main area */ + __le32 root_ino; /* root inode number */ + __le32 node_ino; /* node inode number */ + __le32 meta_ino; /* meta inode number */ + __u8 uuid[16]; /* 128-bit uuid for volume */ + __le16 volume_name[512]; /* volume name */ + __le32 extension_count; /* # of extensions below */ + __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ +} __packed; + +/* + * For checkpoint + */ +#define CP_ERROR_FLAG 0x00000008 +#define CP_COMPACT_SUM_FLAG 0x00000004 +#define CP_ORPHAN_PRESENT_FLAG 0x00000002 +#define CP_UMOUNT_FLAG 0x00000001 + +struct f2fs_checkpoint { + __le64 checkpoint_ver; /* checkpoint block version number */ + __le64 user_block_count; /* # of user blocks */ + __le64 valid_block_count; /* # of valid blocks in main area */ + __le32 rsvd_segment_count; /* # of reserved segments for gc */ + __le32 overprov_segment_count; /* # of overprovision segments */ + __le32 free_segment_count; /* # of free segments in main area */ + + /* information of current node segments */ + __le32 cur_node_segno[MAX_ACTIVE_NODE_LOGS]; + __le16 cur_node_blkoff[MAX_ACTIVE_NODE_LOGS]; + /* information of current data segments */ + __le32 cur_data_segno[MAX_ACTIVE_DATA_LOGS]; + __le16 cur_data_blkoff[MAX_ACTIVE_DATA_LOGS]; + __le32 ckpt_flags; /* Flags : umount and journal_present */ + __le32 cp_pack_total_block_count; /* total # of one cp pack */ + __le32 cp_pack_start_sum; /* start block number of data summary */ + __le32 valid_node_count; /* Total number of valid nodes */ + __le32 valid_inode_count; /* Total number of valid inodes */ + __le32 next_free_nid; /* Next free node number */ + __le32 sit_ver_bitmap_bytesize; /* Default value 64 */ + __le32 nat_ver_bitmap_bytesize; /* Default value 256 */ + __le32 checksum_offset; /* checksum offset inside cp block */ + __le64 elapsed_time; /* mounted time */ + /* allocation type of current segment */ + unsigned char alloc_type[MAX_ACTIVE_LOGS]; + + /* SIT and NAT version bitmap */ + unsigned char sit_nat_version_bitmap[1]; +} __packed; + +/* + * For orphan inode management + */ +#define F2FS_ORPHANS_PER_BLOCK 1020 + +struct f2fs_orphan_block { + __le32 ino[F2FS_ORPHANS_PER_BLOCK]; /* inode numbers */ + __le32 reserved; /* reserved */ + __le16 blk_addr; /* block index in current CP */ + __le16 blk_count; /* Number of orphan inode blocks in CP */ + __le32 entry_count; /* Total number of orphan nodes in current CP */ + __le32 check_sum; /* CRC32 for orphan inode block */ +} __packed; + +/* + * For NODE structure + */ +struct f2fs_extent { + __le32 fofs; /* start file offset of the extent */ + __le32 blk_addr; /* start block address of the extent */ + __le32 len; /* lengh of the extent */ +} __packed; + +#define F2FS_MAX_NAME_LEN 256 +#define ADDRS_PER_INODE 923 /* Address Pointers in an Inode */ +#define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */ +#define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */ + +struct f2fs_inode { + __le16 i_mode; /* file mode */ + __u8 i_advise; /* file hints */ + __u8 i_reserved; /* reserved */ + __le32 i_uid; /* user ID */ + __le32 i_gid; /* group ID */ + __le32 i_links; /* links count */ + __le64 i_size; /* file size in bytes */ + __le64 i_blocks; /* file size in blocks */ + __le64 i_atime; /* access time */ + __le64 i_ctime; /* change time */ + __le64 i_mtime; /* modification time */ + __le32 i_atime_nsec; /* access time in nano scale */ + __le32 i_ctime_nsec; /* change time in nano scale */ + __le32 i_mtime_nsec; /* modification time in nano scale */ + __le32 i_generation; /* file version (for NFS) */ + __le32 i_current_depth; /* only for directory depth */ + __le32 i_xattr_nid; /* nid to save xattr */ + __le32 i_flags; /* file attributes */ + __le32 i_pino; /* parent inode number */ + __le32 i_namelen; /* file name length */ + __u8 i_name[F2FS_MAX_NAME_LEN]; /* file name for SPOR */ + + struct f2fs_extent i_ext; /* caching a largest extent */ + + __le32 i_addr[ADDRS_PER_INODE]; /* Pointers to data blocks */ + + __le32 i_nid[5]; /* direct(2), indirect(2), + double_indirect(1) node id */ +} __packed; + +struct direct_node { + __le32 addr[ADDRS_PER_BLOCK]; /* array of data block address */ +} __packed; + +struct indirect_node { + __le32 nid[NIDS_PER_BLOCK]; /* array of data block address */ +} __packed; + +enum { + COLD_BIT_SHIFT = 0, + FSYNC_BIT_SHIFT, + DENT_BIT_SHIFT, + OFFSET_BIT_SHIFT +}; + +struct node_footer { + __le32 nid; /* node id */ + __le32 ino; /* inode nunmber */ + __le32 flag; /* include cold/fsync/dentry marks and offset */ + __le64 cp_ver; /* checkpoint version */ + __le32 next_blkaddr; /* next node page block address */ +} __packed; + +struct f2fs_node { + /* can be one of three types: inode, direct, and indirect types */ + union { + struct f2fs_inode i; + struct direct_node dn; + struct indirect_node in; + }; + struct node_footer footer; +} __packed; + +/* + * For NAT entries + */ +#define NAT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_nat_entry)) + +struct f2fs_nat_entry { + __u8 version; /* latest version of cached nat entry */ + __le32 ino; /* inode number */ + __le32 block_addr; /* block address */ +} __packed; + +struct f2fs_nat_block { + struct f2fs_nat_entry entries[NAT_ENTRY_PER_BLOCK]; +} __packed; + +/* + * For SIT entries + * + * Each segment is 2MB in size by default so that a bitmap for validity of + * there-in blocks should occupy 64 bytes, 512 bits. + * Not allow to change this. + */ +#define SIT_VBLOCK_MAP_SIZE 64 +#define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry)) + +/* + * Note that f2fs_sit_entry->vblocks has the following bit-field information. + * [15:10] : allocation type such as CURSEG_XXXX_TYPE + * [9:0] : valid block count + */ +#define SIT_VBLOCKS_SHIFT 10 +#define SIT_VBLOCKS_MASK ((1 << SIT_VBLOCKS_SHIFT) - 1) +#define GET_SIT_VBLOCKS(raw_sit) \ + (le16_to_cpu((raw_sit)->vblocks) & SIT_VBLOCKS_MASK) +#define GET_SIT_TYPE(raw_sit) \ + ((le16_to_cpu((raw_sit)->vblocks) & ~SIT_VBLOCKS_MASK) \ + >> SIT_VBLOCKS_SHIFT) + +struct f2fs_sit_entry { + __le16 vblocks; /* reference above */ + __u8 valid_map[SIT_VBLOCK_MAP_SIZE]; /* bitmap for valid blocks */ + __le64 mtime; /* segment age for cleaning */ +} __packed; + +struct f2fs_sit_block { + struct f2fs_sit_entry entries[SIT_ENTRY_PER_BLOCK]; +} __packed; + +/* + * For segment summary + * + * One summary block contains exactly 512 summary entries, which represents + * exactly 2MB segment by default. Not allow to change the basic units. + * + * NOTE: For initializing fields, you must use set_summary + * + * - If data page, nid represents dnode's nid + * - If node page, nid represents the node page's nid. + * + * The ofs_in_node is used by only data page. It represents offset + * from node's page's beginning to get a data block address. + * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node) + */ +#define ENTRIES_IN_SUM 512 +#define SUMMARY_SIZE (sizeof(struct f2fs_summary)) +#define SUM_FOOTER_SIZE (sizeof(struct summary_footer)) +#define SUM_ENTRY_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM) + +/* a summary entry for a 4KB-sized block in a segment */ +struct f2fs_summary { + __le32 nid; /* parent node id */ + union { + __u8 reserved[3]; + struct { + __u8 version; /* node version number */ + __le16 ofs_in_node; /* block index in parent node */ + } __packed; + }; +} __packed; + +/* summary block type, node or data, is stored to the summary_footer */ +#define SUM_TYPE_NODE (1) +#define SUM_TYPE_DATA (0) + +struct summary_footer { + unsigned char entry_type; /* SUM_TYPE_XXX */ + __u32 check_sum; /* summary checksum */ +} __packed; + +#define SUM_JOURNAL_SIZE (PAGE_CACHE_SIZE - SUM_FOOTER_SIZE -\ + SUM_ENTRY_SIZE) +#define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ + sizeof(struct nat_journal_entry)) +#define NAT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ + sizeof(struct nat_journal_entry)) +#define SIT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ + sizeof(struct sit_journal_entry)) +#define SIT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ + sizeof(struct sit_journal_entry)) +/* + * frequently updated NAT/SIT entries can be stored in the spare area in + * summary blocks + */ +enum { + NAT_JOURNAL = 0, + SIT_JOURNAL +}; + +struct nat_journal_entry { + __le32 nid; + struct f2fs_nat_entry ne; +} __packed; + +struct nat_journal { + struct nat_journal_entry entries[NAT_JOURNAL_ENTRIES]; + __u8 reserved[NAT_JOURNAL_RESERVED]; +} __packed; + +struct sit_journal_entry { + __le32 segno; + struct f2fs_sit_entry se; +} __packed; + +struct sit_journal { + struct sit_journal_entry entries[SIT_JOURNAL_ENTRIES]; + __u8 reserved[SIT_JOURNAL_RESERVED]; +} __packed; + +/* 4KB-sized summary block structure */ +struct f2fs_summary_block { + struct f2fs_summary entries[ENTRIES_IN_SUM]; + union { + __le16 n_nats; + __le16 n_sits; + }; + /* spare area is used by NAT or SIT journals */ + union { + struct nat_journal nat_j; + struct sit_journal sit_j; + }; + struct summary_footer footer; +} __packed; + +/* + * For directory operations + */ +#define F2FS_DOT_HASH 0 +#define F2FS_DDOT_HASH F2FS_DOT_HASH +#define F2FS_MAX_HASH (~((0x3ULL) << 62)) +#define F2FS_HASH_COL_BIT ((0x1ULL) << 63) + +typedef __le32 f2fs_hash_t; + +/* One directory entry slot covers 8bytes-long file name */ +#define F2FS_NAME_LEN 8 + +/* the number of dentry in a block */ +#define NR_DENTRY_IN_BLOCK 214 + +/* MAX level for dir lookup */ +#define MAX_DIR_HASH_DEPTH 63 + +#define SIZE_OF_DIR_ENTRY 11 /* by byte */ +#define SIZE_OF_DENTRY_BITMAP ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \ + BITS_PER_BYTE) +#define SIZE_OF_RESERVED (PAGE_SIZE - ((SIZE_OF_DIR_ENTRY + \ + F2FS_NAME_LEN) * \ + NR_DENTRY_IN_BLOCK + SIZE_OF_DENTRY_BITMAP)) + +/* One directory entry slot representing F2FS_NAME_LEN-sized file name */ +struct f2fs_dir_entry { + __le32 hash_code; /* hash code of file name */ + __le32 ino; /* inode number */ + __le16 name_len; /* lengh of file name */ + __u8 file_type; /* file type */ +} __packed; + +/* 4KB-sized directory entry block */ +struct f2fs_dentry_block { + /* validity bitmap for directory entries in each block */ + __u8 dentry_bitmap[SIZE_OF_DENTRY_BITMAP]; + __u8 reserved[SIZE_OF_RESERVED]; + struct f2fs_dir_entry dentry[NR_DENTRY_IN_BLOCK]; + __u8 filename[NR_DENTRY_IN_BLOCK][F2FS_NAME_LEN]; +} __packed; + +/* file types used in inode_info->flags */ +enum { + F2FS_FT_UNKNOWN, + F2FS_FT_REG_FILE, + F2FS_FT_DIR, + F2FS_FT_CHRDEV, + F2FS_FT_BLKDEV, + F2FS_FT_FIFO, + F2FS_FT_SOCK, + F2FS_FT_SYMLINK, + F2FS_FT_MAX +}; + +#endif /* _LINUX_F2FS_FS_H */ -- cgit v0.10.2 From 39a53e0ce0df01b3cf4bb898c7ae2fd2189647d5 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 28 Nov 2012 13:37:31 +0900 Subject: f2fs: add superblock and major in-memory structure This adds the following major in-memory structures in f2fs. - f2fs_sb_info: contains f2fs-specific information, two special inode pointers for node and meta address spaces, and orphan inode management. - f2fs_inode_info: contains vfs_inode and other fs-specific information. - f2fs_nm_info: contains node manager information such as NAT entry cache, free nid list, and NAT page management. - f2fs_node_info: represents a node as node id, inode number, block address, and its version. - f2fs_sm_info: contains segment manager information such as SIT entry cache, free segment map, current active logs, dirty segment management, and segment utilization. The specific structures are sit_info, free_segmap_info, dirty_seglist_info, curseg_info. In addition, add F2FS_SUPER_MAGIC in magic.h. Signed-off-by: Chul Lee Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h new file mode 100644 index 0000000..7aa70b5 --- /dev/null +++ b/fs/f2fs/f2fs.h @@ -0,0 +1,1062 @@ +/** + * fs/f2fs/f2fs.h + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _LINUX_F2FS_H +#define _LINUX_F2FS_H + +#include +#include +#include +#include +#include +#include +#include + +/* + * For mount options + */ +#define F2FS_MOUNT_BG_GC 0x00000001 +#define F2FS_MOUNT_DISABLE_ROLL_FORWARD 0x00000002 +#define F2FS_MOUNT_DISCARD 0x00000004 +#define F2FS_MOUNT_NOHEAP 0x00000008 +#define F2FS_MOUNT_XATTR_USER 0x00000010 +#define F2FS_MOUNT_POSIX_ACL 0x00000020 +#define F2FS_MOUNT_DISABLE_EXT_IDENTIFY 0x00000040 + +#define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option) +#define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option) +#define test_opt(sbi, option) (sbi->mount_opt.opt & F2FS_MOUNT_##option) + +#define ver_after(a, b) (typecheck(unsigned long long, a) && \ + typecheck(unsigned long long, b) && \ + ((long long)((a) - (b)) > 0)) + +typedef u64 block_t; +typedef u32 nid_t; + +struct f2fs_mount_info { + unsigned int opt; +}; + +static inline __u32 f2fs_crc32(void *buff, size_t len) +{ + return crc32_le(F2FS_SUPER_MAGIC, buff, len); +} + +static inline bool f2fs_crc_valid(__u32 blk_crc, void *buff, size_t buff_size) +{ + return f2fs_crc32(buff, buff_size) == blk_crc; +} + +/* + * For checkpoint manager + */ +enum { + NAT_BITMAP, + SIT_BITMAP +}; + +/* for the list of orphan inodes */ +struct orphan_inode_entry { + struct list_head list; /* list head */ + nid_t ino; /* inode number */ +}; + +/* for the list of directory inodes */ +struct dir_inode_entry { + struct list_head list; /* list head */ + struct inode *inode; /* vfs inode pointer */ +}; + +/* for the list of fsync inodes, used only during recovery */ +struct fsync_inode_entry { + struct list_head list; /* list head */ + struct inode *inode; /* vfs inode pointer */ + block_t blkaddr; /* block address locating the last inode */ +}; + +#define nats_in_cursum(sum) (le16_to_cpu(sum->n_nats)) +#define sits_in_cursum(sum) (le16_to_cpu(sum->n_sits)) + +#define nat_in_journal(sum, i) (sum->nat_j.entries[i].ne) +#define nid_in_journal(sum, i) (sum->nat_j.entries[i].nid) +#define sit_in_journal(sum, i) (sum->sit_j.entries[i].se) +#define segno_in_journal(sum, i) (sum->sit_j.entries[i].segno) + +static inline int update_nats_in_cursum(struct f2fs_summary_block *rs, int i) +{ + int before = nats_in_cursum(rs); + rs->n_nats = cpu_to_le16(before + i); + return before; +} + +static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i) +{ + int before = sits_in_cursum(rs); + rs->n_sits = cpu_to_le16(before + i); + return before; +} + +/* + * For INODE and NODE manager + */ +#define XATTR_NODE_OFFSET (-1) /* + * store xattrs to one node block per + * file keeping -1 as its node offset to + * distinguish from index node blocks. + */ +#define RDONLY_NODE 1 /* + * specify a read-only mode when getting + * a node block. 0 is read-write mode. + * used by get_dnode_of_data(). + */ +#define F2FS_LINK_MAX 32000 /* maximum link count per file */ + +/* for in-memory extent cache entry */ +struct extent_info { + rwlock_t ext_lock; /* rwlock for consistency */ + unsigned int fofs; /* start offset in a file */ + u32 blk_addr; /* start block address of the extent */ + unsigned int len; /* lenth of the extent */ +}; + +/* + * i_advise uses FADVISE_XXX_BIT. We can add additional hints later. + */ +#define FADVISE_COLD_BIT 0x01 + +struct f2fs_inode_info { + struct inode vfs_inode; /* serve a vfs inode */ + unsigned long i_flags; /* keep an inode flags for ioctl */ + unsigned char i_advise; /* use to give file attribute hints */ + unsigned int i_current_depth; /* use only in directory structure */ + umode_t i_acl_mode; /* keep file acl mode temporarily */ + + /* Use below internally in f2fs*/ + unsigned long flags; /* use to pass per-file flags */ + unsigned long long data_version;/* lastes version of data for fsync */ + atomic_t dirty_dents; /* # of dirty dentry pages */ + f2fs_hash_t chash; /* hash value of given file name */ + unsigned int clevel; /* maximum level of given file name */ + nid_t i_xattr_nid; /* node id that contains xattrs */ + struct extent_info ext; /* in-memory extent cache entry */ +}; + +static inline void get_extent_info(struct extent_info *ext, + struct f2fs_extent i_ext) +{ + write_lock(&ext->ext_lock); + ext->fofs = le32_to_cpu(i_ext.fofs); + ext->blk_addr = le32_to_cpu(i_ext.blk_addr); + ext->len = le32_to_cpu(i_ext.len); + write_unlock(&ext->ext_lock); +} + +static inline void set_raw_extent(struct extent_info *ext, + struct f2fs_extent *i_ext) +{ + read_lock(&ext->ext_lock); + i_ext->fofs = cpu_to_le32(ext->fofs); + i_ext->blk_addr = cpu_to_le32(ext->blk_addr); + i_ext->len = cpu_to_le32(ext->len); + read_unlock(&ext->ext_lock); +} + +struct f2fs_nm_info { + block_t nat_blkaddr; /* base disk address of NAT */ + nid_t max_nid; /* maximum possible node ids */ + nid_t init_scan_nid; /* the first nid to be scanned */ + nid_t next_scan_nid; /* the next nid to be scanned */ + + /* NAT cache management */ + struct radix_tree_root nat_root;/* root of the nat entry cache */ + rwlock_t nat_tree_lock; /* protect nat_tree_lock */ + unsigned int nat_cnt; /* the # of cached nat entries */ + struct list_head nat_entries; /* cached nat entry list (clean) */ + struct list_head dirty_nat_entries; /* cached nat entry list (dirty) */ + + /* free node ids management */ + struct list_head free_nid_list; /* a list for free nids */ + spinlock_t free_nid_list_lock; /* protect free nid list */ + unsigned int fcnt; /* the number of free node id */ + struct mutex build_lock; /* lock for build free nids */ + + /* for checkpoint */ + char *nat_bitmap; /* NAT bitmap pointer */ + int bitmap_size; /* bitmap size */ +}; + +/* + * this structure is used as one of function parameters. + * all the information are dedicated to a given direct node block determined + * by the data offset in a file. + */ +struct dnode_of_data { + struct inode *inode; /* vfs inode pointer */ + struct page *inode_page; /* its inode page, NULL is possible */ + struct page *node_page; /* cached direct node page */ + nid_t nid; /* node id of the direct node block */ + unsigned int ofs_in_node; /* data offset in the node page */ + bool inode_page_locked; /* inode page is locked or not */ + block_t data_blkaddr; /* block address of the node block */ +}; + +static inline void set_new_dnode(struct dnode_of_data *dn, struct inode *inode, + struct page *ipage, struct page *npage, nid_t nid) +{ + dn->inode = inode; + dn->inode_page = ipage; + dn->node_page = npage; + dn->nid = nid; + dn->inode_page_locked = 0; +} + +/* + * For SIT manager + * + * By default, there are 6 active log areas across the whole main area. + * When considering hot and cold data separation to reduce cleaning overhead, + * we split 3 for data logs and 3 for node logs as hot, warm, and cold types, + * respectively. + * In the current design, you should not change the numbers intentionally. + * Instead, as a mount option such as active_logs=x, you can use 2, 4, and 6 + * logs individually according to the underlying devices. (default: 6) + * Just in case, on-disk layout covers maximum 16 logs that consist of 8 for + * data and 8 for node logs. + */ +#define NR_CURSEG_DATA_TYPE (3) +#define NR_CURSEG_NODE_TYPE (3) +#define NR_CURSEG_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE) + +enum { + CURSEG_HOT_DATA = 0, /* directory entry blocks */ + CURSEG_WARM_DATA, /* data blocks */ + CURSEG_COLD_DATA, /* multimedia or GCed data blocks */ + CURSEG_HOT_NODE, /* direct node blocks of directory files */ + CURSEG_WARM_NODE, /* direct node blocks of normal files */ + CURSEG_COLD_NODE, /* indirect node blocks */ + NO_CHECK_TYPE +}; + +struct f2fs_sm_info { + struct sit_info *sit_info; /* whole segment information */ + struct free_segmap_info *free_info; /* free segment information */ + struct dirty_seglist_info *dirty_info; /* dirty segment information */ + struct curseg_info *curseg_array; /* active segment information */ + + struct list_head wblist_head; /* list of under-writeback pages */ + spinlock_t wblist_lock; /* lock for checkpoint */ + + block_t seg0_blkaddr; /* block address of 0'th segment */ + block_t main_blkaddr; /* start block address of main area */ + block_t ssa_blkaddr; /* start block address of SSA area */ + + unsigned int segment_count; /* total # of segments */ + unsigned int main_segments; /* # of segments in main area */ + unsigned int reserved_segments; /* # of reserved segments */ + unsigned int ovp_segments; /* # of overprovision segments */ +}; + +/* + * For directory operation + */ +#define NODE_DIR1_BLOCK (ADDRS_PER_INODE + 1) +#define NODE_DIR2_BLOCK (ADDRS_PER_INODE + 2) +#define NODE_IND1_BLOCK (ADDRS_PER_INODE + 3) +#define NODE_IND2_BLOCK (ADDRS_PER_INODE + 4) +#define NODE_DIND_BLOCK (ADDRS_PER_INODE + 5) + +/* + * For superblock + */ +/* + * COUNT_TYPE for monitoring + * + * f2fs monitors the number of several block types such as on-writeback, + * dirty dentry blocks, dirty node blocks, and dirty meta blocks. + */ +enum count_type { + F2FS_WRITEBACK, + F2FS_DIRTY_DENTS, + F2FS_DIRTY_NODES, + F2FS_DIRTY_META, + NR_COUNT_TYPE, +}; + +/* + * FS_LOCK nesting subclasses for the lock validator: + * + * The locking order between these classes is + * RENAME -> DENTRY_OPS -> DATA_WRITE -> DATA_NEW + * -> DATA_TRUNC -> NODE_WRITE -> NODE_NEW -> NODE_TRUNC + */ +enum lock_type { + RENAME, /* for renaming operations */ + DENTRY_OPS, /* for directory operations */ + DATA_WRITE, /* for data write */ + DATA_NEW, /* for data allocation */ + DATA_TRUNC, /* for data truncate */ + NODE_NEW, /* for node allocation */ + NODE_TRUNC, /* for node truncate */ + NODE_WRITE, /* for node write */ + NR_LOCK_TYPE, +}; + +/* + * The below are the page types of bios used in submti_bio(). + * The available types are: + * DATA User data pages. It operates as async mode. + * NODE Node pages. It operates as async mode. + * META FS metadata pages such as SIT, NAT, CP. + * NR_PAGE_TYPE The number of page types. + * META_FLUSH Make sure the previous pages are written + * with waiting the bio's completion + * ... Only can be used with META. + */ +enum page_type { + DATA, + NODE, + META, + NR_PAGE_TYPE, + META_FLUSH, +}; + +struct f2fs_sb_info { + struct super_block *sb; /* pointer to VFS super block */ + struct buffer_head *raw_super_buf; /* buffer head of raw sb */ + struct f2fs_super_block *raw_super; /* raw super block pointer */ + int s_dirty; /* dirty flag for checkpoint */ + + /* for node-related operations */ + struct f2fs_nm_info *nm_info; /* node manager */ + struct inode *node_inode; /* cache node blocks */ + + /* for segment-related operations */ + struct f2fs_sm_info *sm_info; /* segment manager */ + struct bio *bio[NR_PAGE_TYPE]; /* bios to merge */ + sector_t last_block_in_bio[NR_PAGE_TYPE]; /* last block number */ + struct rw_semaphore bio_sem; /* IO semaphore */ + + /* for checkpoint */ + struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */ + struct inode *meta_inode; /* cache meta blocks */ + struct mutex cp_mutex; /* for checkpoint procedure */ + struct mutex fs_lock[NR_LOCK_TYPE]; /* for blocking FS operations */ + struct mutex write_inode; /* mutex for write inode */ + struct mutex writepages; /* mutex for writepages() */ + int por_doing; /* recovery is doing or not */ + + /* for orphan inode management */ + struct list_head orphan_inode_list; /* orphan inode list */ + struct mutex orphan_inode_mutex; /* for orphan inode list */ + unsigned int n_orphans; /* # of orphan inodes */ + + /* for directory inode management */ + struct list_head dir_inode_list; /* dir inode list */ + spinlock_t dir_inode_lock; /* for dir inode list lock */ + unsigned int n_dirty_dirs; /* # of dir inodes */ + + /* basic file system units */ + unsigned int log_sectors_per_block; /* log2 sectors per block */ + unsigned int log_blocksize; /* log2 block size */ + unsigned int blocksize; /* block size */ + unsigned int root_ino_num; /* root inode number*/ + unsigned int node_ino_num; /* node inode number*/ + unsigned int meta_ino_num; /* meta inode number*/ + unsigned int log_blocks_per_seg; /* log2 blocks per segment */ + unsigned int blocks_per_seg; /* blocks per segment */ + unsigned int segs_per_sec; /* segments per section */ + unsigned int secs_per_zone; /* sections per zone */ + unsigned int total_sections; /* total section count */ + unsigned int total_node_count; /* total node block count */ + unsigned int total_valid_node_count; /* valid node block count */ + unsigned int total_valid_inode_count; /* valid inode count */ + int active_logs; /* # of active logs */ + + block_t user_block_count; /* # of user blocks */ + block_t total_valid_block_count; /* # of valid blocks */ + block_t alloc_valid_block_count; /* # of allocated blocks */ + block_t last_valid_block_count; /* for recovery */ + u32 s_next_generation; /* for NFS support */ + atomic_t nr_pages[NR_COUNT_TYPE]; /* # of pages, see count_type */ + + struct f2fs_mount_info mount_opt; /* mount options */ + + /* for cleaning operations */ + struct mutex gc_mutex; /* mutex for GC */ + struct f2fs_gc_kthread *gc_thread; /* GC thread */ + + /* + * for stat information. + * one is for the LFS mode, and the other is for the SSR mode. + */ + struct f2fs_stat_info *stat_info; /* FS status information */ + unsigned int segment_count[2]; /* # of allocated segments */ + unsigned int block_count[2]; /* # of allocated blocks */ + unsigned int last_victim[2]; /* last victim segment # */ + int total_hit_ext, read_hit_ext; /* extent cache hit ratio */ + int bg_gc; /* background gc calls */ + spinlock_t stat_lock; /* lock for stat operations */ +}; + +/* + * Inline functions + */ +static inline struct f2fs_inode_info *F2FS_I(struct inode *inode) +{ + return container_of(inode, struct f2fs_inode_info, vfs_inode); +} + +static inline struct f2fs_sb_info *F2FS_SB(struct super_block *sb) +{ + return sb->s_fs_info; +} + +static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_super_block *)(sbi->raw_super); +} + +static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_checkpoint *)(sbi->ckpt); +} + +static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_nm_info *)(sbi->nm_info); +} + +static inline struct f2fs_sm_info *SM_I(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_sm_info *)(sbi->sm_info); +} + +static inline struct sit_info *SIT_I(struct f2fs_sb_info *sbi) +{ + return (struct sit_info *)(SM_I(sbi)->sit_info); +} + +static inline struct free_segmap_info *FREE_I(struct f2fs_sb_info *sbi) +{ + return (struct free_segmap_info *)(SM_I(sbi)->free_info); +} + +static inline struct dirty_seglist_info *DIRTY_I(struct f2fs_sb_info *sbi) +{ + return (struct dirty_seglist_info *)(SM_I(sbi)->dirty_info); +} + +static inline void F2FS_SET_SB_DIRT(struct f2fs_sb_info *sbi) +{ + sbi->s_dirty = 1; +} + +static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi) +{ + sbi->s_dirty = 0; +} + +static inline void mutex_lock_op(struct f2fs_sb_info *sbi, enum lock_type t) +{ + mutex_lock_nested(&sbi->fs_lock[t], t); +} + +static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, enum lock_type t) +{ + mutex_unlock(&sbi->fs_lock[t]); +} + +/* + * Check whether the given nid is within node id range. + */ +static inline void check_nid_range(struct f2fs_sb_info *sbi, nid_t nid) +{ + BUG_ON((nid >= NM_I(sbi)->max_nid)); +} + +#define F2FS_DEFAULT_ALLOCATED_BLOCKS 1 + +/* + * Check whether the inode has blocks or not + */ +static inline int F2FS_HAS_BLOCKS(struct inode *inode) +{ + if (F2FS_I(inode)->i_xattr_nid) + return (inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS + 1); + else + return (inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS); +} + +static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi, + struct inode *inode, blkcnt_t count) +{ + block_t valid_block_count; + + spin_lock(&sbi->stat_lock); + valid_block_count = + sbi->total_valid_block_count + (block_t)count; + if (valid_block_count > sbi->user_block_count) { + spin_unlock(&sbi->stat_lock); + return false; + } + inode->i_blocks += count; + sbi->total_valid_block_count = valid_block_count; + sbi->alloc_valid_block_count += (block_t)count; + spin_unlock(&sbi->stat_lock); + return true; +} + +static inline int dec_valid_block_count(struct f2fs_sb_info *sbi, + struct inode *inode, + blkcnt_t count) +{ + spin_lock(&sbi->stat_lock); + BUG_ON(sbi->total_valid_block_count < (block_t) count); + BUG_ON(inode->i_blocks < count); + inode->i_blocks -= count; + sbi->total_valid_block_count -= (block_t)count; + spin_unlock(&sbi->stat_lock); + return 0; +} + +static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type) +{ + atomic_inc(&sbi->nr_pages[count_type]); + F2FS_SET_SB_DIRT(sbi); +} + +static inline void inode_inc_dirty_dents(struct inode *inode) +{ + atomic_inc(&F2FS_I(inode)->dirty_dents); +} + +static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type) +{ + atomic_dec(&sbi->nr_pages[count_type]); +} + +static inline void inode_dec_dirty_dents(struct inode *inode) +{ + atomic_dec(&F2FS_I(inode)->dirty_dents); +} + +static inline int get_pages(struct f2fs_sb_info *sbi, int count_type) +{ + return atomic_read(&sbi->nr_pages[count_type]); +} + +static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi) +{ + block_t ret; + spin_lock(&sbi->stat_lock); + ret = sbi->total_valid_block_count; + spin_unlock(&sbi->stat_lock); + return ret; +} + +static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + + /* return NAT or SIT bitmap */ + if (flag == NAT_BITMAP) + return le32_to_cpu(ckpt->nat_ver_bitmap_bytesize); + else if (flag == SIT_BITMAP) + return le32_to_cpu(ckpt->sit_ver_bitmap_bytesize); + + return 0; +} + +static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + int offset = (flag == NAT_BITMAP) ? ckpt->sit_ver_bitmap_bytesize : 0; + return &ckpt->sit_nat_version_bitmap + offset; +} + +static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi) +{ + block_t start_addr; + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + unsigned long long ckpt_version = le64_to_cpu(ckpt->checkpoint_ver); + + start_addr = le64_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); + + /* + * odd numbered checkpoint should at cp segment 0 + * and even segent must be at cp segment 1 + */ + if (!(ckpt_version & 1)) + start_addr += sbi->blocks_per_seg; + + return start_addr; +} + +static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi) +{ + return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); +} + +static inline bool inc_valid_node_count(struct f2fs_sb_info *sbi, + struct inode *inode, + unsigned int count) +{ + block_t valid_block_count; + unsigned int valid_node_count; + + spin_lock(&sbi->stat_lock); + + valid_block_count = sbi->total_valid_block_count + (block_t)count; + sbi->alloc_valid_block_count += (block_t)count; + valid_node_count = sbi->total_valid_node_count + count; + + if (valid_block_count > sbi->user_block_count) { + spin_unlock(&sbi->stat_lock); + return false; + } + + if (valid_node_count > sbi->total_node_count) { + spin_unlock(&sbi->stat_lock); + return false; + } + + if (inode) + inode->i_blocks += count; + sbi->total_valid_node_count = valid_node_count; + sbi->total_valid_block_count = valid_block_count; + spin_unlock(&sbi->stat_lock); + + return true; +} + +static inline void dec_valid_node_count(struct f2fs_sb_info *sbi, + struct inode *inode, + unsigned int count) +{ + spin_lock(&sbi->stat_lock); + + BUG_ON(sbi->total_valid_block_count < count); + BUG_ON(sbi->total_valid_node_count < count); + BUG_ON(inode->i_blocks < count); + + inode->i_blocks -= count; + sbi->total_valid_node_count -= count; + sbi->total_valid_block_count -= (block_t)count; + + spin_unlock(&sbi->stat_lock); +} + +static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi) +{ + unsigned int ret; + spin_lock(&sbi->stat_lock); + ret = sbi->total_valid_node_count; + spin_unlock(&sbi->stat_lock); + return ret; +} + +static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi) +{ + spin_lock(&sbi->stat_lock); + BUG_ON(sbi->total_valid_inode_count == sbi->total_node_count); + sbi->total_valid_inode_count++; + spin_unlock(&sbi->stat_lock); +} + +static inline int dec_valid_inode_count(struct f2fs_sb_info *sbi) +{ + spin_lock(&sbi->stat_lock); + BUG_ON(!sbi->total_valid_inode_count); + sbi->total_valid_inode_count--; + spin_unlock(&sbi->stat_lock); + return 0; +} + +static inline unsigned int valid_inode_count(struct f2fs_sb_info *sbi) +{ + unsigned int ret; + spin_lock(&sbi->stat_lock); + ret = sbi->total_valid_inode_count; + spin_unlock(&sbi->stat_lock); + return ret; +} + +static inline void f2fs_put_page(struct page *page, int unlock) +{ + if (!page || IS_ERR(page)) + return; + + if (unlock) { + BUG_ON(!PageLocked(page)); + unlock_page(page); + } + page_cache_release(page); +} + +static inline void f2fs_put_dnode(struct dnode_of_data *dn) +{ + if (dn->node_page) + f2fs_put_page(dn->node_page, 1); + if (dn->inode_page && dn->node_page != dn->inode_page) + f2fs_put_page(dn->inode_page, 0); + dn->node_page = NULL; + dn->inode_page = NULL; +} + +static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name, + size_t size, void (*ctor)(void *)) +{ + return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, ctor); +} + +#define RAW_IS_INODE(p) ((p)->footer.nid == (p)->footer.ino) + +static inline bool IS_INODE(struct page *page) +{ + struct f2fs_node *p = (struct f2fs_node *)page_address(page); + return RAW_IS_INODE(p); +} + +static inline __le32 *blkaddr_in_node(struct f2fs_node *node) +{ + return RAW_IS_INODE(node) ? node->i.i_addr : node->dn.addr; +} + +static inline block_t datablock_addr(struct page *node_page, + unsigned int offset) +{ + struct f2fs_node *raw_node; + __le32 *addr_array; + raw_node = (struct f2fs_node *)page_address(node_page); + addr_array = blkaddr_in_node(raw_node); + return le32_to_cpu(addr_array[offset]); +} + +static inline int f2fs_test_bit(unsigned int nr, char *addr) +{ + int mask; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + return mask & *addr; +} + +static inline int f2fs_set_bit(unsigned int nr, char *addr) +{ + int mask; + int ret; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + ret = mask & *addr; + *addr |= mask; + return ret; +} + +static inline int f2fs_clear_bit(unsigned int nr, char *addr) +{ + int mask; + int ret; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + ret = mask & *addr; + *addr &= ~mask; + return ret; +} + +/* used for f2fs_inode_info->flags */ +enum { + FI_NEW_INODE, /* indicate newly allocated inode */ + FI_NEED_CP, /* need to do checkpoint during fsync */ + FI_INC_LINK, /* need to increment i_nlink */ + FI_ACL_MODE, /* indicate acl mode */ + FI_NO_ALLOC, /* should not allocate any blocks */ +}; + +static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag) +{ + set_bit(flag, &fi->flags); +} + +static inline int is_inode_flag_set(struct f2fs_inode_info *fi, int flag) +{ + return test_bit(flag, &fi->flags); +} + +static inline void clear_inode_flag(struct f2fs_inode_info *fi, int flag) +{ + clear_bit(flag, &fi->flags); +} + +static inline void set_acl_inode(struct f2fs_inode_info *fi, umode_t mode) +{ + fi->i_acl_mode = mode; + set_inode_flag(fi, FI_ACL_MODE); +} + +static inline int cond_clear_inode_flag(struct f2fs_inode_info *fi, int flag) +{ + if (is_inode_flag_set(fi, FI_ACL_MODE)) { + clear_inode_flag(fi, FI_ACL_MODE); + return 1; + } + return 0; +} + +/* + * file.c + */ +int f2fs_sync_file(struct file *, loff_t, loff_t, int); +void truncate_data_blocks(struct dnode_of_data *); +void f2fs_truncate(struct inode *); +int f2fs_setattr(struct dentry *, struct iattr *); +int truncate_hole(struct inode *, pgoff_t, pgoff_t); +long f2fs_ioctl(struct file *, unsigned int, unsigned long); + +/* + * inode.c + */ +void f2fs_set_inode_flags(struct inode *); +struct inode *f2fs_iget_nowait(struct super_block *, unsigned long); +struct inode *f2fs_iget(struct super_block *, unsigned long); +void update_inode(struct inode *, struct page *); +int f2fs_write_inode(struct inode *, struct writeback_control *); +void f2fs_evict_inode(struct inode *); + +/* + * namei.c + */ +struct dentry *f2fs_get_parent(struct dentry *child); + +/* + * dir.c + */ +struct f2fs_dir_entry *f2fs_find_entry(struct inode *, struct qstr *, + struct page **); +struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **); +ino_t f2fs_inode_by_name(struct inode *, struct qstr *); +void f2fs_set_link(struct inode *, struct f2fs_dir_entry *, + struct page *, struct inode *); +void init_dent_inode(struct dentry *, struct page *); +int f2fs_add_link(struct dentry *, struct inode *); +void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *); +int f2fs_make_empty(struct inode *, struct inode *); +bool f2fs_empty_dir(struct inode *); + +/* + * super.c + */ +int f2fs_sync_fs(struct super_block *, int); + +/* + * hash.c + */ +f2fs_hash_t f2fs_dentry_hash(const char *, int); + +/* + * node.c + */ +struct dnode_of_data; +struct node_info; + +int is_checkpointed_node(struct f2fs_sb_info *, nid_t); +void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); +int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int); +int truncate_inode_blocks(struct inode *, pgoff_t); +int remove_inode_page(struct inode *); +int new_inode_page(struct inode *, struct dentry *); +struct page *new_node_page(struct dnode_of_data *, unsigned int); +void ra_node_page(struct f2fs_sb_info *, nid_t); +struct page *get_node_page(struct f2fs_sb_info *, pgoff_t); +struct page *get_node_page_ra(struct page *, int); +void sync_inode_page(struct dnode_of_data *); +int sync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *); +bool alloc_nid(struct f2fs_sb_info *, nid_t *); +void alloc_nid_done(struct f2fs_sb_info *, nid_t); +void alloc_nid_failed(struct f2fs_sb_info *, nid_t); +void recover_node_page(struct f2fs_sb_info *, struct page *, + struct f2fs_summary *, struct node_info *, block_t); +int recover_inode_page(struct f2fs_sb_info *, struct page *); +int restore_node_summary(struct f2fs_sb_info *, unsigned int, + struct f2fs_summary_block *); +void flush_nat_entries(struct f2fs_sb_info *); +int build_node_manager(struct f2fs_sb_info *); +void destroy_node_manager(struct f2fs_sb_info *); +int create_node_manager_caches(void); +void destroy_node_manager_caches(void); + +/* + * segment.c + */ +void f2fs_balance_fs(struct f2fs_sb_info *); +void invalidate_blocks(struct f2fs_sb_info *, block_t); +void locate_dirty_segment(struct f2fs_sb_info *, unsigned int); +void clear_prefree_segments(struct f2fs_sb_info *); +int npages_for_summary_flush(struct f2fs_sb_info *); +void allocate_new_segments(struct f2fs_sb_info *); +struct page *get_sum_page(struct f2fs_sb_info *, unsigned int); +struct bio *f2fs_bio_alloc(struct block_device *, sector_t, int, gfp_t); +void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync); +int write_meta_page(struct f2fs_sb_info *, struct page *, + struct writeback_control *); +void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int, + block_t, block_t *); +void write_data_page(struct inode *, struct page *, struct dnode_of_data*, + block_t, block_t *); +void rewrite_data_page(struct f2fs_sb_info *, struct page *, block_t); +void recover_data_page(struct f2fs_sb_info *, struct page *, + struct f2fs_summary *, block_t, block_t); +void rewrite_node_page(struct f2fs_sb_info *, struct page *, + struct f2fs_summary *, block_t, block_t); +void write_data_summaries(struct f2fs_sb_info *, block_t); +void write_node_summaries(struct f2fs_sb_info *, block_t); +int lookup_journal_in_cursum(struct f2fs_summary_block *, + int, unsigned int, int); +void flush_sit_entries(struct f2fs_sb_info *); +int build_segment_manager(struct f2fs_sb_info *); +void reset_victim_segmap(struct f2fs_sb_info *); +void destroy_segment_manager(struct f2fs_sb_info *); + +/* + * checkpoint.c + */ +struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); +struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); +long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long); +int check_orphan_space(struct f2fs_sb_info *); +void add_orphan_inode(struct f2fs_sb_info *, nid_t); +void remove_orphan_inode(struct f2fs_sb_info *, nid_t); +int recover_orphan_inodes(struct f2fs_sb_info *); +int get_valid_checkpoint(struct f2fs_sb_info *); +void set_dirty_dir_page(struct inode *, struct page *); +void remove_dirty_dir_inode(struct inode *); +void sync_dirty_dir_inodes(struct f2fs_sb_info *); +void block_operations(struct f2fs_sb_info *); +void write_checkpoint(struct f2fs_sb_info *, bool, bool); +void init_orphan_info(struct f2fs_sb_info *); +int create_checkpoint_caches(void); +void destroy_checkpoint_caches(void); + +/* + * data.c + */ +int reserve_new_block(struct dnode_of_data *); +void update_extent_cache(block_t, struct dnode_of_data *); +struct page *find_data_page(struct inode *, pgoff_t); +struct page *get_lock_data_page(struct inode *, pgoff_t); +struct page *get_new_data_page(struct inode *, pgoff_t, bool); +int f2fs_readpage(struct f2fs_sb_info *, struct page *, block_t, int); +int do_write_data_page(struct page *); + +/* + * gc.c + */ +int start_gc_thread(struct f2fs_sb_info *); +void stop_gc_thread(struct f2fs_sb_info *); +block_t start_bidx_of_node(unsigned int); +int f2fs_gc(struct f2fs_sb_info *, int); +void build_gc_manager(struct f2fs_sb_info *); +int create_gc_caches(void); +void destroy_gc_caches(void); + +/* + * recovery.c + */ +void recover_fsync_data(struct f2fs_sb_info *); +bool space_for_roll_forward(struct f2fs_sb_info *); + +/* + * debug.c + */ +#ifdef CONFIG_F2FS_STAT_FS +struct f2fs_stat_info { + struct list_head stat_list; + struct f2fs_sb_info *sbi; + struct mutex stat_lock; + int all_area_segs, sit_area_segs, nat_area_segs, ssa_area_segs; + int main_area_segs, main_area_sections, main_area_zones; + int hit_ext, total_ext; + int ndirty_node, ndirty_dent, ndirty_dirs, ndirty_meta; + int nats, sits, fnids; + int total_count, utilization; + int bg_gc; + unsigned int valid_count, valid_node_count, valid_inode_count; + unsigned int bimodal, avg_vblocks; + int util_free, util_valid, util_invalid; + int rsvd_segs, overp_segs; + int dirty_count, node_pages, meta_pages; + int prefree_count, call_count; + int tot_segs, node_segs, data_segs, free_segs, free_secs; + int tot_blks, data_blks, node_blks; + int curseg[NR_CURSEG_TYPE]; + int cursec[NR_CURSEG_TYPE]; + int curzone[NR_CURSEG_TYPE]; + + unsigned int segment_count[2]; + unsigned int block_count[2]; + unsigned base_mem, cache_mem; +}; + +#define stat_inc_call_count(si) ((si)->call_count++) + +#define stat_inc_seg_count(sbi, type) \ + do { \ + struct f2fs_stat_info *si = sbi->stat_info; \ + (si)->tot_segs++; \ + if (type == SUM_TYPE_DATA) \ + si->data_segs++; \ + else \ + si->node_segs++; \ + } while (0) + +#define stat_inc_tot_blk_count(si, blks) \ + (si->tot_blks += (blks)) + +#define stat_inc_data_blk_count(sbi, blks) \ + do { \ + struct f2fs_stat_info *si = sbi->stat_info; \ + stat_inc_tot_blk_count(si, blks); \ + si->data_blks += (blks); \ + } while (0) + +#define stat_inc_node_blk_count(sbi, blks) \ + do { \ + struct f2fs_stat_info *si = sbi->stat_info; \ + stat_inc_tot_blk_count(si, blks); \ + si->node_blks += (blks); \ + } while (0) + +int f2fs_build_stats(struct f2fs_sb_info *); +void f2fs_destroy_stats(struct f2fs_sb_info *); +void destroy_root_stats(void); +#else +#define stat_inc_call_count(si) +#define stat_inc_seg_count(si, type) +#define stat_inc_tot_blk_count(si, blks) +#define stat_inc_data_blk_count(si, blks) +#define stat_inc_node_blk_count(sbi, blks) + +static inline int f2fs_build_stats(struct f2fs_sb_info *sbi) { return 0; } +static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { } +static inline void destroy_root_stats(void) { } +#endif + +extern const struct file_operations f2fs_dir_operations; +extern const struct file_operations f2fs_file_operations; +extern const struct inode_operations f2fs_file_inode_operations; +extern const struct address_space_operations f2fs_dblock_aops; +extern const struct address_space_operations f2fs_node_aops; +extern const struct address_space_operations f2fs_meta_aops; +extern const struct inode_operations f2fs_dir_inode_operations; +extern const struct inode_operations f2fs_symlink_inode_operations; +extern const struct inode_operations f2fs_special_inode_operations; +#endif diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h new file mode 100644 index 0000000..5d525ed --- /dev/null +++ b/fs/f2fs/node.h @@ -0,0 +1,353 @@ +/** + * fs/f2fs/node.h + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +/* start node id of a node block dedicated to the given node id */ +#define START_NID(nid) ((nid / NAT_ENTRY_PER_BLOCK) * NAT_ENTRY_PER_BLOCK) + +/* node block offset on the NAT area dedicated to the given start node id */ +#define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK) + +/* # of pages to perform readahead before building free nids */ +#define FREE_NID_PAGES 4 + +/* maximum # of free node ids to produce during build_free_nids */ +#define MAX_FREE_NIDS (NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES) + +/* maximum readahead size for node during getting data blocks */ +#define MAX_RA_NODE 128 + +/* maximum cached nat entries to manage memory footprint */ +#define NM_WOUT_THRESHOLD (64 * NAT_ENTRY_PER_BLOCK) + +/* vector size for gang look-up from nat cache that consists of radix tree */ +#define NATVEC_SIZE 64 + +/* + * For node information + */ +struct node_info { + nid_t nid; /* node id */ + nid_t ino; /* inode number of the node's owner */ + block_t blk_addr; /* block address of the node */ + unsigned char version; /* version of the node */ +}; + +struct nat_entry { + struct list_head list; /* for clean or dirty nat list */ + bool checkpointed; /* whether it is checkpointed or not */ + struct node_info ni; /* in-memory node information */ +}; + +#define nat_get_nid(nat) (nat->ni.nid) +#define nat_set_nid(nat, n) (nat->ni.nid = n) +#define nat_get_blkaddr(nat) (nat->ni.blk_addr) +#define nat_set_blkaddr(nat, b) (nat->ni.blk_addr = b) +#define nat_get_ino(nat) (nat->ni.ino) +#define nat_set_ino(nat, i) (nat->ni.ino = i) +#define nat_get_version(nat) (nat->ni.version) +#define nat_set_version(nat, v) (nat->ni.version = v) + +#define __set_nat_cache_dirty(nm_i, ne) \ + list_move_tail(&ne->list, &nm_i->dirty_nat_entries); +#define __clear_nat_cache_dirty(nm_i, ne) \ + list_move_tail(&ne->list, &nm_i->nat_entries); +#define inc_node_version(version) (++version) + +static inline void node_info_from_raw_nat(struct node_info *ni, + struct f2fs_nat_entry *raw_ne) +{ + ni->ino = le32_to_cpu(raw_ne->ino); + ni->blk_addr = le32_to_cpu(raw_ne->block_addr); + ni->version = raw_ne->version; +} + +/* + * For free nid mangement + */ +enum nid_state { + NID_NEW, /* newly added to free nid list */ + NID_ALLOC /* it is allocated */ +}; + +struct free_nid { + struct list_head list; /* for free node id list */ + nid_t nid; /* node id */ + int state; /* in use or not: NID_NEW or NID_ALLOC */ +}; + +static inline int next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct free_nid *fnid; + + if (nm_i->fcnt <= 0) + return -1; + spin_lock(&nm_i->free_nid_list_lock); + fnid = list_entry(nm_i->free_nid_list.next, struct free_nid, list); + *nid = fnid->nid; + spin_unlock(&nm_i->free_nid_list_lock); + return 0; +} + +/* + * inline functions + */ +static inline void get_nat_bitmap(struct f2fs_sb_info *sbi, void *addr) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + memcpy(addr, nm_i->nat_bitmap, nm_i->bitmap_size); +} + +static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + pgoff_t block_off; + pgoff_t block_addr; + int seg_off; + + block_off = NAT_BLOCK_OFFSET(start); + seg_off = block_off >> sbi->log_blocks_per_seg; + + block_addr = (pgoff_t)(nm_i->nat_blkaddr + + (seg_off << sbi->log_blocks_per_seg << 1) + + (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); + + if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) + block_addr += sbi->blocks_per_seg; + + return block_addr; +} + +static inline pgoff_t next_nat_addr(struct f2fs_sb_info *sbi, + pgoff_t block_addr) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + + block_addr -= nm_i->nat_blkaddr; + if ((block_addr >> sbi->log_blocks_per_seg) % 2) + block_addr -= sbi->blocks_per_seg; + else + block_addr += sbi->blocks_per_seg; + + return block_addr + nm_i->nat_blkaddr; +} + +static inline void set_to_next_nat(struct f2fs_nm_info *nm_i, nid_t start_nid) +{ + unsigned int block_off = NAT_BLOCK_OFFSET(start_nid); + + if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) + f2fs_clear_bit(block_off, nm_i->nat_bitmap); + else + f2fs_set_bit(block_off, nm_i->nat_bitmap); +} + +static inline void fill_node_footer(struct page *page, nid_t nid, + nid_t ino, unsigned int ofs, bool reset) +{ + void *kaddr = page_address(page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + if (reset) + memset(rn, 0, sizeof(*rn)); + rn->footer.nid = cpu_to_le32(nid); + rn->footer.ino = cpu_to_le32(ino); + rn->footer.flag = cpu_to_le32(ofs << OFFSET_BIT_SHIFT); +} + +static inline void copy_node_footer(struct page *dst, struct page *src) +{ + void *src_addr = page_address(src); + void *dst_addr = page_address(dst); + struct f2fs_node *src_rn = (struct f2fs_node *)src_addr; + struct f2fs_node *dst_rn = (struct f2fs_node *)dst_addr; + memcpy(&dst_rn->footer, &src_rn->footer, sizeof(struct node_footer)); +} + +static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr) +{ + struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + void *kaddr = page_address(page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + rn->footer.cp_ver = ckpt->checkpoint_ver; + rn->footer.next_blkaddr = blkaddr; +} + +static inline nid_t ino_of_node(struct page *node_page) +{ + void *kaddr = page_address(node_page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + return le32_to_cpu(rn->footer.ino); +} + +static inline nid_t nid_of_node(struct page *node_page) +{ + void *kaddr = page_address(node_page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + return le32_to_cpu(rn->footer.nid); +} + +static inline unsigned int ofs_of_node(struct page *node_page) +{ + void *kaddr = page_address(node_page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + unsigned flag = le32_to_cpu(rn->footer.flag); + return flag >> OFFSET_BIT_SHIFT; +} + +static inline unsigned long long cpver_of_node(struct page *node_page) +{ + void *kaddr = page_address(node_page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + return le64_to_cpu(rn->footer.cp_ver); +} + +static inline block_t next_blkaddr_of_node(struct page *node_page) +{ + void *kaddr = page_address(node_page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + return le32_to_cpu(rn->footer.next_blkaddr); +} + +/* + * f2fs assigns the following node offsets described as (num). + * N = NIDS_PER_BLOCK + * + * Inode block (0) + * |- direct node (1) + * |- direct node (2) + * |- indirect node (3) + * | `- direct node (4 => 4 + N - 1) + * |- indirect node (4 + N) + * | `- direct node (5 + N => 5 + 2N - 1) + * `- double indirect node (5 + 2N) + * `- indirect node (6 + 2N) + * `- direct node (x(N + 1)) + */ +static inline bool IS_DNODE(struct page *node_page) +{ + unsigned int ofs = ofs_of_node(node_page); + if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK || + ofs == 5 + 2 * NIDS_PER_BLOCK) + return false; + if (ofs >= 6 + 2 * NIDS_PER_BLOCK) { + ofs -= 6 + 2 * NIDS_PER_BLOCK; + if ((long int)ofs % (NIDS_PER_BLOCK + 1)) + return false; + } + return true; +} + +static inline void set_nid(struct page *p, int off, nid_t nid, bool i) +{ + struct f2fs_node *rn = (struct f2fs_node *)page_address(p); + + wait_on_page_writeback(p); + + if (i) + rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid); + else + rn->in.nid[off] = cpu_to_le32(nid); + set_page_dirty(p); +} + +static inline nid_t get_nid(struct page *p, int off, bool i) +{ + struct f2fs_node *rn = (struct f2fs_node *)page_address(p); + if (i) + return le32_to_cpu(rn->i.i_nid[off - NODE_DIR1_BLOCK]); + return le32_to_cpu(rn->in.nid[off]); +} + +/* + * Coldness identification: + * - Mark cold files in f2fs_inode_info + * - Mark cold node blocks in their node footer + * - Mark cold data pages in page cache + */ +static inline int is_cold_file(struct inode *inode) +{ + return F2FS_I(inode)->i_advise & FADVISE_COLD_BIT; +} + +static inline int is_cold_data(struct page *page) +{ + return PageChecked(page); +} + +static inline void set_cold_data(struct page *page) +{ + SetPageChecked(page); +} + +static inline void clear_cold_data(struct page *page) +{ + ClearPageChecked(page); +} + +static inline int is_cold_node(struct page *page) +{ + void *kaddr = page_address(page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + unsigned int flag = le32_to_cpu(rn->footer.flag); + return flag & (0x1 << COLD_BIT_SHIFT); +} + +static inline unsigned char is_fsync_dnode(struct page *page) +{ + void *kaddr = page_address(page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + unsigned int flag = le32_to_cpu(rn->footer.flag); + return flag & (0x1 << FSYNC_BIT_SHIFT); +} + +static inline unsigned char is_dent_dnode(struct page *page) +{ + void *kaddr = page_address(page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + unsigned int flag = le32_to_cpu(rn->footer.flag); + return flag & (0x1 << DENT_BIT_SHIFT); +} + +static inline void set_cold_node(struct inode *inode, struct page *page) +{ + struct f2fs_node *rn = (struct f2fs_node *)page_address(page); + unsigned int flag = le32_to_cpu(rn->footer.flag); + + if (S_ISDIR(inode->i_mode)) + flag &= ~(0x1 << COLD_BIT_SHIFT); + else + flag |= (0x1 << COLD_BIT_SHIFT); + rn->footer.flag = cpu_to_le32(flag); +} + +static inline void set_fsync_mark(struct page *page, int mark) +{ + void *kaddr = page_address(page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + unsigned int flag = le32_to_cpu(rn->footer.flag); + if (mark) + flag |= (0x1 << FSYNC_BIT_SHIFT); + else + flag &= ~(0x1 << FSYNC_BIT_SHIFT); + rn->footer.flag = cpu_to_le32(flag); +} + +static inline void set_dentry_mark(struct page *page, int mark) +{ + void *kaddr = page_address(page); + struct f2fs_node *rn = (struct f2fs_node *)kaddr; + unsigned int flag = le32_to_cpu(rn->footer.flag); + if (mark) + flag |= (0x1 << DENT_BIT_SHIFT); + else + flag &= ~(0x1 << DENT_BIT_SHIFT); + rn->footer.flag = cpu_to_le32(flag); +} diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h new file mode 100644 index 0000000..e380a8e --- /dev/null +++ b/fs/f2fs/segment.h @@ -0,0 +1,615 @@ +/** + * fs/f2fs/segment.h + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +/* constant macro */ +#define NULL_SEGNO ((unsigned int)(~0)) + +/* V: Logical segment # in volume, R: Relative segment # in main area */ +#define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno) +#define GET_R2L_SEGNO(free_i, segno) (segno + free_i->start_segno) + +#define IS_DATASEG(t) \ + ((t == CURSEG_HOT_DATA) || (t == CURSEG_COLD_DATA) || \ + (t == CURSEG_WARM_DATA)) + +#define IS_NODESEG(t) \ + ((t == CURSEG_HOT_NODE) || (t == CURSEG_COLD_NODE) || \ + (t == CURSEG_WARM_NODE)) + +#define IS_CURSEG(sbi, segno) \ + ((segno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \ + (segno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) || \ + (segno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) || \ + (segno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) || \ + (segno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) || \ + (segno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno)) + +#define IS_CURSEC(sbi, secno) \ + ((secno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \ + sbi->segs_per_sec) || \ + (secno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno / \ + sbi->segs_per_sec) || \ + (secno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno / \ + sbi->segs_per_sec) || \ + (secno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno / \ + sbi->segs_per_sec) || \ + (secno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \ + sbi->segs_per_sec) || \ + (secno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \ + sbi->segs_per_sec)) \ + +#define START_BLOCK(sbi, segno) \ + (SM_I(sbi)->seg0_blkaddr + \ + (GET_R2L_SEGNO(FREE_I(sbi), segno) << sbi->log_blocks_per_seg)) +#define NEXT_FREE_BLKADDR(sbi, curseg) \ + (START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff) + +#define MAIN_BASE_BLOCK(sbi) (SM_I(sbi)->main_blkaddr) + +#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr) \ + ((blk_addr) - SM_I(sbi)->seg0_blkaddr) +#define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \ + (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg) +#define GET_SEGNO(sbi, blk_addr) \ + (((blk_addr == NULL_ADDR) || (blk_addr == NEW_ADDR)) ? \ + NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \ + GET_SEGNO_FROM_SEG0(sbi, blk_addr))) +#define GET_SECNO(sbi, segno) \ + ((segno) / sbi->segs_per_sec) +#define GET_ZONENO_FROM_SEGNO(sbi, segno) \ + ((segno / sbi->segs_per_sec) / sbi->secs_per_zone) + +#define GET_SUM_BLOCK(sbi, segno) \ + ((sbi->sm_info->ssa_blkaddr) + segno) + +#define GET_SUM_TYPE(footer) ((footer)->entry_type) +#define SET_SUM_TYPE(footer, type) ((footer)->entry_type = type) + +#define SIT_ENTRY_OFFSET(sit_i, segno) \ + (segno % sit_i->sents_per_block) +#define SIT_BLOCK_OFFSET(sit_i, segno) \ + (segno / SIT_ENTRY_PER_BLOCK) +#define START_SEGNO(sit_i, segno) \ + (SIT_BLOCK_OFFSET(sit_i, segno) * SIT_ENTRY_PER_BLOCK) +#define f2fs_bitmap_size(nr) \ + (BITS_TO_LONGS(nr) * sizeof(unsigned long)) +#define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments) + +/* during checkpoint, bio_private is used to synchronize the last bio */ +struct bio_private { + struct f2fs_sb_info *sbi; + bool is_sync; + void *wait; +}; + +/* + * indicate a block allocation direction: RIGHT and LEFT. + * RIGHT means allocating new sections towards the end of volume. + * LEFT means the opposite direction. + */ +enum { + ALLOC_RIGHT = 0, + ALLOC_LEFT +}; + +/* + * In the victim_sel_policy->alloc_mode, there are two block allocation modes. + * LFS writes data sequentially with cleaning operations. + * SSR (Slack Space Recycle) reuses obsolete space without cleaning operations. + */ +enum { + LFS = 0, + SSR +}; + +/* + * In the victim_sel_policy->gc_mode, there are two gc, aka cleaning, modes. + * GC_CB is based on cost-benefit algorithm. + * GC_GREEDY is based on greedy algorithm. + */ +enum { + GC_CB = 0, + GC_GREEDY +}; + +/* + * BG_GC means the background cleaning job. + * FG_GC means the on-demand cleaning job. + */ +enum { + BG_GC = 0, + FG_GC +}; + +/* for a function parameter to select a victim segment */ +struct victim_sel_policy { + int alloc_mode; /* LFS or SSR */ + int gc_mode; /* GC_CB or GC_GREEDY */ + unsigned long *dirty_segmap; /* dirty segment bitmap */ + unsigned int offset; /* last scanned bitmap offset */ + unsigned int ofs_unit; /* bitmap search unit */ + unsigned int min_cost; /* minimum cost */ + unsigned int min_segno; /* segment # having min. cost */ +}; + +struct seg_entry { + unsigned short valid_blocks; /* # of valid blocks */ + unsigned char *cur_valid_map; /* validity bitmap of blocks */ + /* + * # of valid blocks and the validity bitmap stored in the the last + * checkpoint pack. This information is used by the SSR mode. + */ + unsigned short ckpt_valid_blocks; + unsigned char *ckpt_valid_map; + unsigned char type; /* segment type like CURSEG_XXX_TYPE */ + unsigned long long mtime; /* modification time of the segment */ +}; + +struct sec_entry { + unsigned int valid_blocks; /* # of valid blocks in a section */ +}; + +struct segment_allocation { + void (*allocate_segment)(struct f2fs_sb_info *, int, bool); +}; + +struct sit_info { + const struct segment_allocation *s_ops; + + block_t sit_base_addr; /* start block address of SIT area */ + block_t sit_blocks; /* # of blocks used by SIT area */ + block_t written_valid_blocks; /* # of valid blocks in main area */ + char *sit_bitmap; /* SIT bitmap pointer */ + unsigned int bitmap_size; /* SIT bitmap size */ + + unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */ + unsigned int dirty_sentries; /* # of dirty sentries */ + unsigned int sents_per_block; /* # of SIT entries per block */ + struct mutex sentry_lock; /* to protect SIT cache */ + struct seg_entry *sentries; /* SIT segment-level cache */ + struct sec_entry *sec_entries; /* SIT section-level cache */ + + /* for cost-benefit algorithm in cleaning procedure */ + unsigned long long elapsed_time; /* elapsed time after mount */ + unsigned long long mounted_time; /* mount time */ + unsigned long long min_mtime; /* min. modification time */ + unsigned long long max_mtime; /* max. modification time */ +}; + +struct free_segmap_info { + unsigned int start_segno; /* start segment number logically */ + unsigned int free_segments; /* # of free segments */ + unsigned int free_sections; /* # of free sections */ + rwlock_t segmap_lock; /* free segmap lock */ + unsigned long *free_segmap; /* free segment bitmap */ + unsigned long *free_secmap; /* free section bitmap */ +}; + +/* Notice: The order of dirty type is same with CURSEG_XXX in f2fs.h */ +enum dirty_type { + DIRTY_HOT_DATA, /* dirty segments assigned as hot data logs */ + DIRTY_WARM_DATA, /* dirty segments assigned as warm data logs */ + DIRTY_COLD_DATA, /* dirty segments assigned as cold data logs */ + DIRTY_HOT_NODE, /* dirty segments assigned as hot node logs */ + DIRTY_WARM_NODE, /* dirty segments assigned as warm node logs */ + DIRTY_COLD_NODE, /* dirty segments assigned as cold node logs */ + DIRTY, /* to count # of dirty segments */ + PRE, /* to count # of entirely obsolete segments */ + NR_DIRTY_TYPE +}; + +struct dirty_seglist_info { + const struct victim_selection *v_ops; /* victim selction operation */ + unsigned long *dirty_segmap[NR_DIRTY_TYPE]; + struct mutex seglist_lock; /* lock for segment bitmaps */ + int nr_dirty[NR_DIRTY_TYPE]; /* # of dirty segments */ + unsigned long *victim_segmap[2]; /* BG_GC, FG_GC */ +}; + +/* victim selection function for cleaning and SSR */ +struct victim_selection { + int (*get_victim)(struct f2fs_sb_info *, unsigned int *, + int, int, char); +}; + +/* for active log information */ +struct curseg_info { + struct mutex curseg_mutex; /* lock for consistency */ + struct f2fs_summary_block *sum_blk; /* cached summary block */ + unsigned char alloc_type; /* current allocation type */ + unsigned int segno; /* current segment number */ + unsigned short next_blkoff; /* next block offset to write */ + unsigned int zone; /* current zone number */ + unsigned int next_segno; /* preallocated segment */ +}; + +/* + * inline functions + */ +static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type) +{ + return (struct curseg_info *)(SM_I(sbi)->curseg_array + type); +} + +static inline struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, + unsigned int segno) +{ + struct sit_info *sit_i = SIT_I(sbi); + return &sit_i->sentries[segno]; +} + +static inline struct sec_entry *get_sec_entry(struct f2fs_sb_info *sbi, + unsigned int segno) +{ + struct sit_info *sit_i = SIT_I(sbi); + return &sit_i->sec_entries[GET_SECNO(sbi, segno)]; +} + +static inline unsigned int get_valid_blocks(struct f2fs_sb_info *sbi, + unsigned int segno, int section) +{ + /* + * In order to get # of valid blocks in a section instantly from many + * segments, f2fs manages two counting structures separately. + */ + if (section > 1) + return get_sec_entry(sbi, segno)->valid_blocks; + else + return get_seg_entry(sbi, segno)->valid_blocks; +} + +static inline void seg_info_from_raw_sit(struct seg_entry *se, + struct f2fs_sit_entry *rs) +{ + se->valid_blocks = GET_SIT_VBLOCKS(rs); + se->ckpt_valid_blocks = GET_SIT_VBLOCKS(rs); + memcpy(se->cur_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE); + memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE); + se->type = GET_SIT_TYPE(rs); + se->mtime = le64_to_cpu(rs->mtime); +} + +static inline void seg_info_to_raw_sit(struct seg_entry *se, + struct f2fs_sit_entry *rs) +{ + unsigned short raw_vblocks = (se->type << SIT_VBLOCKS_SHIFT) | + se->valid_blocks; + rs->vblocks = cpu_to_le16(raw_vblocks); + memcpy(rs->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); + memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE); + se->ckpt_valid_blocks = se->valid_blocks; + rs->mtime = cpu_to_le64(se->mtime); +} + +static inline unsigned int find_next_inuse(struct free_segmap_info *free_i, + unsigned int max, unsigned int segno) +{ + unsigned int ret; + read_lock(&free_i->segmap_lock); + ret = find_next_bit(free_i->free_segmap, max, segno); + read_unlock(&free_i->segmap_lock); + return ret; +} + +static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno) +{ + struct free_segmap_info *free_i = FREE_I(sbi); + unsigned int secno = segno / sbi->segs_per_sec; + unsigned int start_segno = secno * sbi->segs_per_sec; + unsigned int next; + + write_lock(&free_i->segmap_lock); + clear_bit(segno, free_i->free_segmap); + free_i->free_segments++; + + next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi), start_segno); + if (next >= start_segno + sbi->segs_per_sec) { + clear_bit(secno, free_i->free_secmap); + free_i->free_sections++; + } + write_unlock(&free_i->segmap_lock); +} + +static inline void __set_inuse(struct f2fs_sb_info *sbi, + unsigned int segno) +{ + struct free_segmap_info *free_i = FREE_I(sbi); + unsigned int secno = segno / sbi->segs_per_sec; + set_bit(segno, free_i->free_segmap); + free_i->free_segments--; + if (!test_and_set_bit(secno, free_i->free_secmap)) + free_i->free_sections--; +} + +static inline void __set_test_and_free(struct f2fs_sb_info *sbi, + unsigned int segno) +{ + struct free_segmap_info *free_i = FREE_I(sbi); + unsigned int secno = segno / sbi->segs_per_sec; + unsigned int start_segno = secno * sbi->segs_per_sec; + unsigned int next; + + write_lock(&free_i->segmap_lock); + if (test_and_clear_bit(segno, free_i->free_segmap)) { + free_i->free_segments++; + + next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi), + start_segno); + if (next >= start_segno + sbi->segs_per_sec) { + if (test_and_clear_bit(secno, free_i->free_secmap)) + free_i->free_sections++; + } + } + write_unlock(&free_i->segmap_lock); +} + +static inline void __set_test_and_inuse(struct f2fs_sb_info *sbi, + unsigned int segno) +{ + struct free_segmap_info *free_i = FREE_I(sbi); + unsigned int secno = segno / sbi->segs_per_sec; + write_lock(&free_i->segmap_lock); + if (!test_and_set_bit(segno, free_i->free_segmap)) { + free_i->free_segments--; + if (!test_and_set_bit(secno, free_i->free_secmap)) + free_i->free_sections--; + } + write_unlock(&free_i->segmap_lock); +} + +static inline void get_sit_bitmap(struct f2fs_sb_info *sbi, + void *dst_addr) +{ + struct sit_info *sit_i = SIT_I(sbi); + memcpy(dst_addr, sit_i->sit_bitmap, sit_i->bitmap_size); +} + +static inline block_t written_block_count(struct f2fs_sb_info *sbi) +{ + struct sit_info *sit_i = SIT_I(sbi); + block_t vblocks; + + mutex_lock(&sit_i->sentry_lock); + vblocks = sit_i->written_valid_blocks; + mutex_unlock(&sit_i->sentry_lock); + + return vblocks; +} + +static inline unsigned int free_segments(struct f2fs_sb_info *sbi) +{ + struct free_segmap_info *free_i = FREE_I(sbi); + unsigned int free_segs; + + read_lock(&free_i->segmap_lock); + free_segs = free_i->free_segments; + read_unlock(&free_i->segmap_lock); + + return free_segs; +} + +static inline int reserved_segments(struct f2fs_sb_info *sbi) +{ + return SM_I(sbi)->reserved_segments; +} + +static inline unsigned int free_sections(struct f2fs_sb_info *sbi) +{ + struct free_segmap_info *free_i = FREE_I(sbi); + unsigned int free_secs; + + read_lock(&free_i->segmap_lock); + free_secs = free_i->free_sections; + read_unlock(&free_i->segmap_lock); + + return free_secs; +} + +static inline unsigned int prefree_segments(struct f2fs_sb_info *sbi) +{ + return DIRTY_I(sbi)->nr_dirty[PRE]; +} + +static inline unsigned int dirty_segments(struct f2fs_sb_info *sbi) +{ + return DIRTY_I(sbi)->nr_dirty[DIRTY_HOT_DATA] + + DIRTY_I(sbi)->nr_dirty[DIRTY_WARM_DATA] + + DIRTY_I(sbi)->nr_dirty[DIRTY_COLD_DATA] + + DIRTY_I(sbi)->nr_dirty[DIRTY_HOT_NODE] + + DIRTY_I(sbi)->nr_dirty[DIRTY_WARM_NODE] + + DIRTY_I(sbi)->nr_dirty[DIRTY_COLD_NODE]; +} + +static inline int overprovision_segments(struct f2fs_sb_info *sbi) +{ + return SM_I(sbi)->ovp_segments; +} + +static inline int overprovision_sections(struct f2fs_sb_info *sbi) +{ + return ((unsigned int) overprovision_segments(sbi)) / sbi->segs_per_sec; +} + +static inline int reserved_sections(struct f2fs_sb_info *sbi) +{ + return ((unsigned int) reserved_segments(sbi)) / sbi->segs_per_sec; +} + +static inline bool need_SSR(struct f2fs_sb_info *sbi) +{ + return (free_sections(sbi) < overprovision_sections(sbi)); +} + +static inline int get_ssr_segment(struct f2fs_sb_info *sbi, int type) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + return DIRTY_I(sbi)->v_ops->get_victim(sbi, + &(curseg)->next_segno, BG_GC, type, SSR); +} + +static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi) +{ + return free_sections(sbi) <= reserved_sections(sbi); +} + +static inline int utilization(struct f2fs_sb_info *sbi) +{ + return (long int)valid_user_blocks(sbi) * 100 / + (long int)sbi->user_block_count; +} + +/* + * Sometimes f2fs may be better to drop out-of-place update policy. + * So, if fs utilization is over MIN_IPU_UTIL, then f2fs tries to write + * data in the original place likewise other traditional file systems. + * But, currently set 100 in percentage, which means it is disabled. + * See below need_inplace_update(). + */ +#define MIN_IPU_UTIL 100 +static inline bool need_inplace_update(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + if (S_ISDIR(inode->i_mode)) + return false; + if (need_SSR(sbi) && utilization(sbi) > MIN_IPU_UTIL) + return true; + return false; +} + +static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi, + int type) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + return curseg->segno; +} + +static inline unsigned char curseg_alloc_type(struct f2fs_sb_info *sbi, + int type) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + return curseg->alloc_type; +} + +static inline unsigned short curseg_blkoff(struct f2fs_sb_info *sbi, int type) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + return curseg->next_blkoff; +} + +static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) +{ + unsigned int end_segno = SM_I(sbi)->segment_count - 1; + BUG_ON(segno > end_segno); +} + +/* + * This function is used for only debugging. + * NOTE: In future, we have to remove this function. + */ +static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) +{ + struct f2fs_sm_info *sm_info = SM_I(sbi); + block_t total_blks = sm_info->segment_count << sbi->log_blocks_per_seg; + block_t start_addr = sm_info->seg0_blkaddr; + block_t end_addr = start_addr + total_blks - 1; + BUG_ON(blk_addr < start_addr); + BUG_ON(blk_addr > end_addr); +} + +/* + * Summary block is always treated as invalid block + */ +static inline void check_block_count(struct f2fs_sb_info *sbi, + int segno, struct f2fs_sit_entry *raw_sit) +{ + struct f2fs_sm_info *sm_info = SM_I(sbi); + unsigned int end_segno = sm_info->segment_count - 1; + int valid_blocks = 0; + int i; + + /* check segment usage */ + BUG_ON(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg); + + /* check boundary of a given segment number */ + BUG_ON(segno > end_segno); + + /* check bitmap with valid block count */ + for (i = 0; i < sbi->blocks_per_seg; i++) + if (f2fs_test_bit(i, raw_sit->valid_map)) + valid_blocks++; + BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks); +} + +static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi, + unsigned int start) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned int offset = SIT_BLOCK_OFFSET(sit_i, start); + block_t blk_addr = sit_i->sit_base_addr + offset; + + check_seg_range(sbi, start); + + /* calculate sit block address */ + if (f2fs_test_bit(offset, sit_i->sit_bitmap)) + blk_addr += sit_i->sit_blocks; + + return blk_addr; +} + +static inline pgoff_t next_sit_addr(struct f2fs_sb_info *sbi, + pgoff_t block_addr) +{ + struct sit_info *sit_i = SIT_I(sbi); + block_addr -= sit_i->sit_base_addr; + if (block_addr < sit_i->sit_blocks) + block_addr += sit_i->sit_blocks; + else + block_addr -= sit_i->sit_blocks; + + return block_addr + sit_i->sit_base_addr; +} + +static inline void set_to_next_sit(struct sit_info *sit_i, unsigned int start) +{ + unsigned int block_off = SIT_BLOCK_OFFSET(sit_i, start); + + if (f2fs_test_bit(block_off, sit_i->sit_bitmap)) + f2fs_clear_bit(block_off, sit_i->sit_bitmap); + else + f2fs_set_bit(block_off, sit_i->sit_bitmap); +} + +static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi) +{ + struct sit_info *sit_i = SIT_I(sbi); + return sit_i->elapsed_time + CURRENT_TIME_SEC.tv_sec - + sit_i->mounted_time; +} + +static inline void set_summary(struct f2fs_summary *sum, nid_t nid, + unsigned int ofs_in_node, unsigned char version) +{ + sum->nid = cpu_to_le32(nid); + sum->ofs_in_node = cpu_to_le16(ofs_in_node); + sum->version = version; +} + +static inline block_t start_sum_block(struct f2fs_sb_info *sbi) +{ + return __start_cp_addr(sbi) + + le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); +} + +static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type) +{ + return __start_cp_addr(sbi) + + le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_total_block_count) + - (base + 1) + type; +} diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index e15192c..66353ff 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -23,6 +23,7 @@ #define EXT4_SUPER_MAGIC 0xEF53 #define BTRFS_SUPER_MAGIC 0x9123683E #define NILFS_SUPER_MAGIC 0x3434 +#define F2FS_SUPER_MAGIC 0xF2F52010 #define HPFS_SUPER_MAGIC 0xf995e849 #define ISOFS_SUPER_MAGIC 0x9660 #define JFFS2_SUPER_MAGIC 0x72b6 -- cgit v0.10.2 From aff063e266cbf4754021d8e5d16ee418560906fd Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:07:47 +0900 Subject: f2fs: add super block operations This adds the implementation of superblock operations for f2fs, which includes - init_f2fs_fs/exit_f2fs_fs - f2fs_mount - super_operations of f2fs Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c new file mode 100644 index 0000000..8661c93 --- /dev/null +++ b/fs/f2fs/super.c @@ -0,0 +1,656 @@ +/** + * fs/f2fs/super.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "node.h" +#include "xattr.h" + +static struct kmem_cache *f2fs_inode_cachep; + +enum { + Opt_gc_background_off, + Opt_disable_roll_forward, + Opt_discard, + Opt_noheap, + Opt_nouser_xattr, + Opt_noacl, + Opt_active_logs, + Opt_disable_ext_identify, + Opt_err, +}; + +static match_table_t f2fs_tokens = { + {Opt_gc_background_off, "background_gc_off"}, + {Opt_disable_roll_forward, "disable_roll_forward"}, + {Opt_discard, "discard"}, + {Opt_noheap, "no_heap"}, + {Opt_nouser_xattr, "nouser_xattr"}, + {Opt_noacl, "noacl"}, + {Opt_active_logs, "active_logs=%u"}, + {Opt_disable_ext_identify, "disable_ext_identify"}, + {Opt_err, NULL}, +}; + +static void init_once(void *foo) +{ + struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo; + + memset(fi, 0, sizeof(*fi)); + inode_init_once(&fi->vfs_inode); +} + +static struct inode *f2fs_alloc_inode(struct super_block *sb) +{ + struct f2fs_inode_info *fi; + + fi = kmem_cache_alloc(f2fs_inode_cachep, GFP_NOFS | __GFP_ZERO); + if (!fi) + return NULL; + + init_once((void *) fi); + + /* Initilize f2fs-specific inode info */ + fi->vfs_inode.i_version = 1; + atomic_set(&fi->dirty_dents, 0); + fi->i_current_depth = 1; + fi->i_advise = 0; + rwlock_init(&fi->ext.ext_lock); + + set_inode_flag(fi, FI_NEW_INODE); + + return &fi->vfs_inode; +} + +static void f2fs_i_callback(struct rcu_head *head) +{ + struct inode *inode = container_of(head, struct inode, i_rcu); + kmem_cache_free(f2fs_inode_cachep, F2FS_I(inode)); +} + +void f2fs_destroy_inode(struct inode *inode) +{ + call_rcu(&inode->i_rcu, f2fs_i_callback); +} + +static void f2fs_put_super(struct super_block *sb) +{ + struct f2fs_sb_info *sbi = F2FS_SB(sb); + + f2fs_destroy_stats(sbi); + stop_gc_thread(sbi); + + write_checkpoint(sbi, false, true); + + iput(sbi->node_inode); + iput(sbi->meta_inode); + + /* destroy f2fs internal modules */ + destroy_node_manager(sbi); + destroy_segment_manager(sbi); + + kfree(sbi->ckpt); + + sb->s_fs_info = NULL; + brelse(sbi->raw_super_buf); + kfree(sbi); +} + +int f2fs_sync_fs(struct super_block *sb, int sync) +{ + struct f2fs_sb_info *sbi = F2FS_SB(sb); + int ret = 0; + + if (!sbi->s_dirty && !get_pages(sbi, F2FS_DIRTY_NODES)) + return 0; + + if (sync) + write_checkpoint(sbi, false, false); + + return ret; +} + +static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct super_block *sb = dentry->d_sb; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + u64 id = huge_encode_dev(sb->s_bdev->bd_dev); + block_t total_count, user_block_count, start_count, ovp_count; + + total_count = le64_to_cpu(sbi->raw_super->block_count); + user_block_count = sbi->user_block_count; + start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr); + ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg; + buf->f_type = F2FS_SUPER_MAGIC; + buf->f_bsize = sbi->blocksize; + + buf->f_blocks = total_count - start_count; + buf->f_bfree = buf->f_blocks - valid_user_blocks(sbi) - ovp_count; + buf->f_bavail = user_block_count - valid_user_blocks(sbi); + + buf->f_files = valid_inode_count(sbi); + buf->f_ffree = sbi->total_node_count - valid_node_count(sbi); + + buf->f_namelen = F2FS_MAX_NAME_LEN; + buf->f_fsid.val[0] = (u32)id; + buf->f_fsid.val[1] = (u32)(id >> 32); + + return 0; +} + +static int f2fs_show_options(struct seq_file *seq, struct dentry *root) +{ + struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb); + + if (test_opt(sbi, BG_GC)) + seq_puts(seq, ",background_gc_on"); + else + seq_puts(seq, ",background_gc_off"); + if (test_opt(sbi, DISABLE_ROLL_FORWARD)) + seq_puts(seq, ",disable_roll_forward"); + if (test_opt(sbi, DISCARD)) + seq_puts(seq, ",discard"); + if (test_opt(sbi, NOHEAP)) + seq_puts(seq, ",no_heap_alloc"); +#ifdef CONFIG_F2FS_FS_XATTR + if (test_opt(sbi, XATTR_USER)) + seq_puts(seq, ",user_xattr"); + else + seq_puts(seq, ",nouser_xattr"); +#endif +#ifdef CONFIG_F2FS_FS_POSIX_ACL + if (test_opt(sbi, POSIX_ACL)) + seq_puts(seq, ",acl"); + else + seq_puts(seq, ",noacl"); +#endif + if (test_opt(sbi, DISABLE_EXT_IDENTIFY)) + seq_puts(seq, ",disable_ext_indentify"); + + seq_printf(seq, ",active_logs=%u", sbi->active_logs); + + return 0; +} + +static struct super_operations f2fs_sops = { + .alloc_inode = f2fs_alloc_inode, + .destroy_inode = f2fs_destroy_inode, + .write_inode = f2fs_write_inode, + .show_options = f2fs_show_options, + .evict_inode = f2fs_evict_inode, + .put_super = f2fs_put_super, + .sync_fs = f2fs_sync_fs, + .statfs = f2fs_statfs, +}; + +static struct inode *f2fs_nfs_get_inode(struct super_block *sb, + u64 ino, u32 generation) +{ + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct inode *inode; + + if (ino < F2FS_ROOT_INO(sbi)) + return ERR_PTR(-ESTALE); + + /* + * f2fs_iget isn't quite right if the inode is currently unallocated! + * However f2fs_iget currently does appropriate checks to handle stale + * inodes so everything is OK. + */ + inode = f2fs_iget(sb, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + if (generation && inode->i_generation != generation) { + /* we didn't find the right inode.. */ + iput(inode); + return ERR_PTR(-ESTALE); + } + return inode; +} + +static struct dentry *f2fs_fh_to_dentry(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, + f2fs_nfs_get_inode); +} + +static struct dentry *f2fs_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_parent(sb, fid, fh_len, fh_type, + f2fs_nfs_get_inode); +} + +static const struct export_operations f2fs_export_ops = { + .fh_to_dentry = f2fs_fh_to_dentry, + .fh_to_parent = f2fs_fh_to_parent, + .get_parent = f2fs_get_parent, +}; + +static int parse_options(struct f2fs_sb_info *sbi, char *options) +{ + substring_t args[MAX_OPT_ARGS]; + char *p; + int arg = 0; + + if (!options) + return 0; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + /* + * Initialize args struct so we know whether arg was + * found; some options take optional arguments. + */ + args[0].to = args[0].from = NULL; + token = match_token(p, f2fs_tokens, args); + + switch (token) { + case Opt_gc_background_off: + clear_opt(sbi, BG_GC); + break; + case Opt_disable_roll_forward: + set_opt(sbi, DISABLE_ROLL_FORWARD); + break; + case Opt_discard: + set_opt(sbi, DISCARD); + break; + case Opt_noheap: + set_opt(sbi, NOHEAP); + break; +#ifdef CONFIG_F2FS_FS_XATTR + case Opt_nouser_xattr: + clear_opt(sbi, XATTR_USER); + break; +#else + case Opt_nouser_xattr: + pr_info("nouser_xattr options not supported\n"); + break; +#endif +#ifdef CONFIG_F2FS_FS_POSIX_ACL + case Opt_noacl: + clear_opt(sbi, POSIX_ACL); + break; +#else + case Opt_noacl: + pr_info("noacl options not supported\n"); + break; +#endif + case Opt_active_logs: + if (args->from && match_int(args, &arg)) + return -EINVAL; + if (arg != 2 && arg != 4 && arg != 6) + return -EINVAL; + sbi->active_logs = arg; + break; + case Opt_disable_ext_identify: + set_opt(sbi, DISABLE_EXT_IDENTIFY); + break; + default: + return -EINVAL; + } + } + return 0; +} + +static loff_t max_file_size(unsigned bits) +{ + loff_t result = ADDRS_PER_INODE; + loff_t leaf_count = ADDRS_PER_BLOCK; + + /* two direct node blocks */ + result += (leaf_count * 2); + + /* two indirect node blocks */ + leaf_count *= NIDS_PER_BLOCK; + result += (leaf_count * 2); + + /* one double indirect node block */ + leaf_count *= NIDS_PER_BLOCK; + result += leaf_count; + + result <<= bits; + return result; +} + +static int sanity_check_raw_super(struct f2fs_super_block *raw_super) +{ + unsigned int blocksize; + + if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) + return 1; + + /* Currently, support only 4KB block size */ + blocksize = 1 << le32_to_cpu(raw_super->log_blocksize); + if (blocksize != PAGE_CACHE_SIZE) + return 1; + if (le32_to_cpu(raw_super->log_sectorsize) != + F2FS_LOG_SECTOR_SIZE) + return 1; + if (le32_to_cpu(raw_super->log_sectors_per_block) != + F2FS_LOG_SECTORS_PER_BLOCK) + return 1; + return 0; +} + +static int sanity_check_ckpt(struct f2fs_super_block *raw_super, + struct f2fs_checkpoint *ckpt) +{ + unsigned int total, fsmeta; + + total = le32_to_cpu(raw_super->segment_count); + fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); + fsmeta += le32_to_cpu(raw_super->segment_count_sit); + fsmeta += le32_to_cpu(raw_super->segment_count_nat); + fsmeta += le32_to_cpu(ckpt->rsvd_segment_count); + fsmeta += le32_to_cpu(raw_super->segment_count_ssa); + + if (fsmeta >= total) + return 1; + return 0; +} + +static void init_sb_info(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *raw_super = sbi->raw_super; + int i; + + sbi->log_sectors_per_block = + le32_to_cpu(raw_super->log_sectors_per_block); + sbi->log_blocksize = le32_to_cpu(raw_super->log_blocksize); + sbi->blocksize = 1 << sbi->log_blocksize; + sbi->log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); + sbi->blocks_per_seg = 1 << sbi->log_blocks_per_seg; + sbi->segs_per_sec = le32_to_cpu(raw_super->segs_per_sec); + sbi->secs_per_zone = le32_to_cpu(raw_super->secs_per_zone); + sbi->total_sections = le32_to_cpu(raw_super->section_count); + sbi->total_node_count = + (le32_to_cpu(raw_super->segment_count_nat) / 2) + * sbi->blocks_per_seg * NAT_ENTRY_PER_BLOCK; + sbi->root_ino_num = le32_to_cpu(raw_super->root_ino); + sbi->node_ino_num = le32_to_cpu(raw_super->node_ino); + sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino); + + for (i = 0; i < NR_COUNT_TYPE; i++) + atomic_set(&sbi->nr_pages[i], 0); +} + +static int f2fs_fill_super(struct super_block *sb, void *data, int silent) +{ + struct f2fs_sb_info *sbi; + struct f2fs_super_block *raw_super; + struct buffer_head *raw_super_buf; + struct inode *root; + long err = -EINVAL; + int i; + + /* allocate memory for f2fs-specific super block info */ + sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); + if (!sbi) + return -ENOMEM; + + /* set a temporary block size */ + if (!sb_set_blocksize(sb, F2FS_BLKSIZE)) + goto free_sbi; + + /* read f2fs raw super block */ + raw_super_buf = sb_bread(sb, 0); + if (!raw_super_buf) { + err = -EIO; + goto free_sbi; + } + raw_super = (struct f2fs_super_block *) + ((char *)raw_super_buf->b_data + F2FS_SUPER_OFFSET); + + /* init some FS parameters */ + sbi->active_logs = NR_CURSEG_TYPE; + + set_opt(sbi, BG_GC); + +#ifdef CONFIG_F2FS_FS_XATTR + set_opt(sbi, XATTR_USER); +#endif +#ifdef CONFIG_F2FS_FS_POSIX_ACL + set_opt(sbi, POSIX_ACL); +#endif + /* parse mount options */ + if (parse_options(sbi, (char *)data)) + goto free_sb_buf; + + /* sanity checking of raw super */ + if (sanity_check_raw_super(raw_super)) + goto free_sb_buf; + + sb->s_maxbytes = max_file_size(raw_super->log_blocksize); + sb->s_max_links = F2FS_LINK_MAX; + get_random_bytes(&sbi->s_next_generation, sizeof(u32)); + + sb->s_op = &f2fs_sops; + sb->s_xattr = f2fs_xattr_handlers; + sb->s_export_op = &f2fs_export_ops; + sb->s_magic = F2FS_SUPER_MAGIC; + sb->s_fs_info = sbi; + sb->s_time_gran = 1; + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | + (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); + memcpy(sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid)); + + /* init f2fs-specific super block info */ + sbi->sb = sb; + sbi->raw_super = raw_super; + sbi->raw_super_buf = raw_super_buf; + mutex_init(&sbi->gc_mutex); + mutex_init(&sbi->write_inode); + mutex_init(&sbi->writepages); + mutex_init(&sbi->cp_mutex); + for (i = 0; i < NR_LOCK_TYPE; i++) + mutex_init(&sbi->fs_lock[i]); + sbi->por_doing = 0; + spin_lock_init(&sbi->stat_lock); + init_rwsem(&sbi->bio_sem); + init_sb_info(sbi); + + /* get an inode for meta space */ + sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); + if (IS_ERR(sbi->meta_inode)) { + err = PTR_ERR(sbi->meta_inode); + goto free_sb_buf; + } + + err = get_valid_checkpoint(sbi); + if (err) + goto free_meta_inode; + + /* sanity checking of checkpoint */ + err = -EINVAL; + if (sanity_check_ckpt(raw_super, sbi->ckpt)) + goto free_cp; + + sbi->total_valid_node_count = + le32_to_cpu(sbi->ckpt->valid_node_count); + sbi->total_valid_inode_count = + le32_to_cpu(sbi->ckpt->valid_inode_count); + sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count); + sbi->total_valid_block_count = + le64_to_cpu(sbi->ckpt->valid_block_count); + sbi->last_valid_block_count = sbi->total_valid_block_count; + sbi->alloc_valid_block_count = 0; + INIT_LIST_HEAD(&sbi->dir_inode_list); + spin_lock_init(&sbi->dir_inode_lock); + + /* init super block */ + if (!sb_set_blocksize(sb, sbi->blocksize)) + goto free_cp; + + init_orphan_info(sbi); + + /* setup f2fs internal modules */ + err = build_segment_manager(sbi); + if (err) + goto free_sm; + err = build_node_manager(sbi); + if (err) + goto free_nm; + + build_gc_manager(sbi); + + /* get an inode for node space */ + sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi)); + if (IS_ERR(sbi->node_inode)) { + err = PTR_ERR(sbi->node_inode); + goto free_nm; + } + + /* if there are nt orphan nodes free them */ + err = -EINVAL; + if (!(sbi->ckpt->ckpt_flags & CP_UMOUNT_FLAG) && + recover_orphan_inodes(sbi)) + goto free_node_inode; + + /* read root inode and dentry */ + root = f2fs_iget(sb, F2FS_ROOT_INO(sbi)); + if (IS_ERR(root)) { + err = PTR_ERR(root); + goto free_node_inode; + } + if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) + goto free_root_inode; + + sb->s_root = d_make_root(root); /* allocate root dentry */ + if (!sb->s_root) { + err = -ENOMEM; + goto free_root_inode; + } + + /* recover fsynced data */ + if (!(sbi->ckpt->ckpt_flags & CP_UMOUNT_FLAG) && + !test_opt(sbi, DISABLE_ROLL_FORWARD)) + recover_fsync_data(sbi); + + /* After POR, we can run background GC thread */ + err = start_gc_thread(sbi); + if (err) + goto fail; + + err = f2fs_build_stats(sbi); + if (err) + goto fail; + + return 0; +fail: + stop_gc_thread(sbi); +free_root_inode: + dput(sb->s_root); + sb->s_root = NULL; +free_node_inode: + iput(sbi->node_inode); +free_nm: + destroy_node_manager(sbi); +free_sm: + destroy_segment_manager(sbi); +free_cp: + kfree(sbi->ckpt); +free_meta_inode: + make_bad_inode(sbi->meta_inode); + iput(sbi->meta_inode); +free_sb_buf: + brelse(raw_super_buf); +free_sbi: + kfree(sbi); + return err; +} + +static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) +{ + return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); +} + +static struct file_system_type f2fs_fs_type = { + .owner = THIS_MODULE, + .name = "f2fs", + .mount = f2fs_mount, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, +}; + +static int init_inodecache(void) +{ + f2fs_inode_cachep = f2fs_kmem_cache_create("f2fs_inode_cache", + sizeof(struct f2fs_inode_info), NULL); + if (f2fs_inode_cachep == NULL) + return -ENOMEM; + return 0; +} + +static void destroy_inodecache(void) +{ + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); + kmem_cache_destroy(f2fs_inode_cachep); +} + +static int __init init_f2fs_fs(void) +{ + int err; + + err = init_inodecache(); + if (err) + goto fail; + err = create_node_manager_caches(); + if (err) + goto fail; + err = create_gc_caches(); + if (err) + goto fail; + err = create_checkpoint_caches(); + if (err) + goto fail; + return register_filesystem(&f2fs_fs_type); +fail: + return err; +} + +static void __exit exit_f2fs_fs(void) +{ + destroy_root_stats(); + unregister_filesystem(&f2fs_fs_type); + destroy_checkpoint_caches(); + destroy_gc_caches(); + destroy_node_manager_caches(); + destroy_inodecache(); +} + +module_init(init_f2fs_fs) +module_exit(exit_f2fs_fs) + +MODULE_AUTHOR("Samsung Electronics's Praesto Team"); +MODULE_DESCRIPTION("Flash Friendly File System"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 127e670abfa7fa150f6550d620ded930f5bdb4e7 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:08:18 +0900 Subject: f2fs: add checkpoint operations This adds functions required by the checkpoint operations. Basically, f2fs adopts a roll-back model with checkpoint blocks written in the CP area. The checkpoint procedure includes as follows. - write_checkpoint() 1. block_operations() freezes VFS calls. 2. submit cached bios. 3. flush_nat_entries() writes NAT pages updated by dirty NAT entries. 4. flush_sit_entries() writes SIT pages updated by dirty SIT entries. 5. do_checkpoint() writes, - checkpoint block (#0) - orphan inode blocks - summary blocks made by active logs - checkpoint block (copy of #0) 6. unblock_opeations() In order to provide an address space for meta pages, f2fs_sb_info has a special inode, namely meta_inode. This patch also adds the address space operations for meta_inode. Signed-off-by: Chul Lee Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c new file mode 100644 index 0000000..ab743f9 --- /dev/null +++ b/fs/f2fs/checkpoint.c @@ -0,0 +1,792 @@ +/** + * fs/f2fs/checkpoint.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "node.h" +#include "segment.h" + +static struct kmem_cache *orphan_entry_slab; +static struct kmem_cache *inode_entry_slab; + +/** + * We guarantee no failure on the returned page. + */ +struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) +{ + struct address_space *mapping = sbi->meta_inode->i_mapping; + struct page *page = NULL; +repeat: + page = grab_cache_page(mapping, index); + if (!page) { + cond_resched(); + goto repeat; + } + + /* We wait writeback only inside grab_meta_page() */ + wait_on_page_writeback(page); + SetPageUptodate(page); + return page; +} + +/** + * We guarantee no failure on the returned page. + */ +struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) +{ + struct address_space *mapping = sbi->meta_inode->i_mapping; + struct page *page; +repeat: + page = grab_cache_page(mapping, index); + if (!page) { + cond_resched(); + goto repeat; + } + if (f2fs_readpage(sbi, page, index, READ_SYNC)) { + f2fs_put_page(page, 1); + goto repeat; + } + mark_page_accessed(page); + + /* We do not allow returning an errorneous page */ + return page; +} + +static int f2fs_write_meta_page(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + int err; + + wait_on_page_writeback(page); + + err = write_meta_page(sbi, page, wbc); + if (err) { + wbc->pages_skipped++; + set_page_dirty(page); + } + + dec_page_count(sbi, F2FS_DIRTY_META); + + /* In this case, we should not unlock this page */ + if (err != AOP_WRITEPAGE_ACTIVATE) + unlock_page(page); + return err; +} + +static int f2fs_write_meta_pages(struct address_space *mapping, + struct writeback_control *wbc) +{ + struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); + struct block_device *bdev = sbi->sb->s_bdev; + long written; + + if (wbc->for_kupdate) + return 0; + + if (get_pages(sbi, F2FS_DIRTY_META) == 0) + return 0; + + /* if mounting is failed, skip writing node pages */ + mutex_lock(&sbi->cp_mutex); + written = sync_meta_pages(sbi, META, bio_get_nr_vecs(bdev)); + mutex_unlock(&sbi->cp_mutex); + wbc->nr_to_write -= written; + return 0; +} + +long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, + long nr_to_write) +{ + struct address_space *mapping = sbi->meta_inode->i_mapping; + pgoff_t index = 0, end = LONG_MAX; + struct pagevec pvec; + long nwritten = 0; + struct writeback_control wbc = { + .for_reclaim = 0, + }; + + pagevec_init(&pvec, 0); + + while (index <= end) { + int i, nr_pages; + nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, + PAGECACHE_TAG_DIRTY, + min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); + if (nr_pages == 0) + break; + + for (i = 0; i < nr_pages; i++) { + struct page *page = pvec.pages[i]; + lock_page(page); + BUG_ON(page->mapping != mapping); + BUG_ON(!PageDirty(page)); + clear_page_dirty_for_io(page); + f2fs_write_meta_page(page, &wbc); + if (nwritten++ >= nr_to_write) + break; + } + pagevec_release(&pvec); + cond_resched(); + } + + if (nwritten) + f2fs_submit_bio(sbi, type, nr_to_write == LONG_MAX); + + return nwritten; +} + +static int f2fs_set_meta_page_dirty(struct page *page) +{ + struct address_space *mapping = page->mapping; + struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); + + SetPageUptodate(page); + if (!PageDirty(page)) { + __set_page_dirty_nobuffers(page); + inc_page_count(sbi, F2FS_DIRTY_META); + F2FS_SET_SB_DIRT(sbi); + return 1; + } + return 0; +} + +const struct address_space_operations f2fs_meta_aops = { + .writepage = f2fs_write_meta_page, + .writepages = f2fs_write_meta_pages, + .set_page_dirty = f2fs_set_meta_page_dirty, +}; + +int check_orphan_space(struct f2fs_sb_info *sbi) +{ + unsigned int max_orphans; + int err = 0; + + /* + * considering 512 blocks in a segment 5 blocks are needed for cp + * and log segment summaries. Remaining blocks are used to keep + * orphan entries with the limitation one reserved segment + * for cp pack we can have max 1020*507 orphan entries + */ + max_orphans = (sbi->blocks_per_seg - 5) * F2FS_ORPHANS_PER_BLOCK; + mutex_lock(&sbi->orphan_inode_mutex); + if (sbi->n_orphans >= max_orphans) + err = -ENOSPC; + mutex_unlock(&sbi->orphan_inode_mutex); + return err; +} + +void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) +{ + struct list_head *head, *this; + struct orphan_inode_entry *new = NULL, *orphan = NULL; + + mutex_lock(&sbi->orphan_inode_mutex); + head = &sbi->orphan_inode_list; + list_for_each(this, head) { + orphan = list_entry(this, struct orphan_inode_entry, list); + if (orphan->ino == ino) + goto out; + if (orphan->ino > ino) + break; + orphan = NULL; + } +retry: + new = kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC); + if (!new) { + cond_resched(); + goto retry; + } + new->ino = ino; + INIT_LIST_HEAD(&new->list); + + /* add new_oentry into list which is sorted by inode number */ + if (orphan) { + struct orphan_inode_entry *prev; + + /* get previous entry */ + prev = list_entry(orphan->list.prev, typeof(*prev), list); + if (&prev->list != head) + /* insert new orphan inode entry */ + list_add(&new->list, &prev->list); + else + list_add(&new->list, head); + } else { + list_add_tail(&new->list, head); + } + sbi->n_orphans++; +out: + mutex_unlock(&sbi->orphan_inode_mutex); +} + +void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) +{ + struct list_head *this, *next, *head; + struct orphan_inode_entry *orphan; + + mutex_lock(&sbi->orphan_inode_mutex); + head = &sbi->orphan_inode_list; + list_for_each_safe(this, next, head) { + orphan = list_entry(this, struct orphan_inode_entry, list); + if (orphan->ino == ino) { + list_del(&orphan->list); + kmem_cache_free(orphan_entry_slab, orphan); + sbi->n_orphans--; + break; + } + } + mutex_unlock(&sbi->orphan_inode_mutex); +} + +static void recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) +{ + struct inode *inode = f2fs_iget(sbi->sb, ino); + BUG_ON(IS_ERR(inode)); + clear_nlink(inode); + + /* truncate all the data during iput */ + iput(inode); +} + +int recover_orphan_inodes(struct f2fs_sb_info *sbi) +{ + block_t start_blk, orphan_blkaddr, i, j; + + if (!(F2FS_CKPT(sbi)->ckpt_flags & CP_ORPHAN_PRESENT_FLAG)) + return 0; + + sbi->por_doing = 1; + start_blk = __start_cp_addr(sbi) + 1; + orphan_blkaddr = __start_sum_addr(sbi) - 1; + + for (i = 0; i < orphan_blkaddr; i++) { + struct page *page = get_meta_page(sbi, start_blk + i); + struct f2fs_orphan_block *orphan_blk; + + orphan_blk = (struct f2fs_orphan_block *)page_address(page); + for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) { + nid_t ino = le32_to_cpu(orphan_blk->ino[j]); + recover_orphan_inode(sbi, ino); + } + f2fs_put_page(page, 1); + } + /* clear Orphan Flag */ + F2FS_CKPT(sbi)->ckpt_flags &= (~CP_ORPHAN_PRESENT_FLAG); + sbi->por_doing = 0; + return 0; +} + +static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk) +{ + struct list_head *head, *this, *next; + struct f2fs_orphan_block *orphan_blk = NULL; + struct page *page = NULL; + unsigned int nentries = 0; + unsigned short index = 1; + unsigned short orphan_blocks; + + orphan_blocks = (unsigned short)((sbi->n_orphans + + (F2FS_ORPHANS_PER_BLOCK - 1)) / F2FS_ORPHANS_PER_BLOCK); + + mutex_lock(&sbi->orphan_inode_mutex); + head = &sbi->orphan_inode_list; + + /* loop for each orphan inode entry and write them in Jornal block */ + list_for_each_safe(this, next, head) { + struct orphan_inode_entry *orphan; + + orphan = list_entry(this, struct orphan_inode_entry, list); + + if (nentries == F2FS_ORPHANS_PER_BLOCK) { + /* + * an orphan block is full of 1020 entries, + * then we need to flush current orphan blocks + * and bring another one in memory + */ + orphan_blk->blk_addr = cpu_to_le16(index); + orphan_blk->blk_count = cpu_to_le16(orphan_blocks); + orphan_blk->entry_count = cpu_to_le32(nentries); + set_page_dirty(page); + f2fs_put_page(page, 1); + index++; + start_blk++; + nentries = 0; + page = NULL; + } + if (page) + goto page_exist; + + page = grab_meta_page(sbi, start_blk); + orphan_blk = (struct f2fs_orphan_block *)page_address(page); + memset(orphan_blk, 0, sizeof(*orphan_blk)); +page_exist: + orphan_blk->ino[nentries++] = cpu_to_le32(orphan->ino); + } + if (!page) + goto end; + + orphan_blk->blk_addr = cpu_to_le16(index); + orphan_blk->blk_count = cpu_to_le16(orphan_blocks); + orphan_blk->entry_count = cpu_to_le32(nentries); + set_page_dirty(page); + f2fs_put_page(page, 1); +end: + mutex_unlock(&sbi->orphan_inode_mutex); +} + +static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, + block_t cp_addr, unsigned long long *version) +{ + struct page *cp_page_1, *cp_page_2 = NULL; + unsigned long blk_size = sbi->blocksize; + struct f2fs_checkpoint *cp_block; + unsigned long long cur_version = 0, pre_version = 0; + unsigned int crc = 0; + size_t crc_offset; + + /* Read the 1st cp block in this CP pack */ + cp_page_1 = get_meta_page(sbi, cp_addr); + + /* get the version number */ + cp_block = (struct f2fs_checkpoint *)page_address(cp_page_1); + crc_offset = le32_to_cpu(cp_block->checksum_offset); + if (crc_offset >= blk_size) + goto invalid_cp1; + + crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); + if (!f2fs_crc_valid(crc, cp_block, crc_offset)) + goto invalid_cp1; + + pre_version = le64_to_cpu(cp_block->checkpoint_ver); + + /* Read the 2nd cp block in this CP pack */ + cp_addr += le64_to_cpu(cp_block->cp_pack_total_block_count) - 1; + cp_page_2 = get_meta_page(sbi, cp_addr); + + cp_block = (struct f2fs_checkpoint *)page_address(cp_page_2); + crc_offset = le32_to_cpu(cp_block->checksum_offset); + if (crc_offset >= blk_size) + goto invalid_cp2; + + crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); + if (!f2fs_crc_valid(crc, cp_block, crc_offset)) + goto invalid_cp2; + + cur_version = le64_to_cpu(cp_block->checkpoint_ver); + + if (cur_version == pre_version) { + *version = cur_version; + f2fs_put_page(cp_page_2, 1); + return cp_page_1; + } +invalid_cp2: + f2fs_put_page(cp_page_2, 1); +invalid_cp1: + f2fs_put_page(cp_page_1, 1); + return NULL; +} + +int get_valid_checkpoint(struct f2fs_sb_info *sbi) +{ + struct f2fs_checkpoint *cp_block; + struct f2fs_super_block *fsb = sbi->raw_super; + struct page *cp1, *cp2, *cur_page; + unsigned long blk_size = sbi->blocksize; + unsigned long long cp1_version = 0, cp2_version = 0; + unsigned long long cp_start_blk_no; + + sbi->ckpt = kzalloc(blk_size, GFP_KERNEL); + if (!sbi->ckpt) + return -ENOMEM; + /* + * Finding out valid cp block involves read both + * sets( cp pack1 and cp pack 2) + */ + cp_start_blk_no = le32_to_cpu(fsb->cp_blkaddr); + cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version); + + /* The second checkpoint pack should start at the next segment */ + cp_start_blk_no += 1 << le32_to_cpu(fsb->log_blocks_per_seg); + cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version); + + if (cp1 && cp2) { + if (ver_after(cp2_version, cp1_version)) + cur_page = cp2; + else + cur_page = cp1; + } else if (cp1) { + cur_page = cp1; + } else if (cp2) { + cur_page = cp2; + } else { + goto fail_no_cp; + } + + cp_block = (struct f2fs_checkpoint *)page_address(cur_page); + memcpy(sbi->ckpt, cp_block, blk_size); + + f2fs_put_page(cp1, 1); + f2fs_put_page(cp2, 1); + return 0; + +fail_no_cp: + kfree(sbi->ckpt); + return -EINVAL; +} + +void set_dirty_dir_page(struct inode *inode, struct page *page) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct list_head *head = &sbi->dir_inode_list; + struct dir_inode_entry *new; + struct list_head *this; + + if (!S_ISDIR(inode->i_mode)) + return; +retry: + new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS); + if (!new) { + cond_resched(); + goto retry; + } + new->inode = inode; + INIT_LIST_HEAD(&new->list); + + spin_lock(&sbi->dir_inode_lock); + list_for_each(this, head) { + struct dir_inode_entry *entry; + entry = list_entry(this, struct dir_inode_entry, list); + if (entry->inode == inode) { + kmem_cache_free(inode_entry_slab, new); + goto out; + } + } + list_add_tail(&new->list, head); + sbi->n_dirty_dirs++; + + BUG_ON(!S_ISDIR(inode->i_mode)); +out: + inc_page_count(sbi, F2FS_DIRTY_DENTS); + inode_inc_dirty_dents(inode); + SetPagePrivate(page); + + spin_unlock(&sbi->dir_inode_lock); +} + +void remove_dirty_dir_inode(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct list_head *head = &sbi->dir_inode_list; + struct list_head *this; + + if (!S_ISDIR(inode->i_mode)) + return; + + spin_lock(&sbi->dir_inode_lock); + if (atomic_read(&F2FS_I(inode)->dirty_dents)) + goto out; + + list_for_each(this, head) { + struct dir_inode_entry *entry; + entry = list_entry(this, struct dir_inode_entry, list); + if (entry->inode == inode) { + list_del(&entry->list); + kmem_cache_free(inode_entry_slab, entry); + sbi->n_dirty_dirs--; + break; + } + } +out: + spin_unlock(&sbi->dir_inode_lock); +} + +void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) +{ + struct list_head *head = &sbi->dir_inode_list; + struct dir_inode_entry *entry; + struct inode *inode; +retry: + spin_lock(&sbi->dir_inode_lock); + if (list_empty(head)) { + spin_unlock(&sbi->dir_inode_lock); + return; + } + entry = list_entry(head->next, struct dir_inode_entry, list); + inode = igrab(entry->inode); + spin_unlock(&sbi->dir_inode_lock); + if (inode) { + filemap_flush(inode->i_mapping); + iput(inode); + } else { + /* + * We should submit bio, since it exists several + * wribacking dentry pages in the freeing inode. + */ + f2fs_submit_bio(sbi, DATA, true); + } + goto retry; +} + +/** + * Freeze all the FS-operations for checkpoint. + */ +void block_operations(struct f2fs_sb_info *sbi) +{ + int t; + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .for_reclaim = 0, + }; + + /* Stop renaming operation */ + mutex_lock_op(sbi, RENAME); + mutex_lock_op(sbi, DENTRY_OPS); + +retry_dents: + /* write all the dirty dentry pages */ + sync_dirty_dir_inodes(sbi); + + mutex_lock_op(sbi, DATA_WRITE); + if (get_pages(sbi, F2FS_DIRTY_DENTS)) { + mutex_unlock_op(sbi, DATA_WRITE); + goto retry_dents; + } + + /* block all the operations */ + for (t = DATA_NEW; t <= NODE_TRUNC; t++) + mutex_lock_op(sbi, t); + + mutex_lock(&sbi->write_inode); + + /* + * POR: we should ensure that there is no dirty node pages + * until finishing nat/sit flush. + */ +retry: + sync_node_pages(sbi, 0, &wbc); + + mutex_lock_op(sbi, NODE_WRITE); + + if (get_pages(sbi, F2FS_DIRTY_NODES)) { + mutex_unlock_op(sbi, NODE_WRITE); + goto retry; + } + mutex_unlock(&sbi->write_inode); +} + +static void unblock_operations(struct f2fs_sb_info *sbi) +{ + int t; + for (t = NODE_WRITE; t >= RENAME; t--) + mutex_unlock_op(sbi, t); +} + +static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + nid_t last_nid = 0; + block_t start_blk; + struct page *cp_page; + unsigned int data_sum_blocks, orphan_blocks; + void *kaddr; + __u32 crc32 = 0; + int i; + + /* Flush all the NAT/SIT pages */ + while (get_pages(sbi, F2FS_DIRTY_META)) + sync_meta_pages(sbi, META, LONG_MAX); + + next_free_nid(sbi, &last_nid); + + /* + * modify checkpoint + * version number is already updated + */ + ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi)); + ckpt->valid_block_count = cpu_to_le64(valid_user_blocks(sbi)); + ckpt->free_segment_count = cpu_to_le32(free_segments(sbi)); + for (i = 0; i < 3; i++) { + ckpt->cur_node_segno[i] = + cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_NODE)); + ckpt->cur_node_blkoff[i] = + cpu_to_le16(curseg_blkoff(sbi, i + CURSEG_HOT_NODE)); + ckpt->alloc_type[i + CURSEG_HOT_NODE] = + curseg_alloc_type(sbi, i + CURSEG_HOT_NODE); + } + for (i = 0; i < 3; i++) { + ckpt->cur_data_segno[i] = + cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_DATA)); + ckpt->cur_data_blkoff[i] = + cpu_to_le16(curseg_blkoff(sbi, i + CURSEG_HOT_DATA)); + ckpt->alloc_type[i + CURSEG_HOT_DATA] = + curseg_alloc_type(sbi, i + CURSEG_HOT_DATA); + } + + ckpt->valid_node_count = cpu_to_le32(valid_node_count(sbi)); + ckpt->valid_inode_count = cpu_to_le32(valid_inode_count(sbi)); + ckpt->next_free_nid = cpu_to_le32(last_nid); + + /* 2 cp + n data seg summary + orphan inode blocks */ + data_sum_blocks = npages_for_summary_flush(sbi); + if (data_sum_blocks < 3) + ckpt->ckpt_flags |= CP_COMPACT_SUM_FLAG; + else + ckpt->ckpt_flags &= (~CP_COMPACT_SUM_FLAG); + + orphan_blocks = (sbi->n_orphans + F2FS_ORPHANS_PER_BLOCK - 1) + / F2FS_ORPHANS_PER_BLOCK; + ckpt->cp_pack_start_sum = 1 + orphan_blocks; + ckpt->cp_pack_total_block_count = 2 + data_sum_blocks + orphan_blocks; + + if (is_umount) { + ckpt->ckpt_flags |= CP_UMOUNT_FLAG; + ckpt->cp_pack_total_block_count += NR_CURSEG_NODE_TYPE; + } else { + ckpt->ckpt_flags &= (~CP_UMOUNT_FLAG); + } + + if (sbi->n_orphans) + ckpt->ckpt_flags |= CP_ORPHAN_PRESENT_FLAG; + else + ckpt->ckpt_flags &= (~CP_ORPHAN_PRESENT_FLAG); + + /* update SIT/NAT bitmap */ + get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP)); + get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP)); + + crc32 = f2fs_crc32(ckpt, le32_to_cpu(ckpt->checksum_offset)); + *(__u32 *)((unsigned char *)ckpt + + le32_to_cpu(ckpt->checksum_offset)) + = cpu_to_le32(crc32); + + start_blk = __start_cp_addr(sbi); + + /* write out checkpoint buffer at block 0 */ + cp_page = grab_meta_page(sbi, start_blk++); + kaddr = page_address(cp_page); + memcpy(kaddr, ckpt, (1 << sbi->log_blocksize)); + set_page_dirty(cp_page); + f2fs_put_page(cp_page, 1); + + if (sbi->n_orphans) { + write_orphan_inodes(sbi, start_blk); + start_blk += orphan_blocks; + } + + write_data_summaries(sbi, start_blk); + start_blk += data_sum_blocks; + if (is_umount) { + write_node_summaries(sbi, start_blk); + start_blk += NR_CURSEG_NODE_TYPE; + } + + /* writeout checkpoint block */ + cp_page = grab_meta_page(sbi, start_blk); + kaddr = page_address(cp_page); + memcpy(kaddr, ckpt, (1 << sbi->log_blocksize)); + set_page_dirty(cp_page); + f2fs_put_page(cp_page, 1); + + /* wait for previous submitted node/meta pages writeback */ + while (get_pages(sbi, F2FS_WRITEBACK)) + congestion_wait(BLK_RW_ASYNC, HZ / 50); + + filemap_fdatawait_range(sbi->node_inode->i_mapping, 0, LONG_MAX); + filemap_fdatawait_range(sbi->meta_inode->i_mapping, 0, LONG_MAX); + + /* update user_block_counts */ + sbi->last_valid_block_count = sbi->total_valid_block_count; + sbi->alloc_valid_block_count = 0; + + /* Here, we only have one bio having CP pack */ + if (sbi->ckpt->ckpt_flags & CP_ERROR_FLAG) + sbi->sb->s_flags |= MS_RDONLY; + else + sync_meta_pages(sbi, META_FLUSH, LONG_MAX); + + clear_prefree_segments(sbi); + F2FS_RESET_SB_DIRT(sbi); +} + +/** + * We guarantee that this checkpoint procedure should not fail. + */ +void write_checkpoint(struct f2fs_sb_info *sbi, bool blocked, bool is_umount) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + unsigned long long ckpt_ver; + + if (!blocked) { + mutex_lock(&sbi->cp_mutex); + block_operations(sbi); + } + + f2fs_submit_bio(sbi, DATA, true); + f2fs_submit_bio(sbi, NODE, true); + f2fs_submit_bio(sbi, META, true); + + /* + * update checkpoint pack index + * Increase the version number so that + * SIT entries and seg summaries are written at correct place + */ + ckpt_ver = le64_to_cpu(ckpt->checkpoint_ver); + ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver); + + /* write cached NAT/SIT entries to NAT/SIT area */ + flush_nat_entries(sbi); + flush_sit_entries(sbi); + + reset_victim_segmap(sbi); + + /* unlock all the fs_lock[] in do_checkpoint() */ + do_checkpoint(sbi, is_umount); + + unblock_operations(sbi); + mutex_unlock(&sbi->cp_mutex); +} + +void init_orphan_info(struct f2fs_sb_info *sbi) +{ + mutex_init(&sbi->orphan_inode_mutex); + INIT_LIST_HEAD(&sbi->orphan_inode_list); + sbi->n_orphans = 0; +} + +int create_checkpoint_caches(void) +{ + orphan_entry_slab = f2fs_kmem_cache_create("f2fs_orphan_entry", + sizeof(struct orphan_inode_entry), NULL); + if (unlikely(!orphan_entry_slab)) + return -ENOMEM; + inode_entry_slab = f2fs_kmem_cache_create("f2fs_dirty_dir_entry", + sizeof(struct dir_inode_entry), NULL); + if (unlikely(!inode_entry_slab)) { + kmem_cache_destroy(orphan_entry_slab); + return -ENOMEM; + } + return 0; +} + +void destroy_checkpoint_caches(void) +{ + kmem_cache_destroy(orphan_entry_slab); + kmem_cache_destroy(inode_entry_slab); +} -- cgit v0.10.2 From e05df3b115e7308afbca652769b54e4549fcc723 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:08:50 +0900 Subject: f2fs: add node operations This adds specific functions to manage NAT pages, a cache for NAT entries, free nids, direct/indirect node blocks for indexing data, and address space for node pages. - The key information of an NAT entry consists of a node id and a block address. - An NAT page is composed of block addresses covered by a certain range of NAT entries, which is maintained by the address space of meta_inode. - A radix tree structure is used to cache NAT entries. The index for the tree is a node id. - When there is no free nid, F2FS should scan NAT entries to find new one. In order to avoid scanning frequently, F2FS manages a list containing a number of free nids in memory. Only when free nids in the list are exhausted, scanning process, build_free_nids(), is triggered. - F2FS has direct and indirect node blocks for indexing data. This patch adds fuctions related to the node block management such as getting, allocating, and truncating node blocks to index data. - In order to cache node blocks in memory, F2FS has a node_inode with an address space for node pages. This patch also adds the address space operations for node_inode. Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c new file mode 100644 index 0000000..216f04d --- /dev/null +++ b/fs/f2fs/node.c @@ -0,0 +1,1763 @@ +/** + * fs/f2fs/node.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "node.h" +#include "segment.h" + +static struct kmem_cache *nat_entry_slab; +static struct kmem_cache *free_nid_slab; + +static void clear_node_page_dirty(struct page *page) +{ + struct address_space *mapping = page->mapping; + struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); + unsigned int long flags; + + if (PageDirty(page)) { + spin_lock_irqsave(&mapping->tree_lock, flags); + radix_tree_tag_clear(&mapping->page_tree, + page_index(page), + PAGECACHE_TAG_DIRTY); + spin_unlock_irqrestore(&mapping->tree_lock, flags); + + clear_page_dirty_for_io(page); + dec_page_count(sbi, F2FS_DIRTY_NODES); + } + ClearPageUptodate(page); +} + +static struct page *get_current_nat_page(struct f2fs_sb_info *sbi, nid_t nid) +{ + pgoff_t index = current_nat_addr(sbi, nid); + return get_meta_page(sbi, index); +} + +static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid) +{ + struct page *src_page; + struct page *dst_page; + pgoff_t src_off; + pgoff_t dst_off; + void *src_addr; + void *dst_addr; + struct f2fs_nm_info *nm_i = NM_I(sbi); + + src_off = current_nat_addr(sbi, nid); + dst_off = next_nat_addr(sbi, src_off); + + /* get current nat block page with lock */ + src_page = get_meta_page(sbi, src_off); + + /* Dirty src_page means that it is already the new target NAT page. */ + if (PageDirty(src_page)) + return src_page; + + dst_page = grab_meta_page(sbi, dst_off); + + src_addr = page_address(src_page); + dst_addr = page_address(dst_page); + memcpy(dst_addr, src_addr, PAGE_CACHE_SIZE); + set_page_dirty(dst_page); + f2fs_put_page(src_page, 1); + + set_to_next_nat(nm_i, nid); + + return dst_page; +} + +/** + * Readahead NAT pages + */ +static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid) +{ + struct address_space *mapping = sbi->meta_inode->i_mapping; + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct page *page; + pgoff_t index; + int i; + + for (i = 0; i < FREE_NID_PAGES; i++, nid += NAT_ENTRY_PER_BLOCK) { + if (nid >= nm_i->max_nid) + nid = 0; + index = current_nat_addr(sbi, nid); + + page = grab_cache_page(mapping, index); + if (!page) + continue; + if (f2fs_readpage(sbi, page, index, READ)) { + f2fs_put_page(page, 1); + continue; + } + page_cache_release(page); + } +} + +static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n) +{ + return radix_tree_lookup(&nm_i->nat_root, n); +} + +static unsigned int __gang_lookup_nat_cache(struct f2fs_nm_info *nm_i, + nid_t start, unsigned int nr, struct nat_entry **ep) +{ + return radix_tree_gang_lookup(&nm_i->nat_root, (void **)ep, start, nr); +} + +static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e) +{ + list_del(&e->list); + radix_tree_delete(&nm_i->nat_root, nat_get_nid(e)); + nm_i->nat_cnt--; + kmem_cache_free(nat_entry_slab, e); +} + +int is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct nat_entry *e; + int is_cp = 1; + + read_lock(&nm_i->nat_tree_lock); + e = __lookup_nat_cache(nm_i, nid); + if (e && !e->checkpointed) + is_cp = 0; + read_unlock(&nm_i->nat_tree_lock); + return is_cp; +} + +static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid) +{ + struct nat_entry *new; + + new = kmem_cache_alloc(nat_entry_slab, GFP_ATOMIC); + if (!new) + return NULL; + if (radix_tree_insert(&nm_i->nat_root, nid, new)) { + kmem_cache_free(nat_entry_slab, new); + return NULL; + } + memset(new, 0, sizeof(struct nat_entry)); + nat_set_nid(new, nid); + list_add_tail(&new->list, &nm_i->nat_entries); + nm_i->nat_cnt++; + return new; +} + +static void cache_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid, + struct f2fs_nat_entry *ne) +{ + struct nat_entry *e; +retry: + write_lock(&nm_i->nat_tree_lock); + e = __lookup_nat_cache(nm_i, nid); + if (!e) { + e = grab_nat_entry(nm_i, nid); + if (!e) { + write_unlock(&nm_i->nat_tree_lock); + goto retry; + } + nat_set_blkaddr(e, le32_to_cpu(ne->block_addr)); + nat_set_ino(e, le32_to_cpu(ne->ino)); + nat_set_version(e, ne->version); + e->checkpointed = true; + } + write_unlock(&nm_i->nat_tree_lock); +} + +static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni, + block_t new_blkaddr) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct nat_entry *e; +retry: + write_lock(&nm_i->nat_tree_lock); + e = __lookup_nat_cache(nm_i, ni->nid); + if (!e) { + e = grab_nat_entry(nm_i, ni->nid); + if (!e) { + write_unlock(&nm_i->nat_tree_lock); + goto retry; + } + e->ni = *ni; + e->checkpointed = true; + BUG_ON(ni->blk_addr == NEW_ADDR); + } else if (new_blkaddr == NEW_ADDR) { + /* + * when nid is reallocated, + * previous nat entry can be remained in nat cache. + * So, reinitialize it with new information. + */ + e->ni = *ni; + BUG_ON(ni->blk_addr != NULL_ADDR); + } + + if (new_blkaddr == NEW_ADDR) + e->checkpointed = false; + + /* sanity check */ + BUG_ON(nat_get_blkaddr(e) != ni->blk_addr); + BUG_ON(nat_get_blkaddr(e) == NULL_ADDR && + new_blkaddr == NULL_ADDR); + BUG_ON(nat_get_blkaddr(e) == NEW_ADDR && + new_blkaddr == NEW_ADDR); + BUG_ON(nat_get_blkaddr(e) != NEW_ADDR && + nat_get_blkaddr(e) != NULL_ADDR && + new_blkaddr == NEW_ADDR); + + /* increament version no as node is removed */ + if (nat_get_blkaddr(e) != NEW_ADDR && new_blkaddr == NULL_ADDR) { + unsigned char version = nat_get_version(e); + nat_set_version(e, inc_node_version(version)); + } + + /* change address */ + nat_set_blkaddr(e, new_blkaddr); + __set_nat_cache_dirty(nm_i, e); + write_unlock(&nm_i->nat_tree_lock); +} + +static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + + if (nm_i->nat_cnt < 2 * NM_WOUT_THRESHOLD) + return 0; + + write_lock(&nm_i->nat_tree_lock); + while (nr_shrink && !list_empty(&nm_i->nat_entries)) { + struct nat_entry *ne; + ne = list_first_entry(&nm_i->nat_entries, + struct nat_entry, list); + __del_from_nat_cache(nm_i, ne); + nr_shrink--; + } + write_unlock(&nm_i->nat_tree_lock); + return nr_shrink; +} + +/** + * This function returns always success + */ +void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_summary_block *sum = curseg->sum_blk; + nid_t start_nid = START_NID(nid); + struct f2fs_nat_block *nat_blk; + struct page *page = NULL; + struct f2fs_nat_entry ne; + struct nat_entry *e; + int i; + + ni->nid = nid; + + /* Check nat cache */ + read_lock(&nm_i->nat_tree_lock); + e = __lookup_nat_cache(nm_i, nid); + if (e) { + ni->ino = nat_get_ino(e); + ni->blk_addr = nat_get_blkaddr(e); + ni->version = nat_get_version(e); + } + read_unlock(&nm_i->nat_tree_lock); + if (e) + return; + + /* Check current segment summary */ + mutex_lock(&curseg->curseg_mutex); + i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0); + if (i >= 0) { + ne = nat_in_journal(sum, i); + node_info_from_raw_nat(ni, &ne); + } + mutex_unlock(&curseg->curseg_mutex); + if (i >= 0) + goto cache; + + /* Fill node_info from nat page */ + page = get_current_nat_page(sbi, start_nid); + nat_blk = (struct f2fs_nat_block *)page_address(page); + ne = nat_blk->entries[nid - start_nid]; + node_info_from_raw_nat(ni, &ne); + f2fs_put_page(page, 1); +cache: + /* cache nat entry */ + cache_nat_entry(NM_I(sbi), nid, &ne); +} + +/** + * The maximum depth is four. + * Offset[0] will have raw inode offset. + */ +static int get_node_path(long block, int offset[4], unsigned int noffset[4]) +{ + const long direct_index = ADDRS_PER_INODE; + const long direct_blks = ADDRS_PER_BLOCK; + const long dptrs_per_blk = NIDS_PER_BLOCK; + const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK; + const long dindirect_blks = indirect_blks * NIDS_PER_BLOCK; + int n = 0; + int level = 0; + + noffset[0] = 0; + + if (block < direct_index) { + offset[n++] = block; + level = 0; + goto got; + } + block -= direct_index; + if (block < direct_blks) { + offset[n++] = NODE_DIR1_BLOCK; + noffset[n] = 1; + offset[n++] = block; + level = 1; + goto got; + } + block -= direct_blks; + if (block < direct_blks) { + offset[n++] = NODE_DIR2_BLOCK; + noffset[n] = 2; + offset[n++] = block; + level = 1; + goto got; + } + block -= direct_blks; + if (block < indirect_blks) { + offset[n++] = NODE_IND1_BLOCK; + noffset[n] = 3; + offset[n++] = block / direct_blks; + noffset[n] = 4 + offset[n - 1]; + offset[n++] = block % direct_blks; + level = 2; + goto got; + } + block -= indirect_blks; + if (block < indirect_blks) { + offset[n++] = NODE_IND2_BLOCK; + noffset[n] = 4 + dptrs_per_blk; + offset[n++] = block / direct_blks; + noffset[n] = 5 + dptrs_per_blk + offset[n - 1]; + offset[n++] = block % direct_blks; + level = 2; + goto got; + } + block -= indirect_blks; + if (block < dindirect_blks) { + offset[n++] = NODE_DIND_BLOCK; + noffset[n] = 5 + (dptrs_per_blk * 2); + offset[n++] = block / indirect_blks; + noffset[n] = 6 + (dptrs_per_blk * 2) + + offset[n - 1] * (dptrs_per_blk + 1); + offset[n++] = (block / direct_blks) % dptrs_per_blk; + noffset[n] = 7 + (dptrs_per_blk * 2) + + offset[n - 2] * (dptrs_per_blk + 1) + + offset[n - 1]; + offset[n++] = block % direct_blks; + level = 3; + goto got; + } else { + BUG(); + } +got: + return level; +} + +/* + * Caller should call f2fs_put_dnode(dn). + */ +int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int ro) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct page *npage[4]; + struct page *parent; + int offset[4]; + unsigned int noffset[4]; + nid_t nids[4]; + int level, i; + int err = 0; + + level = get_node_path(index, offset, noffset); + + nids[0] = dn->inode->i_ino; + npage[0] = get_node_page(sbi, nids[0]); + if (IS_ERR(npage[0])) + return PTR_ERR(npage[0]); + + parent = npage[0]; + nids[1] = get_nid(parent, offset[0], true); + dn->inode_page = npage[0]; + dn->inode_page_locked = true; + + /* get indirect or direct nodes */ + for (i = 1; i <= level; i++) { + bool done = false; + + if (!nids[i] && !ro) { + mutex_lock_op(sbi, NODE_NEW); + + /* alloc new node */ + if (!alloc_nid(sbi, &(nids[i]))) { + mutex_unlock_op(sbi, NODE_NEW); + err = -ENOSPC; + goto release_pages; + } + + dn->nid = nids[i]; + npage[i] = new_node_page(dn, noffset[i]); + if (IS_ERR(npage[i])) { + alloc_nid_failed(sbi, nids[i]); + mutex_unlock_op(sbi, NODE_NEW); + err = PTR_ERR(npage[i]); + goto release_pages; + } + + set_nid(parent, offset[i - 1], nids[i], i == 1); + alloc_nid_done(sbi, nids[i]); + mutex_unlock_op(sbi, NODE_NEW); + done = true; + } else if (ro && i == level && level > 1) { + npage[i] = get_node_page_ra(parent, offset[i - 1]); + if (IS_ERR(npage[i])) { + err = PTR_ERR(npage[i]); + goto release_pages; + } + done = true; + } + if (i == 1) { + dn->inode_page_locked = false; + unlock_page(parent); + } else { + f2fs_put_page(parent, 1); + } + + if (!done) { + npage[i] = get_node_page(sbi, nids[i]); + if (IS_ERR(npage[i])) { + err = PTR_ERR(npage[i]); + f2fs_put_page(npage[0], 0); + goto release_out; + } + } + if (i < level) { + parent = npage[i]; + nids[i + 1] = get_nid(parent, offset[i], false); + } + } + dn->nid = nids[level]; + dn->ofs_in_node = offset[level]; + dn->node_page = npage[level]; + dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node); + return 0; + +release_pages: + f2fs_put_page(parent, 1); + if (i > 1) + f2fs_put_page(npage[0], 0); +release_out: + dn->inode_page = NULL; + dn->node_page = NULL; + return err; +} + +static void truncate_node(struct dnode_of_data *dn) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct node_info ni; + + get_node_info(sbi, dn->nid, &ni); + BUG_ON(ni.blk_addr == NULL_ADDR); + + if (ni.blk_addr != NULL_ADDR) + invalidate_blocks(sbi, ni.blk_addr); + + /* Deallocate node address */ + dec_valid_node_count(sbi, dn->inode, 1); + set_node_addr(sbi, &ni, NULL_ADDR); + + if (dn->nid == dn->inode->i_ino) { + remove_orphan_inode(sbi, dn->nid); + dec_valid_inode_count(sbi); + } else { + sync_inode_page(dn); + } + + clear_node_page_dirty(dn->node_page); + F2FS_SET_SB_DIRT(sbi); + + f2fs_put_page(dn->node_page, 1); + dn->node_page = NULL; +} + +static int truncate_dnode(struct dnode_of_data *dn) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct page *page; + + if (dn->nid == 0) + return 1; + + /* get direct node */ + page = get_node_page(sbi, dn->nid); + if (IS_ERR(page) && PTR_ERR(page) == -ENOENT) + return 1; + else if (IS_ERR(page)) + return PTR_ERR(page); + + /* Make dnode_of_data for parameter */ + dn->node_page = page; + dn->ofs_in_node = 0; + truncate_data_blocks(dn); + truncate_node(dn); + return 1; +} + +static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs, + int ofs, int depth) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct dnode_of_data rdn = *dn; + struct page *page; + struct f2fs_node *rn; + nid_t child_nid; + unsigned int child_nofs; + int freed = 0; + int i, ret; + + if (dn->nid == 0) + return NIDS_PER_BLOCK + 1; + + page = get_node_page(sbi, dn->nid); + if (IS_ERR(page)) + return PTR_ERR(page); + + rn = (struct f2fs_node *)page_address(page); + if (depth < 3) { + for (i = ofs; i < NIDS_PER_BLOCK; i++, freed++) { + child_nid = le32_to_cpu(rn->in.nid[i]); + if (child_nid == 0) + continue; + rdn.nid = child_nid; + ret = truncate_dnode(&rdn); + if (ret < 0) + goto out_err; + set_nid(page, i, 0, false); + } + } else { + child_nofs = nofs + ofs * (NIDS_PER_BLOCK + 1) + 1; + for (i = ofs; i < NIDS_PER_BLOCK; i++) { + child_nid = le32_to_cpu(rn->in.nid[i]); + if (child_nid == 0) { + child_nofs += NIDS_PER_BLOCK + 1; + continue; + } + rdn.nid = child_nid; + ret = truncate_nodes(&rdn, child_nofs, 0, depth - 1); + if (ret == (NIDS_PER_BLOCK + 1)) { + set_nid(page, i, 0, false); + child_nofs += ret; + } else if (ret < 0 && ret != -ENOENT) { + goto out_err; + } + } + freed = child_nofs; + } + + if (!ofs) { + /* remove current indirect node */ + dn->node_page = page; + truncate_node(dn); + freed++; + } else { + f2fs_put_page(page, 1); + } + return freed; + +out_err: + f2fs_put_page(page, 1); + return ret; +} + +static int truncate_partial_nodes(struct dnode_of_data *dn, + struct f2fs_inode *ri, int *offset, int depth) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct page *pages[2]; + nid_t nid[3]; + nid_t child_nid; + int err = 0; + int i; + int idx = depth - 2; + + nid[0] = le32_to_cpu(ri->i_nid[offset[0] - NODE_DIR1_BLOCK]); + if (!nid[0]) + return 0; + + /* get indirect nodes in the path */ + for (i = 0; i < depth - 1; i++) { + /* refernece count'll be increased */ + pages[i] = get_node_page(sbi, nid[i]); + if (IS_ERR(pages[i])) { + depth = i + 1; + err = PTR_ERR(pages[i]); + goto fail; + } + nid[i + 1] = get_nid(pages[i], offset[i + 1], false); + } + + /* free direct nodes linked to a partial indirect node */ + for (i = offset[depth - 1]; i < NIDS_PER_BLOCK; i++) { + child_nid = get_nid(pages[idx], i, false); + if (!child_nid) + continue; + dn->nid = child_nid; + err = truncate_dnode(dn); + if (err < 0) + goto fail; + set_nid(pages[idx], i, 0, false); + } + + if (offset[depth - 1] == 0) { + dn->node_page = pages[idx]; + dn->nid = nid[idx]; + truncate_node(dn); + } else { + f2fs_put_page(pages[idx], 1); + } + offset[idx]++; + offset[depth - 1] = 0; +fail: + for (i = depth - 3; i >= 0; i--) + f2fs_put_page(pages[i], 1); + return err; +} + +/** + * All the block addresses of data and nodes should be nullified. + */ +int truncate_inode_blocks(struct inode *inode, pgoff_t from) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + int err = 0, cont = 1; + int level, offset[4], noffset[4]; + unsigned int nofs; + struct f2fs_node *rn; + struct dnode_of_data dn; + struct page *page; + + level = get_node_path(from, offset, noffset); + + page = get_node_page(sbi, inode->i_ino); + if (IS_ERR(page)) + return PTR_ERR(page); + + set_new_dnode(&dn, inode, page, NULL, 0); + unlock_page(page); + + rn = page_address(page); + switch (level) { + case 0: + case 1: + nofs = noffset[1]; + break; + case 2: + nofs = noffset[1]; + if (!offset[level - 1]) + goto skip_partial; + err = truncate_partial_nodes(&dn, &rn->i, offset, level); + if (err < 0 && err != -ENOENT) + goto fail; + nofs += 1 + NIDS_PER_BLOCK; + break; + case 3: + nofs = 5 + 2 * NIDS_PER_BLOCK; + if (!offset[level - 1]) + goto skip_partial; + err = truncate_partial_nodes(&dn, &rn->i, offset, level); + if (err < 0 && err != -ENOENT) + goto fail; + break; + default: + BUG(); + } + +skip_partial: + while (cont) { + dn.nid = le32_to_cpu(rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]); + switch (offset[0]) { + case NODE_DIR1_BLOCK: + case NODE_DIR2_BLOCK: + err = truncate_dnode(&dn); + break; + + case NODE_IND1_BLOCK: + case NODE_IND2_BLOCK: + err = truncate_nodes(&dn, nofs, offset[1], 2); + break; + + case NODE_DIND_BLOCK: + err = truncate_nodes(&dn, nofs, offset[1], 3); + cont = 0; + break; + + default: + BUG(); + } + if (err < 0 && err != -ENOENT) + goto fail; + if (offset[1] == 0 && + rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]) { + lock_page(page); + wait_on_page_writeback(page); + rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK] = 0; + set_page_dirty(page); + unlock_page(page); + } + offset[1] = 0; + offset[0]++; + nofs += err; + } +fail: + f2fs_put_page(page, 0); + return err > 0 ? 0 : err; +} + +int remove_inode_page(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct page *page; + nid_t ino = inode->i_ino; + struct dnode_of_data dn; + + mutex_lock_op(sbi, NODE_TRUNC); + page = get_node_page(sbi, ino); + if (IS_ERR(page)) { + mutex_unlock_op(sbi, NODE_TRUNC); + return PTR_ERR(page); + } + + if (F2FS_I(inode)->i_xattr_nid) { + nid_t nid = F2FS_I(inode)->i_xattr_nid; + struct page *npage = get_node_page(sbi, nid); + + if (IS_ERR(npage)) { + mutex_unlock_op(sbi, NODE_TRUNC); + return PTR_ERR(npage); + } + + F2FS_I(inode)->i_xattr_nid = 0; + set_new_dnode(&dn, inode, page, npage, nid); + dn.inode_page_locked = 1; + truncate_node(&dn); + } + if (inode->i_blocks == 1) { + /* inernally call f2fs_put_page() */ + set_new_dnode(&dn, inode, page, page, ino); + truncate_node(&dn); + } else if (inode->i_blocks == 0) { + struct node_info ni; + get_node_info(sbi, inode->i_ino, &ni); + + /* called after f2fs_new_inode() is failed */ + BUG_ON(ni.blk_addr != NULL_ADDR); + f2fs_put_page(page, 1); + } else { + BUG(); + } + mutex_unlock_op(sbi, NODE_TRUNC); + return 0; +} + +int new_inode_page(struct inode *inode, struct dentry *dentry) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct page *page; + struct dnode_of_data dn; + + /* allocate inode page for new inode */ + set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino); + mutex_lock_op(sbi, NODE_NEW); + page = new_node_page(&dn, 0); + init_dent_inode(dentry, page); + mutex_unlock_op(sbi, NODE_NEW); + if (IS_ERR(page)) + return PTR_ERR(page); + f2fs_put_page(page, 1); + return 0; +} + +struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct address_space *mapping = sbi->node_inode->i_mapping; + struct node_info old_ni, new_ni; + struct page *page; + int err; + + if (is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)) + return ERR_PTR(-EPERM); + + page = grab_cache_page(mapping, dn->nid); + if (!page) + return ERR_PTR(-ENOMEM); + + get_node_info(sbi, dn->nid, &old_ni); + + SetPageUptodate(page); + fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true); + + /* Reinitialize old_ni with new node page */ + BUG_ON(old_ni.blk_addr != NULL_ADDR); + new_ni = old_ni; + new_ni.ino = dn->inode->i_ino; + + if (!inc_valid_node_count(sbi, dn->inode, 1)) { + err = -ENOSPC; + goto fail; + } + set_node_addr(sbi, &new_ni, NEW_ADDR); + + dn->node_page = page; + sync_inode_page(dn); + set_page_dirty(page); + set_cold_node(dn->inode, page); + if (ofs == 0) + inc_valid_inode_count(sbi); + + return page; + +fail: + f2fs_put_page(page, 1); + return ERR_PTR(err); +} + +static int read_node_page(struct page *page, int type) +{ + struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); + struct node_info ni; + + get_node_info(sbi, page->index, &ni); + + if (ni.blk_addr == NULL_ADDR) + return -ENOENT; + return f2fs_readpage(sbi, page, ni.blk_addr, type); +} + +/** + * Readahead a node page + */ +void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) +{ + struct address_space *mapping = sbi->node_inode->i_mapping; + struct page *apage; + + apage = find_get_page(mapping, nid); + if (apage && PageUptodate(apage)) + goto release_out; + f2fs_put_page(apage, 0); + + apage = grab_cache_page(mapping, nid); + if (!apage) + return; + + if (read_node_page(apage, READA)) + goto unlock_out; + + page_cache_release(apage); + return; + +unlock_out: + unlock_page(apage); +release_out: + page_cache_release(apage); +} + +struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) +{ + int err; + struct page *page; + struct address_space *mapping = sbi->node_inode->i_mapping; + + page = grab_cache_page(mapping, nid); + if (!page) + return ERR_PTR(-ENOMEM); + + err = read_node_page(page, READ_SYNC); + if (err) { + f2fs_put_page(page, 1); + return ERR_PTR(err); + } + + BUG_ON(nid != nid_of_node(page)); + mark_page_accessed(page); + return page; +} + +/** + * Return a locked page for the desired node page. + * And, readahead MAX_RA_NODE number of node pages. + */ +struct page *get_node_page_ra(struct page *parent, int start) +{ + struct f2fs_sb_info *sbi = F2FS_SB(parent->mapping->host->i_sb); + struct address_space *mapping = sbi->node_inode->i_mapping; + int i, end; + int err = 0; + nid_t nid; + struct page *page; + + /* First, try getting the desired direct node. */ + nid = get_nid(parent, start, false); + if (!nid) + return ERR_PTR(-ENOENT); + + page = find_get_page(mapping, nid); + if (page && PageUptodate(page)) + goto page_hit; + f2fs_put_page(page, 0); + +repeat: + page = grab_cache_page(mapping, nid); + if (!page) + return ERR_PTR(-ENOMEM); + + err = read_node_page(page, READA); + if (err) { + f2fs_put_page(page, 1); + return ERR_PTR(err); + } + + /* Then, try readahead for siblings of the desired node */ + end = start + MAX_RA_NODE; + end = min(end, NIDS_PER_BLOCK); + for (i = start + 1; i < end; i++) { + nid = get_nid(parent, i, false); + if (!nid) + continue; + ra_node_page(sbi, nid); + } + +page_hit: + lock_page(page); + if (PageError(page)) { + f2fs_put_page(page, 1); + return ERR_PTR(-EIO); + } + + /* Has the page been truncated? */ + if (page->mapping != mapping) { + f2fs_put_page(page, 1); + goto repeat; + } + return page; +} + +void sync_inode_page(struct dnode_of_data *dn) +{ + if (IS_INODE(dn->node_page) || dn->inode_page == dn->node_page) { + update_inode(dn->inode, dn->node_page); + } else if (dn->inode_page) { + if (!dn->inode_page_locked) + lock_page(dn->inode_page); + update_inode(dn->inode, dn->inode_page); + if (!dn->inode_page_locked) + unlock_page(dn->inode_page); + } else { + f2fs_write_inode(dn->inode, NULL); + } +} + +int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino, + struct writeback_control *wbc) +{ + struct address_space *mapping = sbi->node_inode->i_mapping; + pgoff_t index, end; + struct pagevec pvec; + int step = ino ? 2 : 0; + int nwritten = 0, wrote = 0; + + pagevec_init(&pvec, 0); + +next_step: + index = 0; + end = LONG_MAX; + + while (index <= end) { + int i, nr_pages; + nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, + PAGECACHE_TAG_DIRTY, + min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); + if (nr_pages == 0) + break; + + for (i = 0; i < nr_pages; i++) { + struct page *page = pvec.pages[i]; + + /* + * flushing sequence with step: + * 0. indirect nodes + * 1. dentry dnodes + * 2. file dnodes + */ + if (step == 0 && IS_DNODE(page)) + continue; + if (step == 1 && (!IS_DNODE(page) || + is_cold_node(page))) + continue; + if (step == 2 && (!IS_DNODE(page) || + !is_cold_node(page))) + continue; + + /* + * If an fsync mode, + * we should not skip writing node pages. + */ + if (ino && ino_of_node(page) == ino) + lock_page(page); + else if (!trylock_page(page)) + continue; + + if (unlikely(page->mapping != mapping)) { +continue_unlock: + unlock_page(page); + continue; + } + if (ino && ino_of_node(page) != ino) + goto continue_unlock; + + if (!PageDirty(page)) { + /* someone wrote it for us */ + goto continue_unlock; + } + + if (!clear_page_dirty_for_io(page)) + goto continue_unlock; + + /* called by fsync() */ + if (ino && IS_DNODE(page)) { + int mark = !is_checkpointed_node(sbi, ino); + set_fsync_mark(page, 1); + if (IS_INODE(page)) + set_dentry_mark(page, mark); + nwritten++; + } else { + set_fsync_mark(page, 0); + set_dentry_mark(page, 0); + } + mapping->a_ops->writepage(page, wbc); + wrote++; + + if (--wbc->nr_to_write == 0) + break; + } + pagevec_release(&pvec); + cond_resched(); + + if (wbc->nr_to_write == 0) { + step = 2; + break; + } + } + + if (step < 2) { + step++; + goto next_step; + } + + if (wrote) + f2fs_submit_bio(sbi, NODE, wbc->sync_mode == WB_SYNC_ALL); + + return nwritten; +} + +static int f2fs_write_node_page(struct page *page, + struct writeback_control *wbc) +{ + struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); + nid_t nid; + unsigned int nofs; + block_t new_addr; + struct node_info ni; + + if (wbc->for_reclaim) { + dec_page_count(sbi, F2FS_DIRTY_NODES); + wbc->pages_skipped++; + set_page_dirty(page); + return AOP_WRITEPAGE_ACTIVATE; + } + + wait_on_page_writeback(page); + + mutex_lock_op(sbi, NODE_WRITE); + + /* get old block addr of this node page */ + nid = nid_of_node(page); + nofs = ofs_of_node(page); + BUG_ON(page->index != nid); + + get_node_info(sbi, nid, &ni); + + /* This page is already truncated */ + if (ni.blk_addr == NULL_ADDR) + return 0; + + set_page_writeback(page); + + /* insert node offset */ + write_node_page(sbi, page, nid, ni.blk_addr, &new_addr); + set_node_addr(sbi, &ni, new_addr); + dec_page_count(sbi, F2FS_DIRTY_NODES); + + mutex_unlock_op(sbi, NODE_WRITE); + unlock_page(page); + return 0; +} + +static int f2fs_write_node_pages(struct address_space *mapping, + struct writeback_control *wbc) +{ + struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); + struct block_device *bdev = sbi->sb->s_bdev; + long nr_to_write = wbc->nr_to_write; + + if (wbc->for_kupdate) + return 0; + + if (get_pages(sbi, F2FS_DIRTY_NODES) == 0) + return 0; + + if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) { + write_checkpoint(sbi, false, false); + return 0; + } + + /* if mounting is failed, skip writing node pages */ + wbc->nr_to_write = bio_get_nr_vecs(bdev); + sync_node_pages(sbi, 0, wbc); + wbc->nr_to_write = nr_to_write - + (bio_get_nr_vecs(bdev) - wbc->nr_to_write); + return 0; +} + +static int f2fs_set_node_page_dirty(struct page *page) +{ + struct address_space *mapping = page->mapping; + struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb); + + SetPageUptodate(page); + if (!PageDirty(page)) { + __set_page_dirty_nobuffers(page); + inc_page_count(sbi, F2FS_DIRTY_NODES); + SetPagePrivate(page); + return 1; + } + return 0; +} + +static void f2fs_invalidate_node_page(struct page *page, unsigned long offset) +{ + struct inode *inode = page->mapping->host; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + if (PageDirty(page)) + dec_page_count(sbi, F2FS_DIRTY_NODES); + ClearPagePrivate(page); +} + +static int f2fs_release_node_page(struct page *page, gfp_t wait) +{ + ClearPagePrivate(page); + return 0; +} + +/** + * Structure of the f2fs node operations + */ +const struct address_space_operations f2fs_node_aops = { + .writepage = f2fs_write_node_page, + .writepages = f2fs_write_node_pages, + .set_page_dirty = f2fs_set_node_page_dirty, + .invalidatepage = f2fs_invalidate_node_page, + .releasepage = f2fs_release_node_page, +}; + +static struct free_nid *__lookup_free_nid_list(nid_t n, struct list_head *head) +{ + struct list_head *this; + struct free_nid *i = NULL; + list_for_each(this, head) { + i = list_entry(this, struct free_nid, list); + if (i->nid == n) + break; + i = NULL; + } + return i; +} + +static void __del_from_free_nid_list(struct free_nid *i) +{ + list_del(&i->list); + kmem_cache_free(free_nid_slab, i); +} + +static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid) +{ + struct free_nid *i; + + if (nm_i->fcnt > 2 * MAX_FREE_NIDS) + return 0; +retry: + i = kmem_cache_alloc(free_nid_slab, GFP_NOFS); + if (!i) { + cond_resched(); + goto retry; + } + i->nid = nid; + i->state = NID_NEW; + + spin_lock(&nm_i->free_nid_list_lock); + if (__lookup_free_nid_list(nid, &nm_i->free_nid_list)) { + spin_unlock(&nm_i->free_nid_list_lock); + kmem_cache_free(free_nid_slab, i); + return 0; + } + list_add_tail(&i->list, &nm_i->free_nid_list); + nm_i->fcnt++; + spin_unlock(&nm_i->free_nid_list_lock); + return 1; +} + +static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid) +{ + struct free_nid *i; + spin_lock(&nm_i->free_nid_list_lock); + i = __lookup_free_nid_list(nid, &nm_i->free_nid_list); + if (i && i->state == NID_NEW) { + __del_from_free_nid_list(i); + nm_i->fcnt--; + } + spin_unlock(&nm_i->free_nid_list_lock); +} + +static int scan_nat_page(struct f2fs_nm_info *nm_i, + struct page *nat_page, nid_t start_nid) +{ + struct f2fs_nat_block *nat_blk = page_address(nat_page); + block_t blk_addr; + int fcnt = 0; + int i; + + /* 0 nid should not be used */ + if (start_nid == 0) + ++start_nid; + + i = start_nid % NAT_ENTRY_PER_BLOCK; + + for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) { + blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr); + BUG_ON(blk_addr == NEW_ADDR); + if (blk_addr == NULL_ADDR) + fcnt += add_free_nid(nm_i, start_nid); + } + return fcnt; +} + +static void build_free_nids(struct f2fs_sb_info *sbi) +{ + struct free_nid *fnid, *next_fnid; + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_summary_block *sum = curseg->sum_blk; + nid_t nid = 0; + bool is_cycled = false; + int fcnt = 0; + int i; + + nid = nm_i->next_scan_nid; + nm_i->init_scan_nid = nid; + + ra_nat_pages(sbi, nid); + + while (1) { + struct page *page = get_current_nat_page(sbi, nid); + + fcnt += scan_nat_page(nm_i, page, nid); + f2fs_put_page(page, 1); + + nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK)); + + if (nid >= nm_i->max_nid) { + nid = 0; + is_cycled = true; + } + if (fcnt > MAX_FREE_NIDS) + break; + if (is_cycled && nm_i->init_scan_nid <= nid) + break; + } + + nm_i->next_scan_nid = nid; + + /* find free nids from current sum_pages */ + mutex_lock(&curseg->curseg_mutex); + for (i = 0; i < nats_in_cursum(sum); i++) { + block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr); + nid = le32_to_cpu(nid_in_journal(sum, i)); + if (addr == NULL_ADDR) + add_free_nid(nm_i, nid); + else + remove_free_nid(nm_i, nid); + } + mutex_unlock(&curseg->curseg_mutex); + + /* remove the free nids from current allocated nids */ + list_for_each_entry_safe(fnid, next_fnid, &nm_i->free_nid_list, list) { + struct nat_entry *ne; + + read_lock(&nm_i->nat_tree_lock); + ne = __lookup_nat_cache(nm_i, fnid->nid); + if (ne && nat_get_blkaddr(ne) != NULL_ADDR) + remove_free_nid(nm_i, fnid->nid); + read_unlock(&nm_i->nat_tree_lock); + } +} + +/* + * If this function returns success, caller can obtain a new nid + * from second parameter of this function. + * The returned nid could be used ino as well as nid when inode is created. + */ +bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct free_nid *i = NULL; + struct list_head *this; +retry: + mutex_lock(&nm_i->build_lock); + if (!nm_i->fcnt) { + /* scan NAT in order to build free nid list */ + build_free_nids(sbi); + if (!nm_i->fcnt) { + mutex_unlock(&nm_i->build_lock); + return false; + } + } + mutex_unlock(&nm_i->build_lock); + + /* + * We check fcnt again since previous check is racy as + * we didn't hold free_nid_list_lock. So other thread + * could consume all of free nids. + */ + spin_lock(&nm_i->free_nid_list_lock); + if (!nm_i->fcnt) { + spin_unlock(&nm_i->free_nid_list_lock); + goto retry; + } + + BUG_ON(list_empty(&nm_i->free_nid_list)); + list_for_each(this, &nm_i->free_nid_list) { + i = list_entry(this, struct free_nid, list); + if (i->state == NID_NEW) + break; + } + + BUG_ON(i->state != NID_NEW); + *nid = i->nid; + i->state = NID_ALLOC; + nm_i->fcnt--; + spin_unlock(&nm_i->free_nid_list_lock); + return true; +} + +/** + * alloc_nid() should be called prior to this function. + */ +void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct free_nid *i; + + spin_lock(&nm_i->free_nid_list_lock); + i = __lookup_free_nid_list(nid, &nm_i->free_nid_list); + if (i) { + BUG_ON(i->state != NID_ALLOC); + __del_from_free_nid_list(i); + } + spin_unlock(&nm_i->free_nid_list_lock); +} + +/** + * alloc_nid() should be called prior to this function. + */ +void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid) +{ + alloc_nid_done(sbi, nid); + add_free_nid(NM_I(sbi), nid); +} + +void recover_node_page(struct f2fs_sb_info *sbi, struct page *page, + struct f2fs_summary *sum, struct node_info *ni, + block_t new_blkaddr) +{ + rewrite_node_page(sbi, page, sum, ni->blk_addr, new_blkaddr); + set_node_addr(sbi, ni, new_blkaddr); + clear_node_page_dirty(page); +} + +int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) +{ + struct address_space *mapping = sbi->node_inode->i_mapping; + struct f2fs_node *src, *dst; + nid_t ino = ino_of_node(page); + struct node_info old_ni, new_ni; + struct page *ipage; + + ipage = grab_cache_page(mapping, ino); + if (!ipage) + return -ENOMEM; + + /* Should not use this inode from free nid list */ + remove_free_nid(NM_I(sbi), ino); + + get_node_info(sbi, ino, &old_ni); + SetPageUptodate(ipage); + fill_node_footer(ipage, ino, ino, 0, true); + + src = (struct f2fs_node *)page_address(page); + dst = (struct f2fs_node *)page_address(ipage); + + memcpy(dst, src, (unsigned long)&src->i.i_ext - (unsigned long)&src->i); + dst->i.i_size = 0; + dst->i.i_blocks = 1; + dst->i.i_links = 1; + dst->i.i_xattr_nid = 0; + + new_ni = old_ni; + new_ni.ino = ino; + + set_node_addr(sbi, &new_ni, NEW_ADDR); + inc_valid_inode_count(sbi); + + f2fs_put_page(ipage, 1); + return 0; +} + +int restore_node_summary(struct f2fs_sb_info *sbi, + unsigned int segno, struct f2fs_summary_block *sum) +{ + struct f2fs_node *rn; + struct f2fs_summary *sum_entry; + struct page *page; + block_t addr; + int i, last_offset; + + /* alloc temporal page for read node */ + page = alloc_page(GFP_NOFS | __GFP_ZERO); + if (IS_ERR(page)) + return PTR_ERR(page); + lock_page(page); + + /* scan the node segment */ + last_offset = sbi->blocks_per_seg; + addr = START_BLOCK(sbi, segno); + sum_entry = &sum->entries[0]; + + for (i = 0; i < last_offset; i++, sum_entry++) { + if (f2fs_readpage(sbi, page, addr, READ_SYNC)) + goto out; + + rn = (struct f2fs_node *)page_address(page); + sum_entry->nid = rn->footer.nid; + sum_entry->version = 0; + sum_entry->ofs_in_node = 0; + addr++; + + /* + * In order to read next node page, + * we must clear PageUptodate flag. + */ + ClearPageUptodate(page); + } +out: + unlock_page(page); + __free_pages(page, 0); + return 0; +} + +static bool flush_nats_in_journal(struct f2fs_sb_info *sbi) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_summary_block *sum = curseg->sum_blk; + int i; + + mutex_lock(&curseg->curseg_mutex); + + if (nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES) { + mutex_unlock(&curseg->curseg_mutex); + return false; + } + + for (i = 0; i < nats_in_cursum(sum); i++) { + struct nat_entry *ne; + struct f2fs_nat_entry raw_ne; + nid_t nid = le32_to_cpu(nid_in_journal(sum, i)); + + raw_ne = nat_in_journal(sum, i); +retry: + write_lock(&nm_i->nat_tree_lock); + ne = __lookup_nat_cache(nm_i, nid); + if (ne) { + __set_nat_cache_dirty(nm_i, ne); + write_unlock(&nm_i->nat_tree_lock); + continue; + } + ne = grab_nat_entry(nm_i, nid); + if (!ne) { + write_unlock(&nm_i->nat_tree_lock); + goto retry; + } + nat_set_blkaddr(ne, le32_to_cpu(raw_ne.block_addr)); + nat_set_ino(ne, le32_to_cpu(raw_ne.ino)); + nat_set_version(ne, raw_ne.version); + __set_nat_cache_dirty(nm_i, ne); + write_unlock(&nm_i->nat_tree_lock); + } + update_nats_in_cursum(sum, -i); + mutex_unlock(&curseg->curseg_mutex); + return true; +} + +/** + * This function is called during the checkpointing process. + */ +void flush_nat_entries(struct f2fs_sb_info *sbi) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_summary_block *sum = curseg->sum_blk; + struct list_head *cur, *n; + struct page *page = NULL; + struct f2fs_nat_block *nat_blk = NULL; + nid_t start_nid = 0, end_nid = 0; + bool flushed; + + flushed = flush_nats_in_journal(sbi); + + if (!flushed) + mutex_lock(&curseg->curseg_mutex); + + /* 1) flush dirty nat caches */ + list_for_each_safe(cur, n, &nm_i->dirty_nat_entries) { + struct nat_entry *ne; + nid_t nid; + struct f2fs_nat_entry raw_ne; + int offset = -1; + block_t old_blkaddr, new_blkaddr; + + ne = list_entry(cur, struct nat_entry, list); + nid = nat_get_nid(ne); + + if (nat_get_blkaddr(ne) == NEW_ADDR) + continue; + if (flushed) + goto to_nat_page; + + /* if there is room for nat enries in curseg->sumpage */ + offset = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 1); + if (offset >= 0) { + raw_ne = nat_in_journal(sum, offset); + old_blkaddr = le32_to_cpu(raw_ne.block_addr); + goto flush_now; + } +to_nat_page: + if (!page || (start_nid > nid || nid > end_nid)) { + if (page) { + f2fs_put_page(page, 1); + page = NULL; + } + start_nid = START_NID(nid); + end_nid = start_nid + NAT_ENTRY_PER_BLOCK - 1; + + /* + * get nat block with dirty flag, increased reference + * count, mapped and lock + */ + page = get_next_nat_page(sbi, start_nid); + nat_blk = page_address(page); + } + + BUG_ON(!nat_blk); + raw_ne = nat_blk->entries[nid - start_nid]; + old_blkaddr = le32_to_cpu(raw_ne.block_addr); +flush_now: + new_blkaddr = nat_get_blkaddr(ne); + + raw_ne.ino = cpu_to_le32(nat_get_ino(ne)); + raw_ne.block_addr = cpu_to_le32(new_blkaddr); + raw_ne.version = nat_get_version(ne); + + if (offset < 0) { + nat_blk->entries[nid - start_nid] = raw_ne; + } else { + nat_in_journal(sum, offset) = raw_ne; + nid_in_journal(sum, offset) = cpu_to_le32(nid); + } + + if (nat_get_blkaddr(ne) == NULL_ADDR) { + write_lock(&nm_i->nat_tree_lock); + __del_from_nat_cache(nm_i, ne); + write_unlock(&nm_i->nat_tree_lock); + + /* We can reuse this freed nid at this point */ + add_free_nid(NM_I(sbi), nid); + } else { + write_lock(&nm_i->nat_tree_lock); + __clear_nat_cache_dirty(nm_i, ne); + ne->checkpointed = true; + write_unlock(&nm_i->nat_tree_lock); + } + } + if (!flushed) + mutex_unlock(&curseg->curseg_mutex); + f2fs_put_page(page, 1); + + /* 2) shrink nat caches if necessary */ + try_to_free_nats(sbi, nm_i->nat_cnt - NM_WOUT_THRESHOLD); +} + +static int init_node_manager(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb_raw = F2FS_RAW_SUPER(sbi); + struct f2fs_nm_info *nm_i = NM_I(sbi); + unsigned char *version_bitmap; + unsigned int nat_segs, nat_blocks; + + nm_i->nat_blkaddr = le32_to_cpu(sb_raw->nat_blkaddr); + + /* segment_count_nat includes pair segment so divide to 2. */ + nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1; + nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg); + nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks; + nm_i->fcnt = 0; + nm_i->nat_cnt = 0; + + INIT_LIST_HEAD(&nm_i->free_nid_list); + INIT_RADIX_TREE(&nm_i->nat_root, GFP_ATOMIC); + INIT_LIST_HEAD(&nm_i->nat_entries); + INIT_LIST_HEAD(&nm_i->dirty_nat_entries); + + mutex_init(&nm_i->build_lock); + spin_lock_init(&nm_i->free_nid_list_lock); + rwlock_init(&nm_i->nat_tree_lock); + + nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP); + nm_i->init_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid); + nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid); + + nm_i->nat_bitmap = kzalloc(nm_i->bitmap_size, GFP_KERNEL); + if (!nm_i->nat_bitmap) + return -ENOMEM; + version_bitmap = __bitmap_ptr(sbi, NAT_BITMAP); + if (!version_bitmap) + return -EFAULT; + + /* copy version bitmap */ + memcpy(nm_i->nat_bitmap, version_bitmap, nm_i->bitmap_size); + return 0; +} + +int build_node_manager(struct f2fs_sb_info *sbi) +{ + int err; + + sbi->nm_info = kzalloc(sizeof(struct f2fs_nm_info), GFP_KERNEL); + if (!sbi->nm_info) + return -ENOMEM; + + err = init_node_manager(sbi); + if (err) + return err; + + build_free_nids(sbi); + return 0; +} + +void destroy_node_manager(struct f2fs_sb_info *sbi) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct free_nid *i, *next_i; + struct nat_entry *natvec[NATVEC_SIZE]; + nid_t nid = 0; + unsigned int found; + + if (!nm_i) + return; + + /* destroy free nid list */ + spin_lock(&nm_i->free_nid_list_lock); + list_for_each_entry_safe(i, next_i, &nm_i->free_nid_list, list) { + BUG_ON(i->state == NID_ALLOC); + __del_from_free_nid_list(i); + nm_i->fcnt--; + } + BUG_ON(nm_i->fcnt); + spin_unlock(&nm_i->free_nid_list_lock); + + /* destroy nat cache */ + write_lock(&nm_i->nat_tree_lock); + while ((found = __gang_lookup_nat_cache(nm_i, + nid, NATVEC_SIZE, natvec))) { + unsigned idx; + for (idx = 0; idx < found; idx++) { + struct nat_entry *e = natvec[idx]; + nid = nat_get_nid(e) + 1; + __del_from_nat_cache(nm_i, e); + } + } + BUG_ON(nm_i->nat_cnt); + write_unlock(&nm_i->nat_tree_lock); + + kfree(nm_i->nat_bitmap); + sbi->nm_info = NULL; + kfree(nm_i); +} + +int create_node_manager_caches(void) +{ + nat_entry_slab = f2fs_kmem_cache_create("nat_entry", + sizeof(struct nat_entry), NULL); + if (!nat_entry_slab) + return -ENOMEM; + + free_nid_slab = f2fs_kmem_cache_create("free_nid", + sizeof(struct free_nid), NULL); + if (!free_nid_slab) { + kmem_cache_destroy(nat_entry_slab); + return -ENOMEM; + } + return 0; +} + +void destroy_node_manager_caches(void) +{ + kmem_cache_destroy(free_nid_slab); + kmem_cache_destroy(nat_entry_slab); +} -- cgit v0.10.2 From 351df4b201157351c7d26bf12c3eeb9dbce98854 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:09:16 +0900 Subject: f2fs: add segment operations This adds specific functions not only to manage dirty/free segments, SIT pages, a cache for SIT entries, and summary entries, but also to allocate free blocks and write three types of pages: data, node, and meta. - F2FS maintains three types of bitmaps in memory, which indicate free, prefree, and dirty segments respectively. - The key information of an SIT entry consists of a segment number, the number of valid blocks in the segment, a bitmap to identify there-in valid or invalid blocks. - An SIT page is composed of a certain range of SIT entries, which is maintained by the address space of meta_inode. - To cache SIT entries, a simple array is used. The index for the array is the segment number. - A summary entry for data contains the parent node information. A summary entry for node contains its node offset from the inode. - F2FS manages information about six active logs and those summary entries in memory. Whenever one of them is changed, its summary entries are flushed to its SIT page maintained by the address space of meta_inode. - This patch adds a default block allocation function which supports heap-based allocation policy. - This patch adds core functions to write data, node, and meta pages. Since LFS basically produces a series of sequential writes, F2FS merges sequential bios with a single one as much as possible to reduce the IO scheduling overhead. Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c new file mode 100644 index 0000000..ed7c079 --- /dev/null +++ b/fs/f2fs/segment.c @@ -0,0 +1,1798 @@ +/** + * fs/f2fs/segment.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "segment.h" +#include "node.h" + +static int need_to_flush(struct f2fs_sb_info *sbi) +{ + unsigned int pages_per_sec = (1 << sbi->log_blocks_per_seg) * + sbi->segs_per_sec; + int node_secs = ((get_pages(sbi, F2FS_DIRTY_NODES) + pages_per_sec - 1) + >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; + int dent_secs = ((get_pages(sbi, F2FS_DIRTY_DENTS) + pages_per_sec - 1) + >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; + + if (sbi->por_doing) + return 0; + + if (free_sections(sbi) <= (node_secs + 2 * dent_secs + + reserved_sections(sbi))) + return 1; + return 0; +} + +/** + * This function balances dirty node and dentry pages. + * In addition, it controls garbage collection. + */ +void f2fs_balance_fs(struct f2fs_sb_info *sbi) +{ + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .for_reclaim = 0, + }; + + if (sbi->por_doing) + return; + + /* + * We should do checkpoint when there are so many dirty node pages + * with enough free segments. After then, we should do GC. + */ + if (need_to_flush(sbi)) { + sync_dirty_dir_inodes(sbi); + sync_node_pages(sbi, 0, &wbc); + } + + if (has_not_enough_free_secs(sbi)) { + mutex_lock(&sbi->gc_mutex); + f2fs_gc(sbi, 1); + } +} + +static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, + enum dirty_type dirty_type) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + + /* need not be added */ + if (IS_CURSEG(sbi, segno)) + return; + + if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type])) + dirty_i->nr_dirty[dirty_type]++; + + if (dirty_type == DIRTY) { + struct seg_entry *sentry = get_seg_entry(sbi, segno); + dirty_type = sentry->type; + if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type])) + dirty_i->nr_dirty[dirty_type]++; + } +} + +static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, + enum dirty_type dirty_type) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + + if (test_and_clear_bit(segno, dirty_i->dirty_segmap[dirty_type])) + dirty_i->nr_dirty[dirty_type]--; + + if (dirty_type == DIRTY) { + struct seg_entry *sentry = get_seg_entry(sbi, segno); + dirty_type = sentry->type; + if (test_and_clear_bit(segno, + dirty_i->dirty_segmap[dirty_type])) + dirty_i->nr_dirty[dirty_type]--; + clear_bit(segno, dirty_i->victim_segmap[FG_GC]); + clear_bit(segno, dirty_i->victim_segmap[BG_GC]); + } +} + +/** + * Should not occur error such as -ENOMEM. + * Adding dirty entry into seglist is not critical operation. + * If a given segment is one of current working segments, it won't be added. + */ +void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + unsigned short valid_blocks; + + if (segno == NULL_SEGNO || IS_CURSEG(sbi, segno)) + return; + + mutex_lock(&dirty_i->seglist_lock); + + valid_blocks = get_valid_blocks(sbi, segno, 0); + + if (valid_blocks == 0) { + __locate_dirty_segment(sbi, segno, PRE); + __remove_dirty_segment(sbi, segno, DIRTY); + } else if (valid_blocks < sbi->blocks_per_seg) { + __locate_dirty_segment(sbi, segno, DIRTY); + } else { + /* Recovery routine with SSR needs this */ + __remove_dirty_segment(sbi, segno, DIRTY); + } + + mutex_unlock(&dirty_i->seglist_lock); + return; +} + +/** + * Should call clear_prefree_segments after checkpoint is done. + */ +static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + unsigned int segno, offset = 0; + unsigned int total_segs = TOTAL_SEGS(sbi); + + mutex_lock(&dirty_i->seglist_lock); + while (1) { + segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, + offset); + if (segno >= total_segs) + break; + __set_test_and_free(sbi, segno); + offset = segno + 1; + } + mutex_unlock(&dirty_i->seglist_lock); +} + +void clear_prefree_segments(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + unsigned int segno, offset = 0; + unsigned int total_segs = TOTAL_SEGS(sbi); + + mutex_lock(&dirty_i->seglist_lock); + while (1) { + segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs, + offset); + if (segno >= total_segs) + break; + + offset = segno + 1; + if (test_and_clear_bit(segno, dirty_i->dirty_segmap[PRE])) + dirty_i->nr_dirty[PRE]--; + + /* Let's use trim */ + if (test_opt(sbi, DISCARD)) + blkdev_issue_discard(sbi->sb->s_bdev, + START_BLOCK(sbi, segno) << + sbi->log_sectors_per_block, + 1 << (sbi->log_sectors_per_block + + sbi->log_blocks_per_seg), + GFP_NOFS, 0); + } + mutex_unlock(&dirty_i->seglist_lock); +} + +static void __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno) +{ + struct sit_info *sit_i = SIT_I(sbi); + if (!__test_and_set_bit(segno, sit_i->dirty_sentries_bitmap)) + sit_i->dirty_sentries++; +} + +static void __set_sit_entry_type(struct f2fs_sb_info *sbi, int type, + unsigned int segno, int modified) +{ + struct seg_entry *se = get_seg_entry(sbi, segno); + se->type = type; + if (modified) + __mark_sit_entry_dirty(sbi, segno); +} + +static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) +{ + struct seg_entry *se; + unsigned int segno, offset; + long int new_vblocks; + + segno = GET_SEGNO(sbi, blkaddr); + + se = get_seg_entry(sbi, segno); + new_vblocks = se->valid_blocks + del; + offset = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & (sbi->blocks_per_seg - 1); + + BUG_ON((new_vblocks >> (sizeof(unsigned short) << 3) || + (new_vblocks > sbi->blocks_per_seg))); + + se->valid_blocks = new_vblocks; + se->mtime = get_mtime(sbi); + SIT_I(sbi)->max_mtime = se->mtime; + + /* Update valid block bitmap */ + if (del > 0) { + if (f2fs_set_bit(offset, se->cur_valid_map)) + BUG(); + } else { + if (!f2fs_clear_bit(offset, se->cur_valid_map)) + BUG(); + } + if (!f2fs_test_bit(offset, se->ckpt_valid_map)) + se->ckpt_valid_blocks += del; + + __mark_sit_entry_dirty(sbi, segno); + + /* update total number of valid blocks to be written in ckpt area */ + SIT_I(sbi)->written_valid_blocks += del; + + if (sbi->segs_per_sec > 1) + get_sec_entry(sbi, segno)->valid_blocks += del; +} + +static void refresh_sit_entry(struct f2fs_sb_info *sbi, + block_t old_blkaddr, block_t new_blkaddr) +{ + update_sit_entry(sbi, new_blkaddr, 1); + if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) + update_sit_entry(sbi, old_blkaddr, -1); +} + +void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) +{ + unsigned int segno = GET_SEGNO(sbi, addr); + struct sit_info *sit_i = SIT_I(sbi); + + BUG_ON(addr == NULL_ADDR); + if (addr == NEW_ADDR) + return; + + /* add it into sit main buffer */ + mutex_lock(&sit_i->sentry_lock); + + update_sit_entry(sbi, addr, -1); + + /* add it into dirty seglist */ + locate_dirty_segment(sbi, segno); + + mutex_unlock(&sit_i->sentry_lock); +} + +/** + * This function should be resided under the curseg_mutex lock + */ +static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, + struct f2fs_summary *sum, unsigned short offset) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + void *addr = curseg->sum_blk; + addr += offset * sizeof(struct f2fs_summary); + memcpy(addr, sum, sizeof(struct f2fs_summary)); + return; +} + +/** + * Calculate the number of current summary pages for writing + */ +int npages_for_summary_flush(struct f2fs_sb_info *sbi) +{ + int total_size_bytes = 0; + int valid_sum_count = 0; + int i, sum_space; + + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { + if (sbi->ckpt->alloc_type[i] == SSR) + valid_sum_count += sbi->blocks_per_seg; + else + valid_sum_count += curseg_blkoff(sbi, i); + } + + total_size_bytes = valid_sum_count * (SUMMARY_SIZE + 1) + + sizeof(struct nat_journal) + 2 + + sizeof(struct sit_journal) + 2; + sum_space = PAGE_CACHE_SIZE - SUM_FOOTER_SIZE; + if (total_size_bytes < sum_space) + return 1; + else if (total_size_bytes < 2 * sum_space) + return 2; + return 3; +} + +/** + * Caller should put this summary page + */ +struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno) +{ + return get_meta_page(sbi, GET_SUM_BLOCK(sbi, segno)); +} + +static void write_sum_page(struct f2fs_sb_info *sbi, + struct f2fs_summary_block *sum_blk, block_t blk_addr) +{ + struct page *page = grab_meta_page(sbi, blk_addr); + void *kaddr = page_address(page); + memcpy(kaddr, sum_blk, PAGE_CACHE_SIZE); + set_page_dirty(page); + f2fs_put_page(page, 1); +} + +static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi, + int ofs_unit, int type) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + unsigned long *prefree_segmap = dirty_i->dirty_segmap[PRE]; + unsigned int segno, next_segno, i; + int ofs = 0; + + /* + * If there is not enough reserved sections, + * we should not reuse prefree segments. + */ + if (has_not_enough_free_secs(sbi)) + return NULL_SEGNO; + + /* + * NODE page should not reuse prefree segment, + * since those information is used for SPOR. + */ + if (IS_NODESEG(type)) + return NULL_SEGNO; +next: + segno = find_next_bit(prefree_segmap, TOTAL_SEGS(sbi), ofs++); + ofs = ((segno / ofs_unit) * ofs_unit) + ofs_unit; + if (segno < TOTAL_SEGS(sbi)) { + /* skip intermediate segments in a section */ + if (segno % ofs_unit) + goto next; + + /* skip if whole section is not prefree */ + next_segno = find_next_zero_bit(prefree_segmap, + TOTAL_SEGS(sbi), segno + 1); + if (next_segno - segno < ofs_unit) + goto next; + + /* skip if whole section was not free at the last checkpoint */ + for (i = 0; i < ofs_unit; i++) + if (get_seg_entry(sbi, segno)->ckpt_valid_blocks) + goto next; + return segno; + } + return NULL_SEGNO; +} + +/** + * Find a new segment from the free segments bitmap to right order + * This function should be returned with success, otherwise BUG + */ +static void get_new_segment(struct f2fs_sb_info *sbi, + unsigned int *newseg, bool new_sec, int dir) +{ + struct free_segmap_info *free_i = FREE_I(sbi); + unsigned int total_secs = sbi->total_sections; + unsigned int segno, secno, zoneno; + unsigned int total_zones = sbi->total_sections / sbi->secs_per_zone; + unsigned int hint = *newseg / sbi->segs_per_sec; + unsigned int old_zoneno = GET_ZONENO_FROM_SEGNO(sbi, *newseg); + unsigned int left_start = hint; + bool init = true; + int go_left = 0; + int i; + + write_lock(&free_i->segmap_lock); + + if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { + segno = find_next_zero_bit(free_i->free_segmap, + TOTAL_SEGS(sbi), *newseg + 1); + if (segno < TOTAL_SEGS(sbi)) + goto got_it; + } +find_other_zone: + secno = find_next_zero_bit(free_i->free_secmap, total_secs, hint); + if (secno >= total_secs) { + if (dir == ALLOC_RIGHT) { + secno = find_next_zero_bit(free_i->free_secmap, + total_secs, 0); + BUG_ON(secno >= total_secs); + } else { + go_left = 1; + left_start = hint - 1; + } + } + if (go_left == 0) + goto skip_left; + + while (test_bit(left_start, free_i->free_secmap)) { + if (left_start > 0) { + left_start--; + continue; + } + left_start = find_next_zero_bit(free_i->free_secmap, + total_secs, 0); + BUG_ON(left_start >= total_secs); + break; + } + secno = left_start; +skip_left: + hint = secno; + segno = secno * sbi->segs_per_sec; + zoneno = secno / sbi->secs_per_zone; + + /* give up on finding another zone */ + if (!init) + goto got_it; + if (sbi->secs_per_zone == 1) + goto got_it; + if (zoneno == old_zoneno) + goto got_it; + if (dir == ALLOC_LEFT) { + if (!go_left && zoneno + 1 >= total_zones) + goto got_it; + if (go_left && zoneno == 0) + goto got_it; + } + for (i = 0; i < NR_CURSEG_TYPE; i++) + if (CURSEG_I(sbi, i)->zone == zoneno) + break; + + if (i < NR_CURSEG_TYPE) { + /* zone is in user, try another */ + if (go_left) + hint = zoneno * sbi->secs_per_zone - 1; + else if (zoneno + 1 >= total_zones) + hint = 0; + else + hint = (zoneno + 1) * sbi->secs_per_zone; + init = false; + goto find_other_zone; + } +got_it: + /* set it as dirty segment in free segmap */ + BUG_ON(test_bit(segno, free_i->free_segmap)); + __set_inuse(sbi, segno); + *newseg = segno; + write_unlock(&free_i->segmap_lock); +} + +static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + struct summary_footer *sum_footer; + + curseg->segno = curseg->next_segno; + curseg->zone = GET_ZONENO_FROM_SEGNO(sbi, curseg->segno); + curseg->next_blkoff = 0; + curseg->next_segno = NULL_SEGNO; + + sum_footer = &(curseg->sum_blk->footer); + memset(sum_footer, 0, sizeof(struct summary_footer)); + if (IS_DATASEG(type)) + SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA); + if (IS_NODESEG(type)) + SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE); + __set_sit_entry_type(sbi, type, curseg->segno, modified); +} + +/** + * Allocate a current working segment. + * This function always allocates a free segment in LFS manner. + */ +static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + unsigned int segno = curseg->segno; + int dir = ALLOC_LEFT; + + write_sum_page(sbi, curseg->sum_blk, + GET_SUM_BLOCK(sbi, curseg->segno)); + if (type == CURSEG_WARM_DATA || type == CURSEG_COLD_DATA) + dir = ALLOC_RIGHT; + + if (test_opt(sbi, NOHEAP)) + dir = ALLOC_RIGHT; + + get_new_segment(sbi, &segno, new_sec, dir); + curseg->next_segno = segno; + reset_curseg(sbi, type, 1); + curseg->alloc_type = LFS; +} + +static void __next_free_blkoff(struct f2fs_sb_info *sbi, + struct curseg_info *seg, block_t start) +{ + struct seg_entry *se = get_seg_entry(sbi, seg->segno); + block_t ofs; + for (ofs = start; ofs < sbi->blocks_per_seg; ofs++) { + if (!f2fs_test_bit(ofs, se->ckpt_valid_map) + && !f2fs_test_bit(ofs, se->cur_valid_map)) + break; + } + seg->next_blkoff = ofs; +} + +/** + * If a segment is written by LFS manner, next block offset is just obtained + * by increasing the current block offset. However, if a segment is written by + * SSR manner, next block offset obtained by calling __next_free_blkoff + */ +static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, + struct curseg_info *seg) +{ + if (seg->alloc_type == SSR) + __next_free_blkoff(sbi, seg, seg->next_blkoff + 1); + else + seg->next_blkoff++; +} + +/** + * This function always allocates a used segment (from dirty seglist) by SSR + * manner, so it should recover the existing segment information of valid blocks + */ +static void change_curseg(struct f2fs_sb_info *sbi, int type, bool reuse) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, type); + unsigned int new_segno = curseg->next_segno; + struct f2fs_summary_block *sum_node; + struct page *sum_page; + + write_sum_page(sbi, curseg->sum_blk, + GET_SUM_BLOCK(sbi, curseg->segno)); + __set_test_and_inuse(sbi, new_segno); + + mutex_lock(&dirty_i->seglist_lock); + __remove_dirty_segment(sbi, new_segno, PRE); + __remove_dirty_segment(sbi, new_segno, DIRTY); + mutex_unlock(&dirty_i->seglist_lock); + + reset_curseg(sbi, type, 1); + curseg->alloc_type = SSR; + __next_free_blkoff(sbi, curseg, 0); + + if (reuse) { + sum_page = get_sum_page(sbi, new_segno); + sum_node = (struct f2fs_summary_block *)page_address(sum_page); + memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); + f2fs_put_page(sum_page, 1); + } +} + +/* + * flush out current segment and replace it with new segment + * This function should be returned with success, otherwise BUG + */ +static void allocate_segment_by_default(struct f2fs_sb_info *sbi, + int type, bool force) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + unsigned int ofs_unit; + + if (force) { + new_curseg(sbi, type, true); + goto out; + } + + ofs_unit = need_SSR(sbi) ? 1 : sbi->segs_per_sec; + curseg->next_segno = check_prefree_segments(sbi, ofs_unit, type); + + if (curseg->next_segno != NULL_SEGNO) + change_curseg(sbi, type, false); + else if (type == CURSEG_WARM_NODE) + new_curseg(sbi, type, false); + else if (need_SSR(sbi) && get_ssr_segment(sbi, type)) + change_curseg(sbi, type, true); + else + new_curseg(sbi, type, false); +out: + sbi->segment_count[curseg->alloc_type]++; +} + +void allocate_new_segments(struct f2fs_sb_info *sbi) +{ + struct curseg_info *curseg; + unsigned int old_curseg; + int i; + + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { + curseg = CURSEG_I(sbi, i); + old_curseg = curseg->segno; + SIT_I(sbi)->s_ops->allocate_segment(sbi, i, true); + locate_dirty_segment(sbi, old_curseg); + } +} + +static const struct segment_allocation default_salloc_ops = { + .allocate_segment = allocate_segment_by_default, +}; + +static void f2fs_end_io_write(struct bio *bio, int err) +{ + const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + struct bio_private *p = bio->bi_private; + + do { + struct page *page = bvec->bv_page; + + if (--bvec >= bio->bi_io_vec) + prefetchw(&bvec->bv_page->flags); + if (!uptodate) { + SetPageError(page); + if (page->mapping) + set_bit(AS_EIO, &page->mapping->flags); + p->sbi->ckpt->ckpt_flags |= CP_ERROR_FLAG; + set_page_dirty(page); + } + end_page_writeback(page); + dec_page_count(p->sbi, F2FS_WRITEBACK); + } while (bvec >= bio->bi_io_vec); + + if (p->is_sync) + complete(p->wait); + kfree(p); + bio_put(bio); +} + +struct bio *f2fs_bio_alloc(struct block_device *bdev, sector_t first_sector, + int nr_vecs, gfp_t gfp_flags) +{ + struct bio *bio; +repeat: + /* allocate new bio */ + bio = bio_alloc(gfp_flags, nr_vecs); + + if (bio == NULL && (current->flags & PF_MEMALLOC)) { + while (!bio && (nr_vecs /= 2)) + bio = bio_alloc(gfp_flags, nr_vecs); + } + if (bio) { + bio->bi_bdev = bdev; + bio->bi_sector = first_sector; +retry: + bio->bi_private = kmalloc(sizeof(struct bio_private), + GFP_NOFS | __GFP_HIGH); + if (!bio->bi_private) { + cond_resched(); + goto retry; + } + } + if (bio == NULL) { + cond_resched(); + goto repeat; + } + return bio; +} + +static void do_submit_bio(struct f2fs_sb_info *sbi, + enum page_type type, bool sync) +{ + int rw = sync ? WRITE_SYNC : WRITE; + enum page_type btype = type > META ? META : type; + + if (type >= META_FLUSH) + rw = WRITE_FLUSH_FUA; + + if (sbi->bio[btype]) { + struct bio_private *p = sbi->bio[btype]->bi_private; + p->sbi = sbi; + sbi->bio[btype]->bi_end_io = f2fs_end_io_write; + if (type == META_FLUSH) { + DECLARE_COMPLETION_ONSTACK(wait); + p->is_sync = true; + p->wait = &wait; + submit_bio(rw, sbi->bio[btype]); + wait_for_completion(&wait); + } else { + p->is_sync = false; + submit_bio(rw, sbi->bio[btype]); + } + sbi->bio[btype] = NULL; + } +} + +void f2fs_submit_bio(struct f2fs_sb_info *sbi, enum page_type type, bool sync) +{ + down_write(&sbi->bio_sem); + do_submit_bio(sbi, type, sync); + up_write(&sbi->bio_sem); +} + +static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page, + block_t blk_addr, enum page_type type) +{ + struct block_device *bdev = sbi->sb->s_bdev; + + verify_block_addr(sbi, blk_addr); + + down_write(&sbi->bio_sem); + + inc_page_count(sbi, F2FS_WRITEBACK); + + if (sbi->bio[type] && sbi->last_block_in_bio[type] != blk_addr - 1) + do_submit_bio(sbi, type, false); +alloc_new: + if (sbi->bio[type] == NULL) + sbi->bio[type] = f2fs_bio_alloc(bdev, + blk_addr << (sbi->log_blocksize - 9), + bio_get_nr_vecs(bdev), GFP_NOFS | __GFP_HIGH); + + if (bio_add_page(sbi->bio[type], page, PAGE_CACHE_SIZE, 0) < + PAGE_CACHE_SIZE) { + do_submit_bio(sbi, type, false); + goto alloc_new; + } + + sbi->last_block_in_bio[type] = blk_addr; + + up_write(&sbi->bio_sem); +} + +static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + if (curseg->next_blkoff < sbi->blocks_per_seg) + return true; + return false; +} + +static int __get_segment_type_2(struct page *page, enum page_type p_type) +{ + if (p_type == DATA) + return CURSEG_HOT_DATA; + else + return CURSEG_HOT_NODE; +} + +static int __get_segment_type_4(struct page *page, enum page_type p_type) +{ + if (p_type == DATA) { + struct inode *inode = page->mapping->host; + + if (S_ISDIR(inode->i_mode)) + return CURSEG_HOT_DATA; + else + return CURSEG_COLD_DATA; + } else { + if (IS_DNODE(page) && !is_cold_node(page)) + return CURSEG_HOT_NODE; + else + return CURSEG_COLD_NODE; + } +} + +static int __get_segment_type_6(struct page *page, enum page_type p_type) +{ + if (p_type == DATA) { + struct inode *inode = page->mapping->host; + + if (S_ISDIR(inode->i_mode)) + return CURSEG_HOT_DATA; + else if (is_cold_data(page) || is_cold_file(inode)) + return CURSEG_COLD_DATA; + else + return CURSEG_WARM_DATA; + } else { + if (IS_DNODE(page)) + return is_cold_node(page) ? CURSEG_WARM_NODE : + CURSEG_HOT_NODE; + else + return CURSEG_COLD_NODE; + } +} + +static int __get_segment_type(struct page *page, enum page_type p_type) +{ + struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); + switch (sbi->active_logs) { + case 2: + return __get_segment_type_2(page, p_type); + case 4: + return __get_segment_type_4(page, p_type); + case 6: + return __get_segment_type_6(page, p_type); + default: + BUG(); + } +} + +static void do_write_page(struct f2fs_sb_info *sbi, struct page *page, + block_t old_blkaddr, block_t *new_blkaddr, + struct f2fs_summary *sum, enum page_type p_type) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct curseg_info *curseg; + unsigned int old_cursegno; + int type; + + type = __get_segment_type(page, p_type); + curseg = CURSEG_I(sbi, type); + + mutex_lock(&curseg->curseg_mutex); + + *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); + old_cursegno = curseg->segno; + + /* + * __add_sum_entry should be resided under the curseg_mutex + * because, this function updates a summary entry in the + * current summary block. + */ + __add_sum_entry(sbi, type, sum, curseg->next_blkoff); + + mutex_lock(&sit_i->sentry_lock); + __refresh_next_blkoff(sbi, curseg); + sbi->block_count[curseg->alloc_type]++; + + /* + * SIT information should be updated before segment allocation, + * since SSR needs latest valid block information. + */ + refresh_sit_entry(sbi, old_blkaddr, *new_blkaddr); + + if (!__has_curseg_space(sbi, type)) + sit_i->s_ops->allocate_segment(sbi, type, false); + + locate_dirty_segment(sbi, old_cursegno); + locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); + mutex_unlock(&sit_i->sentry_lock); + + if (p_type == NODE) + fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg)); + + /* writeout dirty page into bdev */ + submit_write_page(sbi, page, *new_blkaddr, p_type); + + mutex_unlock(&curseg->curseg_mutex); +} + +int write_meta_page(struct f2fs_sb_info *sbi, struct page *page, + struct writeback_control *wbc) +{ + if (wbc->for_reclaim) + return AOP_WRITEPAGE_ACTIVATE; + + set_page_writeback(page); + submit_write_page(sbi, page, page->index, META); + return 0; +} + +void write_node_page(struct f2fs_sb_info *sbi, struct page *page, + unsigned int nid, block_t old_blkaddr, block_t *new_blkaddr) +{ + struct f2fs_summary sum; + set_summary(&sum, nid, 0, 0); + do_write_page(sbi, page, old_blkaddr, new_blkaddr, &sum, NODE); +} + +void write_data_page(struct inode *inode, struct page *page, + struct dnode_of_data *dn, block_t old_blkaddr, + block_t *new_blkaddr) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_summary sum; + struct node_info ni; + + BUG_ON(old_blkaddr == NULL_ADDR); + get_node_info(sbi, dn->nid, &ni); + set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); + + do_write_page(sbi, page, old_blkaddr, + new_blkaddr, &sum, DATA); +} + +void rewrite_data_page(struct f2fs_sb_info *sbi, struct page *page, + block_t old_blk_addr) +{ + submit_write_page(sbi, page, old_blk_addr, DATA); +} + +void recover_data_page(struct f2fs_sb_info *sbi, + struct page *page, struct f2fs_summary *sum, + block_t old_blkaddr, block_t new_blkaddr) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct curseg_info *curseg; + unsigned int segno, old_cursegno; + struct seg_entry *se; + int type; + + segno = GET_SEGNO(sbi, new_blkaddr); + se = get_seg_entry(sbi, segno); + type = se->type; + + if (se->valid_blocks == 0 && !IS_CURSEG(sbi, segno)) { + if (old_blkaddr == NULL_ADDR) + type = CURSEG_COLD_DATA; + else + type = CURSEG_WARM_DATA; + } + curseg = CURSEG_I(sbi, type); + + mutex_lock(&curseg->curseg_mutex); + mutex_lock(&sit_i->sentry_lock); + + old_cursegno = curseg->segno; + + /* change the current segment */ + if (segno != curseg->segno) { + curseg->next_segno = segno; + change_curseg(sbi, type, true); + } + + curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) & + (sbi->blocks_per_seg - 1); + __add_sum_entry(sbi, type, sum, curseg->next_blkoff); + + refresh_sit_entry(sbi, old_blkaddr, new_blkaddr); + + locate_dirty_segment(sbi, old_cursegno); + locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); + + mutex_unlock(&sit_i->sentry_lock); + mutex_unlock(&curseg->curseg_mutex); +} + +void rewrite_node_page(struct f2fs_sb_info *sbi, + struct page *page, struct f2fs_summary *sum, + block_t old_blkaddr, block_t new_blkaddr) +{ + struct sit_info *sit_i = SIT_I(sbi); + int type = CURSEG_WARM_NODE; + struct curseg_info *curseg; + unsigned int segno, old_cursegno; + block_t next_blkaddr = next_blkaddr_of_node(page); + unsigned int next_segno = GET_SEGNO(sbi, next_blkaddr); + + curseg = CURSEG_I(sbi, type); + + mutex_lock(&curseg->curseg_mutex); + mutex_lock(&sit_i->sentry_lock); + + segno = GET_SEGNO(sbi, new_blkaddr); + old_cursegno = curseg->segno; + + /* change the current segment */ + if (segno != curseg->segno) { + curseg->next_segno = segno; + change_curseg(sbi, type, true); + } + curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) & + (sbi->blocks_per_seg - 1); + __add_sum_entry(sbi, type, sum, curseg->next_blkoff); + + /* change the current log to the next block addr in advance */ + if (next_segno != segno) { + curseg->next_segno = next_segno; + change_curseg(sbi, type, true); + } + curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, next_blkaddr) & + (sbi->blocks_per_seg - 1); + + /* rewrite node page */ + set_page_writeback(page); + submit_write_page(sbi, page, new_blkaddr, NODE); + f2fs_submit_bio(sbi, NODE, true); + refresh_sit_entry(sbi, old_blkaddr, new_blkaddr); + + locate_dirty_segment(sbi, old_cursegno); + locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); + + mutex_unlock(&sit_i->sentry_lock); + mutex_unlock(&curseg->curseg_mutex); +} + +static int read_compacted_summaries(struct f2fs_sb_info *sbi) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + struct curseg_info *seg_i; + unsigned char *kaddr; + struct page *page; + block_t start; + int i, j, offset; + + start = start_sum_block(sbi); + + page = get_meta_page(sbi, start++); + kaddr = (unsigned char *)page_address(page); + + /* Step 1: restore nat cache */ + seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); + memcpy(&seg_i->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE); + + /* Step 2: restore sit cache */ + seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); + memcpy(&seg_i->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, + SUM_JOURNAL_SIZE); + offset = 2 * SUM_JOURNAL_SIZE; + + /* Step 3: restore summary entries */ + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { + unsigned short blk_off; + unsigned int segno; + + seg_i = CURSEG_I(sbi, i); + segno = le32_to_cpu(ckpt->cur_data_segno[i]); + blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); + seg_i->next_segno = segno; + reset_curseg(sbi, i, 0); + seg_i->alloc_type = ckpt->alloc_type[i]; + seg_i->next_blkoff = blk_off; + + if (seg_i->alloc_type == SSR) + blk_off = sbi->blocks_per_seg; + + for (j = 0; j < blk_off; j++) { + struct f2fs_summary *s; + s = (struct f2fs_summary *)(kaddr + offset); + seg_i->sum_blk->entries[j] = *s; + offset += SUMMARY_SIZE; + if (offset + SUMMARY_SIZE <= PAGE_CACHE_SIZE - + SUM_FOOTER_SIZE) + continue; + + f2fs_put_page(page, 1); + page = NULL; + + page = get_meta_page(sbi, start++); + kaddr = (unsigned char *)page_address(page); + offset = 0; + } + } + f2fs_put_page(page, 1); + return 0; +} + +static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + struct f2fs_summary_block *sum; + struct curseg_info *curseg; + struct page *new; + unsigned short blk_off; + unsigned int segno = 0; + block_t blk_addr = 0; + + /* get segment number and block addr */ + if (IS_DATASEG(type)) { + segno = le32_to_cpu(ckpt->cur_data_segno[type]); + blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - + CURSEG_HOT_DATA]); + if (ckpt->ckpt_flags & CP_UMOUNT_FLAG) + blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type); + else + blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); + } else { + segno = le32_to_cpu(ckpt->cur_node_segno[type - + CURSEG_HOT_NODE]); + blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - + CURSEG_HOT_NODE]); + if (ckpt->ckpt_flags & CP_UMOUNT_FLAG) + blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, + type - CURSEG_HOT_NODE); + else + blk_addr = GET_SUM_BLOCK(sbi, segno); + } + + new = get_meta_page(sbi, blk_addr); + sum = (struct f2fs_summary_block *)page_address(new); + + if (IS_NODESEG(type)) { + if (ckpt->ckpt_flags & CP_UMOUNT_FLAG) { + struct f2fs_summary *ns = &sum->entries[0]; + int i; + for (i = 0; i < sbi->blocks_per_seg; i++, ns++) { + ns->version = 0; + ns->ofs_in_node = 0; + } + } else { + if (restore_node_summary(sbi, segno, sum)) { + f2fs_put_page(new, 1); + return -EINVAL; + } + } + } + + /* set uncompleted segment to curseg */ + curseg = CURSEG_I(sbi, type); + mutex_lock(&curseg->curseg_mutex); + memcpy(curseg->sum_blk, sum, PAGE_CACHE_SIZE); + curseg->next_segno = segno; + reset_curseg(sbi, type, 0); + curseg->alloc_type = ckpt->alloc_type[type]; + curseg->next_blkoff = blk_off; + mutex_unlock(&curseg->curseg_mutex); + f2fs_put_page(new, 1); + return 0; +} + +static int restore_curseg_summaries(struct f2fs_sb_info *sbi) +{ + int type = CURSEG_HOT_DATA; + + if (sbi->ckpt->ckpt_flags & CP_COMPACT_SUM_FLAG) { + /* restore for compacted data summary */ + if (read_compacted_summaries(sbi)) + return -EINVAL; + type = CURSEG_HOT_NODE; + } + + for (; type <= CURSEG_COLD_NODE; type++) + if (read_normal_summaries(sbi, type)) + return -EINVAL; + return 0; +} + +static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) +{ + struct page *page; + unsigned char *kaddr; + struct f2fs_summary *summary; + struct curseg_info *seg_i; + int written_size = 0; + int i, j; + + page = grab_meta_page(sbi, blkaddr++); + kaddr = (unsigned char *)page_address(page); + + /* Step 1: write nat cache */ + seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); + memcpy(kaddr, &seg_i->sum_blk->n_nats, SUM_JOURNAL_SIZE); + written_size += SUM_JOURNAL_SIZE; + + /* Step 2: write sit cache */ + seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); + memcpy(kaddr + written_size, &seg_i->sum_blk->n_sits, + SUM_JOURNAL_SIZE); + written_size += SUM_JOURNAL_SIZE; + + set_page_dirty(page); + + /* Step 3: write summary entries */ + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { + unsigned short blkoff; + seg_i = CURSEG_I(sbi, i); + if (sbi->ckpt->alloc_type[i] == SSR) + blkoff = sbi->blocks_per_seg; + else + blkoff = curseg_blkoff(sbi, i); + + for (j = 0; j < blkoff; j++) { + if (!page) { + page = grab_meta_page(sbi, blkaddr++); + kaddr = (unsigned char *)page_address(page); + written_size = 0; + } + summary = (struct f2fs_summary *)(kaddr + written_size); + *summary = seg_i->sum_blk->entries[j]; + written_size += SUMMARY_SIZE; + set_page_dirty(page); + + if (written_size + SUMMARY_SIZE <= PAGE_CACHE_SIZE - + SUM_FOOTER_SIZE) + continue; + + f2fs_put_page(page, 1); + page = NULL; + } + } + if (page) + f2fs_put_page(page, 1); +} + +static void write_normal_summaries(struct f2fs_sb_info *sbi, + block_t blkaddr, int type) +{ + int i, end; + if (IS_DATASEG(type)) + end = type + NR_CURSEG_DATA_TYPE; + else + end = type + NR_CURSEG_NODE_TYPE; + + for (i = type; i < end; i++) { + struct curseg_info *sum = CURSEG_I(sbi, i); + mutex_lock(&sum->curseg_mutex); + write_sum_page(sbi, sum->sum_blk, blkaddr + (i - type)); + mutex_unlock(&sum->curseg_mutex); + } +} + +void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) +{ + if (sbi->ckpt->ckpt_flags & CP_COMPACT_SUM_FLAG) + write_compacted_summaries(sbi, start_blk); + else + write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA); +} + +void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) +{ + if (sbi->ckpt->ckpt_flags & CP_UMOUNT_FLAG) + write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); + return; +} + +int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, + unsigned int val, int alloc) +{ + int i; + + if (type == NAT_JOURNAL) { + for (i = 0; i < nats_in_cursum(sum); i++) { + if (le32_to_cpu(nid_in_journal(sum, i)) == val) + return i; + } + if (alloc && nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES) + return update_nats_in_cursum(sum, 1); + } else if (type == SIT_JOURNAL) { + for (i = 0; i < sits_in_cursum(sum); i++) + if (le32_to_cpu(segno_in_journal(sum, i)) == val) + return i; + if (alloc && sits_in_cursum(sum) < SIT_JOURNAL_ENTRIES) + return update_sits_in_cursum(sum, 1); + } + return -1; +} + +static struct page *get_current_sit_page(struct f2fs_sb_info *sbi, + unsigned int segno) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno); + block_t blk_addr = sit_i->sit_base_addr + offset; + + check_seg_range(sbi, segno); + + /* calculate sit block address */ + if (f2fs_test_bit(offset, sit_i->sit_bitmap)) + blk_addr += sit_i->sit_blocks; + + return get_meta_page(sbi, blk_addr); +} + +static struct page *get_next_sit_page(struct f2fs_sb_info *sbi, + unsigned int start) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct page *src_page, *dst_page; + pgoff_t src_off, dst_off; + void *src_addr, *dst_addr; + + src_off = current_sit_addr(sbi, start); + dst_off = next_sit_addr(sbi, src_off); + + /* get current sit block page without lock */ + src_page = get_meta_page(sbi, src_off); + dst_page = grab_meta_page(sbi, dst_off); + BUG_ON(PageDirty(src_page)); + + src_addr = page_address(src_page); + dst_addr = page_address(dst_page); + memcpy(dst_addr, src_addr, PAGE_CACHE_SIZE); + + set_page_dirty(dst_page); + f2fs_put_page(src_page, 1); + + set_to_next_sit(sit_i, start); + + return dst_page; +} + +static bool flush_sits_in_journal(struct f2fs_sb_info *sbi) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); + struct f2fs_summary_block *sum = curseg->sum_blk; + int i; + + /* + * If the journal area in the current summary is full of sit entries, + * all the sit entries will be flushed. Otherwise the sit entries + * are not able to replace with newly hot sit entries. + */ + if (sits_in_cursum(sum) >= SIT_JOURNAL_ENTRIES) { + for (i = sits_in_cursum(sum) - 1; i >= 0; i--) { + unsigned int segno; + segno = le32_to_cpu(segno_in_journal(sum, i)); + __mark_sit_entry_dirty(sbi, segno); + } + update_sits_in_cursum(sum, -sits_in_cursum(sum)); + return 1; + } + return 0; +} + +/** + * CP calls this function, which flushes SIT entries including sit_journal, + * and moves prefree segs to free segs. + */ +void flush_sit_entries(struct f2fs_sb_info *sbi) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned long *bitmap = sit_i->dirty_sentries_bitmap; + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); + struct f2fs_summary_block *sum = curseg->sum_blk; + unsigned long nsegs = TOTAL_SEGS(sbi); + struct page *page = NULL; + struct f2fs_sit_block *raw_sit = NULL; + unsigned int start = 0, end = 0; + unsigned int segno = -1; + bool flushed; + + mutex_lock(&curseg->curseg_mutex); + mutex_lock(&sit_i->sentry_lock); + + /* + * "flushed" indicates whether sit entries in journal are flushed + * to the SIT area or not. + */ + flushed = flush_sits_in_journal(sbi); + + while ((segno = find_next_bit(bitmap, nsegs, segno + 1)) < nsegs) { + struct seg_entry *se = get_seg_entry(sbi, segno); + int sit_offset, offset; + + sit_offset = SIT_ENTRY_OFFSET(sit_i, segno); + + if (flushed) + goto to_sit_page; + + offset = lookup_journal_in_cursum(sum, SIT_JOURNAL, segno, 1); + if (offset >= 0) { + segno_in_journal(sum, offset) = cpu_to_le32(segno); + seg_info_to_raw_sit(se, &sit_in_journal(sum, offset)); + goto flush_done; + } +to_sit_page: + if (!page || (start > segno) || (segno > end)) { + if (page) { + f2fs_put_page(page, 1); + page = NULL; + } + + start = START_SEGNO(sit_i, segno); + end = start + SIT_ENTRY_PER_BLOCK - 1; + + /* read sit block that will be updated */ + page = get_next_sit_page(sbi, start); + raw_sit = page_address(page); + } + + /* udpate entry in SIT block */ + seg_info_to_raw_sit(se, &raw_sit->entries[sit_offset]); +flush_done: + __clear_bit(segno, bitmap); + sit_i->dirty_sentries--; + } + mutex_unlock(&sit_i->sentry_lock); + mutex_unlock(&curseg->curseg_mutex); + + /* writeout last modified SIT block */ + f2fs_put_page(page, 1); + + set_prefree_as_free_segments(sbi); +} + +static int build_sit_info(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + struct sit_info *sit_i; + unsigned int sit_segs, start; + char *src_bitmap, *dst_bitmap; + unsigned int bitmap_size; + + /* allocate memory for SIT information */ + sit_i = kzalloc(sizeof(struct sit_info), GFP_KERNEL); + if (!sit_i) + return -ENOMEM; + + SM_I(sbi)->sit_info = sit_i; + + sit_i->sentries = vzalloc(TOTAL_SEGS(sbi) * sizeof(struct seg_entry)); + if (!sit_i->sentries) + return -ENOMEM; + + bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); + sit_i->dirty_sentries_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!sit_i->dirty_sentries_bitmap) + return -ENOMEM; + + for (start = 0; start < TOTAL_SEGS(sbi); start++) { + sit_i->sentries[start].cur_valid_map + = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); + sit_i->sentries[start].ckpt_valid_map + = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); + if (!sit_i->sentries[start].cur_valid_map + || !sit_i->sentries[start].ckpt_valid_map) + return -ENOMEM; + } + + if (sbi->segs_per_sec > 1) { + sit_i->sec_entries = vzalloc(sbi->total_sections * + sizeof(struct sec_entry)); + if (!sit_i->sec_entries) + return -ENOMEM; + } + + /* get information related with SIT */ + sit_segs = le32_to_cpu(raw_super->segment_count_sit) >> 1; + + /* setup SIT bitmap from ckeckpoint pack */ + bitmap_size = __bitmap_size(sbi, SIT_BITMAP); + src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP); + + dst_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!dst_bitmap) + return -ENOMEM; + memcpy(dst_bitmap, src_bitmap, bitmap_size); + + /* init SIT information */ + sit_i->s_ops = &default_salloc_ops; + + sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr); + sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg; + sit_i->written_valid_blocks = le64_to_cpu(ckpt->valid_block_count); + sit_i->sit_bitmap = dst_bitmap; + sit_i->bitmap_size = bitmap_size; + sit_i->dirty_sentries = 0; + sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK; + sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time); + sit_i->mounted_time = CURRENT_TIME_SEC.tv_sec; + mutex_init(&sit_i->sentry_lock); + return 0; +} + +static int build_free_segmap(struct f2fs_sb_info *sbi) +{ + struct f2fs_sm_info *sm_info = SM_I(sbi); + struct free_segmap_info *free_i; + unsigned int bitmap_size, sec_bitmap_size; + + /* allocate memory for free segmap information */ + free_i = kzalloc(sizeof(struct free_segmap_info), GFP_KERNEL); + if (!free_i) + return -ENOMEM; + + SM_I(sbi)->free_info = free_i; + + bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); + free_i->free_segmap = kmalloc(bitmap_size, GFP_KERNEL); + if (!free_i->free_segmap) + return -ENOMEM; + + sec_bitmap_size = f2fs_bitmap_size(sbi->total_sections); + free_i->free_secmap = kmalloc(sec_bitmap_size, GFP_KERNEL); + if (!free_i->free_secmap) + return -ENOMEM; + + /* set all segments as dirty temporarily */ + memset(free_i->free_segmap, 0xff, bitmap_size); + memset(free_i->free_secmap, 0xff, sec_bitmap_size); + + /* init free segmap information */ + free_i->start_segno = + (unsigned int) GET_SEGNO_FROM_SEG0(sbi, sm_info->main_blkaddr); + free_i->free_segments = 0; + free_i->free_sections = 0; + rwlock_init(&free_i->segmap_lock); + return 0; +} + +static int build_curseg(struct f2fs_sb_info *sbi) +{ + struct curseg_info *array = NULL; + int i; + + array = kzalloc(sizeof(*array) * NR_CURSEG_TYPE, GFP_KERNEL); + if (!array) + return -ENOMEM; + + SM_I(sbi)->curseg_array = array; + + for (i = 0; i < NR_CURSEG_TYPE; i++) { + mutex_init(&array[i].curseg_mutex); + array[i].sum_blk = kzalloc(PAGE_CACHE_SIZE, GFP_KERNEL); + if (!array[i].sum_blk) + return -ENOMEM; + array[i].segno = NULL_SEGNO; + array[i].next_blkoff = 0; + } + return restore_curseg_summaries(sbi); +} + +static void build_sit_entries(struct f2fs_sb_info *sbi) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); + struct f2fs_summary_block *sum = curseg->sum_blk; + unsigned int start; + + for (start = 0; start < TOTAL_SEGS(sbi); start++) { + struct seg_entry *se = &sit_i->sentries[start]; + struct f2fs_sit_block *sit_blk; + struct f2fs_sit_entry sit; + struct page *page; + int i; + + mutex_lock(&curseg->curseg_mutex); + for (i = 0; i < sits_in_cursum(sum); i++) { + if (le32_to_cpu(segno_in_journal(sum, i)) == start) { + sit = sit_in_journal(sum, i); + mutex_unlock(&curseg->curseg_mutex); + goto got_it; + } + } + mutex_unlock(&curseg->curseg_mutex); + page = get_current_sit_page(sbi, start); + sit_blk = (struct f2fs_sit_block *)page_address(page); + sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)]; + f2fs_put_page(page, 1); +got_it: + check_block_count(sbi, start, &sit); + seg_info_from_raw_sit(se, &sit); + if (sbi->segs_per_sec > 1) { + struct sec_entry *e = get_sec_entry(sbi, start); + e->valid_blocks += se->valid_blocks; + } + } +} + +static void init_free_segmap(struct f2fs_sb_info *sbi) +{ + unsigned int start; + int type; + + for (start = 0; start < TOTAL_SEGS(sbi); start++) { + struct seg_entry *sentry = get_seg_entry(sbi, start); + if (!sentry->valid_blocks) + __set_free(sbi, start); + } + + /* set use the current segments */ + for (type = CURSEG_HOT_DATA; type <= CURSEG_COLD_NODE; type++) { + struct curseg_info *curseg_t = CURSEG_I(sbi, type); + __set_test_and_inuse(sbi, curseg_t->segno); + } +} + +static void init_dirty_segmap(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + struct free_segmap_info *free_i = FREE_I(sbi); + unsigned int segno = 0, offset = 0; + unsigned short valid_blocks; + + while (segno < TOTAL_SEGS(sbi)) { + /* find dirty segment based on free segmap */ + segno = find_next_inuse(free_i, TOTAL_SEGS(sbi), offset); + if (segno >= TOTAL_SEGS(sbi)) + break; + offset = segno + 1; + valid_blocks = get_valid_blocks(sbi, segno, 0); + if (valid_blocks >= sbi->blocks_per_seg || !valid_blocks) + continue; + mutex_lock(&dirty_i->seglist_lock); + __locate_dirty_segment(sbi, segno, DIRTY); + mutex_unlock(&dirty_i->seglist_lock); + } +} + +static int init_victim_segmap(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); + + dirty_i->victim_segmap[FG_GC] = kzalloc(bitmap_size, GFP_KERNEL); + dirty_i->victim_segmap[BG_GC] = kzalloc(bitmap_size, GFP_KERNEL); + if (!dirty_i->victim_segmap[FG_GC] || !dirty_i->victim_segmap[BG_GC]) + return -ENOMEM; + return 0; +} + +static int build_dirty_segmap(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i; + unsigned int bitmap_size, i; + + /* allocate memory for dirty segments list information */ + dirty_i = kzalloc(sizeof(struct dirty_seglist_info), GFP_KERNEL); + if (!dirty_i) + return -ENOMEM; + + SM_I(sbi)->dirty_info = dirty_i; + mutex_init(&dirty_i->seglist_lock); + + bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); + + for (i = 0; i < NR_DIRTY_TYPE; i++) { + dirty_i->dirty_segmap[i] = kzalloc(bitmap_size, GFP_KERNEL); + dirty_i->nr_dirty[i] = 0; + if (!dirty_i->dirty_segmap[i]) + return -ENOMEM; + } + + init_dirty_segmap(sbi); + return init_victim_segmap(sbi); +} + +/** + * Update min, max modified time for cost-benefit GC algorithm + */ +static void init_min_max_mtime(struct f2fs_sb_info *sbi) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned int segno; + + mutex_lock(&sit_i->sentry_lock); + + sit_i->min_mtime = LLONG_MAX; + + for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) { + unsigned int i; + unsigned long long mtime = 0; + + for (i = 0; i < sbi->segs_per_sec; i++) + mtime += get_seg_entry(sbi, segno + i)->mtime; + + mtime = div_u64(mtime, sbi->segs_per_sec); + + if (sit_i->min_mtime > mtime) + sit_i->min_mtime = mtime; + } + sit_i->max_mtime = get_mtime(sbi); + mutex_unlock(&sit_i->sentry_lock); +} + +int build_segment_manager(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + struct f2fs_sm_info *sm_info = NULL; + int err; + + sm_info = kzalloc(sizeof(struct f2fs_sm_info), GFP_KERNEL); + if (!sm_info) + return -ENOMEM; + + /* init sm info */ + sbi->sm_info = sm_info; + INIT_LIST_HEAD(&sm_info->wblist_head); + spin_lock_init(&sm_info->wblist_lock); + sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); + sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); + sm_info->segment_count = le32_to_cpu(raw_super->segment_count); + sm_info->reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count); + sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count); + sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main); + sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); + + err = build_sit_info(sbi); + if (err) + return err; + err = build_free_segmap(sbi); + if (err) + return err; + err = build_curseg(sbi); + if (err) + return err; + + /* reinit free segmap based on SIT */ + build_sit_entries(sbi); + + init_free_segmap(sbi); + err = build_dirty_segmap(sbi); + if (err) + return err; + + init_min_max_mtime(sbi); + return 0; +} + +static void discard_dirty_segmap(struct f2fs_sb_info *sbi, + enum dirty_type dirty_type) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + + mutex_lock(&dirty_i->seglist_lock); + kfree(dirty_i->dirty_segmap[dirty_type]); + dirty_i->nr_dirty[dirty_type] = 0; + mutex_unlock(&dirty_i->seglist_lock); +} + +void reset_victim_segmap(struct f2fs_sb_info *sbi) +{ + unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); + memset(DIRTY_I(sbi)->victim_segmap[FG_GC], 0, bitmap_size); +} + +static void destroy_victim_segmap(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + + kfree(dirty_i->victim_segmap[FG_GC]); + kfree(dirty_i->victim_segmap[BG_GC]); +} + +static void destroy_dirty_segmap(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + int i; + + if (!dirty_i) + return; + + /* discard pre-free/dirty segments list */ + for (i = 0; i < NR_DIRTY_TYPE; i++) + discard_dirty_segmap(sbi, i); + + destroy_victim_segmap(sbi); + SM_I(sbi)->dirty_info = NULL; + kfree(dirty_i); +} + +static void destroy_curseg(struct f2fs_sb_info *sbi) +{ + struct curseg_info *array = SM_I(sbi)->curseg_array; + int i; + + if (!array) + return; + SM_I(sbi)->curseg_array = NULL; + for (i = 0; i < NR_CURSEG_TYPE; i++) + kfree(array[i].sum_blk); + kfree(array); +} + +static void destroy_free_segmap(struct f2fs_sb_info *sbi) +{ + struct free_segmap_info *free_i = SM_I(sbi)->free_info; + if (!free_i) + return; + SM_I(sbi)->free_info = NULL; + kfree(free_i->free_segmap); + kfree(free_i->free_secmap); + kfree(free_i); +} + +static void destroy_sit_info(struct f2fs_sb_info *sbi) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned int start; + + if (!sit_i) + return; + + if (sit_i->sentries) { + for (start = 0; start < TOTAL_SEGS(sbi); start++) { + kfree(sit_i->sentries[start].cur_valid_map); + kfree(sit_i->sentries[start].ckpt_valid_map); + } + } + vfree(sit_i->sentries); + vfree(sit_i->sec_entries); + kfree(sit_i->dirty_sentries_bitmap); + + SM_I(sbi)->sit_info = NULL; + kfree(sit_i->sit_bitmap); + kfree(sit_i); +} + +void destroy_segment_manager(struct f2fs_sb_info *sbi) +{ + struct f2fs_sm_info *sm_info = SM_I(sbi); + destroy_dirty_segmap(sbi); + destroy_curseg(sbi); + destroy_free_segmap(sbi); + destroy_sit_info(sbi); + sbi->sm_info = NULL; + kfree(sm_info); +} -- cgit v0.10.2 From fbfa2cc58d5363f780f4f2ad0243a47185c2bb2a Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:09:44 +0900 Subject: f2fs: add file operations This adds memory operations and file/file_inode operations. - F2FS supports fallocate(), mmap(), fsync(), and basic ioctl(). Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c new file mode 100644 index 0000000..f5ae36d --- /dev/null +++ b/fs/f2fs/file.c @@ -0,0 +1,637 @@ +/** + * fs/f2fs/file.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "node.h" +#include "segment.h" +#include "xattr.h" +#include "acl.h" + +static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + struct page *page = vmf->page; + struct inode *inode = vma->vm_file->f_path.dentry->d_inode; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct page *node_page; + block_t old_blk_addr; + struct dnode_of_data dn; + int err; + + f2fs_balance_fs(sbi); + + sb_start_pagefault(inode->i_sb); + + mutex_lock_op(sbi, DATA_NEW); + + /* block allocation */ + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, page->index, 0); + if (err) { + mutex_unlock_op(sbi, DATA_NEW); + goto out; + } + + old_blk_addr = dn.data_blkaddr; + node_page = dn.node_page; + + if (old_blk_addr == NULL_ADDR) { + err = reserve_new_block(&dn); + if (err) { + f2fs_put_dnode(&dn); + mutex_unlock_op(sbi, DATA_NEW); + goto out; + } + } + f2fs_put_dnode(&dn); + + mutex_unlock_op(sbi, DATA_NEW); + + lock_page(page); + if (page->mapping != inode->i_mapping || + page_offset(page) >= i_size_read(inode) || + !PageUptodate(page)) { + unlock_page(page); + err = -EFAULT; + goto out; + } + + /* + * check to see if the page is mapped already (no holes) + */ + if (PageMappedToDisk(page)) + goto out; + + /* fill the page */ + wait_on_page_writeback(page); + + /* page is wholly or partially inside EOF */ + if (((page->index + 1) << PAGE_CACHE_SHIFT) > i_size_read(inode)) { + unsigned offset; + offset = i_size_read(inode) & ~PAGE_CACHE_MASK; + zero_user_segment(page, offset, PAGE_CACHE_SIZE); + } + set_page_dirty(page); + SetPageUptodate(page); + + file_update_time(vma->vm_file); +out: + sb_end_pagefault(inode->i_sb); + return block_page_mkwrite_return(err); +} + +static const struct vm_operations_struct f2fs_file_vm_ops = { + .fault = filemap_fault, + .page_mkwrite = f2fs_vm_page_mkwrite, +}; + +static int need_to_sync_dir(struct f2fs_sb_info *sbi, struct inode *inode) +{ + struct dentry *dentry; + nid_t pino; + + inode = igrab(inode); + dentry = d_find_any_alias(inode); + if (!dentry) { + iput(inode); + return 0; + } + pino = dentry->d_parent->d_inode->i_ino; + dput(dentry); + iput(inode); + return !is_checkpointed_node(sbi, pino); +} + +int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) +{ + struct inode *inode = file->f_mapping->host; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + unsigned long long cur_version; + int ret = 0; + bool need_cp = false; + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .for_reclaim = 0, + }; + + ret = filemap_write_and_wait_range(inode->i_mapping, start, end); + if (ret) + return ret; + + mutex_lock(&inode->i_mutex); + + if (inode->i_sb->s_flags & MS_RDONLY) + goto out; + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + goto out; + + mutex_lock(&sbi->cp_mutex); + cur_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver); + mutex_unlock(&sbi->cp_mutex); + + if (F2FS_I(inode)->data_version != cur_version && + !(inode->i_state & I_DIRTY)) + goto out; + F2FS_I(inode)->data_version--; + + if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) + need_cp = true; + if (is_inode_flag_set(F2FS_I(inode), FI_NEED_CP)) + need_cp = true; + if (!space_for_roll_forward(sbi)) + need_cp = true; + if (need_to_sync_dir(sbi, inode)) + need_cp = true; + + f2fs_write_inode(inode, NULL); + + if (need_cp) { + /* all the dirty node pages should be flushed for POR */ + ret = f2fs_sync_fs(inode->i_sb, 1); + clear_inode_flag(F2FS_I(inode), FI_NEED_CP); + } else { + while (sync_node_pages(sbi, inode->i_ino, &wbc) == 0) + f2fs_write_inode(inode, NULL); + filemap_fdatawait_range(sbi->node_inode->i_mapping, + 0, LONG_MAX); + } +out: + mutex_unlock(&inode->i_mutex); + return ret; +} + +static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + file_accessed(file); + vma->vm_ops = &f2fs_file_vm_ops; + return 0; +} + +static int truncate_data_blocks_range(struct dnode_of_data *dn, int count) +{ + int nr_free = 0, ofs = dn->ofs_in_node; + struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + struct f2fs_node *raw_node; + __le32 *addr; + + raw_node = page_address(dn->node_page); + addr = blkaddr_in_node(raw_node) + ofs; + + for ( ; count > 0; count--, addr++, dn->ofs_in_node++) { + block_t blkaddr = le32_to_cpu(*addr); + if (blkaddr == NULL_ADDR) + continue; + + update_extent_cache(NULL_ADDR, dn); + invalidate_blocks(sbi, blkaddr); + dec_valid_block_count(sbi, dn->inode, 1); + nr_free++; + } + if (nr_free) { + set_page_dirty(dn->node_page); + sync_inode_page(dn); + } + dn->ofs_in_node = ofs; + return nr_free; +} + +void truncate_data_blocks(struct dnode_of_data *dn) +{ + truncate_data_blocks_range(dn, ADDRS_PER_BLOCK); +} + +static void truncate_partial_data_page(struct inode *inode, u64 from) +{ + unsigned offset = from & (PAGE_CACHE_SIZE - 1); + struct page *page; + + if (!offset) + return; + + page = find_data_page(inode, from >> PAGE_CACHE_SHIFT); + if (IS_ERR(page)) + return; + + lock_page(page); + wait_on_page_writeback(page); + zero_user(page, offset, PAGE_CACHE_SIZE - offset); + set_page_dirty(page); + f2fs_put_page(page, 1); +} + +static int truncate_blocks(struct inode *inode, u64 from) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + unsigned int blocksize = inode->i_sb->s_blocksize; + struct dnode_of_data dn; + pgoff_t free_from; + int count = 0; + int err; + + free_from = (pgoff_t) + ((from + blocksize - 1) >> (sbi->log_blocksize)); + + mutex_lock_op(sbi, DATA_TRUNC); + + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, free_from, RDONLY_NODE); + if (err) { + if (err == -ENOENT) + goto free_next; + mutex_unlock_op(sbi, DATA_TRUNC); + return err; + } + + if (IS_INODE(dn.node_page)) + count = ADDRS_PER_INODE; + else + count = ADDRS_PER_BLOCK; + + count -= dn.ofs_in_node; + BUG_ON(count < 0); + if (dn.ofs_in_node || IS_INODE(dn.node_page)) { + truncate_data_blocks_range(&dn, count); + free_from += count; + } + + f2fs_put_dnode(&dn); +free_next: + err = truncate_inode_blocks(inode, free_from); + mutex_unlock_op(sbi, DATA_TRUNC); + + /* lastly zero out the first data page */ + truncate_partial_data_page(inode, from); + + return err; +} + +void f2fs_truncate(struct inode *inode) +{ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + + if (!truncate_blocks(inode, i_size_read(inode))) { + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + } + + f2fs_balance_fs(F2FS_SB(inode->i_sb)); +} + +static int f2fs_getattr(struct vfsmount *mnt, + struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + generic_fillattr(inode, stat); + stat->blocks <<= 3; + return 0; +} + +#ifdef CONFIG_F2FS_FS_POSIX_ACL +static void __setattr_copy(struct inode *inode, const struct iattr *attr) +{ + struct f2fs_inode_info *fi = F2FS_I(inode); + unsigned int ia_valid = attr->ia_valid; + + if (ia_valid & ATTR_UID) + inode->i_uid = attr->ia_uid; + if (ia_valid & ATTR_GID) + inode->i_gid = attr->ia_gid; + if (ia_valid & ATTR_ATIME) + inode->i_atime = timespec_trunc(attr->ia_atime, + inode->i_sb->s_time_gran); + if (ia_valid & ATTR_MTIME) + inode->i_mtime = timespec_trunc(attr->ia_mtime, + inode->i_sb->s_time_gran); + if (ia_valid & ATTR_CTIME) + inode->i_ctime = timespec_trunc(attr->ia_ctime, + inode->i_sb->s_time_gran); + if (ia_valid & ATTR_MODE) { + umode_t mode = attr->ia_mode; + + if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) + mode &= ~S_ISGID; + set_acl_inode(fi, mode); + } +} +#else +#define __setattr_copy setattr_copy +#endif + +int f2fs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + struct f2fs_inode_info *fi = F2FS_I(inode); + int err; + + err = inode_change_ok(inode, attr); + if (err) + return err; + + if ((attr->ia_valid & ATTR_SIZE) && + attr->ia_size != i_size_read(inode)) { + truncate_setsize(inode, attr->ia_size); + f2fs_truncate(inode); + } + + __setattr_copy(inode, attr); + + if (attr->ia_valid & ATTR_MODE) { + err = f2fs_acl_chmod(inode); + if (err || is_inode_flag_set(fi, FI_ACL_MODE)) { + inode->i_mode = fi->i_acl_mode; + clear_inode_flag(fi, FI_ACL_MODE); + } + } + + mark_inode_dirty(inode); + return err; +} + +const struct inode_operations f2fs_file_inode_operations = { + .getattr = f2fs_getattr, + .setattr = f2fs_setattr, + .get_acl = f2fs_get_acl, +#ifdef CONFIG_F2FS_FS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = f2fs_listxattr, + .removexattr = generic_removexattr, +#endif +}; + +static void fill_zero(struct inode *inode, pgoff_t index, + loff_t start, loff_t len) +{ + struct page *page; + + if (!len) + return; + + page = get_new_data_page(inode, index, false); + + if (!IS_ERR(page)) { + wait_on_page_writeback(page); + zero_user(page, start, len); + set_page_dirty(page); + f2fs_put_page(page, 1); + } +} + +int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end) +{ + pgoff_t index; + int err; + + for (index = pg_start; index < pg_end; index++) { + struct dnode_of_data dn; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + + mutex_lock_op(sbi, DATA_TRUNC); + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, index, RDONLY_NODE); + if (err) { + mutex_unlock_op(sbi, DATA_TRUNC); + if (err == -ENOENT) + continue; + return err; + } + + if (dn.data_blkaddr != NULL_ADDR) + truncate_data_blocks_range(&dn, 1); + f2fs_put_dnode(&dn); + mutex_unlock_op(sbi, DATA_TRUNC); + } + return 0; +} + +static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode) +{ + pgoff_t pg_start, pg_end; + loff_t off_start, off_end; + int ret = 0; + + pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; + pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; + + off_start = offset & (PAGE_CACHE_SIZE - 1); + off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); + + if (pg_start == pg_end) { + fill_zero(inode, pg_start, off_start, + off_end - off_start); + } else { + if (off_start) + fill_zero(inode, pg_start++, off_start, + PAGE_CACHE_SIZE - off_start); + if (off_end) + fill_zero(inode, pg_end, 0, off_end); + + if (pg_start < pg_end) { + struct address_space *mapping = inode->i_mapping; + loff_t blk_start, blk_end; + + blk_start = pg_start << PAGE_CACHE_SHIFT; + blk_end = pg_end << PAGE_CACHE_SHIFT; + truncate_inode_pages_range(mapping, blk_start, + blk_end - 1); + ret = truncate_hole(inode, pg_start, pg_end); + } + } + + if (!(mode & FALLOC_FL_KEEP_SIZE) && + i_size_read(inode) <= (offset + len)) { + i_size_write(inode, offset); + mark_inode_dirty(inode); + } + + return ret; +} + +static int expand_inode_data(struct inode *inode, loff_t offset, + loff_t len, int mode) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + pgoff_t index, pg_start, pg_end; + loff_t new_size = i_size_read(inode); + loff_t off_start, off_end; + int ret = 0; + + ret = inode_newsize_ok(inode, (len + offset)); + if (ret) + return ret; + + pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT; + pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT; + + off_start = offset & (PAGE_CACHE_SIZE - 1); + off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); + + for (index = pg_start; index <= pg_end; index++) { + struct dnode_of_data dn; + + mutex_lock_op(sbi, DATA_NEW); + + set_new_dnode(&dn, inode, NULL, NULL, 0); + ret = get_dnode_of_data(&dn, index, 0); + if (ret) { + mutex_unlock_op(sbi, DATA_NEW); + break; + } + + if (dn.data_blkaddr == NULL_ADDR) { + ret = reserve_new_block(&dn); + if (ret) { + f2fs_put_dnode(&dn); + mutex_unlock_op(sbi, DATA_NEW); + break; + } + } + f2fs_put_dnode(&dn); + + mutex_unlock_op(sbi, DATA_NEW); + + if (pg_start == pg_end) + new_size = offset + len; + else if (index == pg_start && off_start) + new_size = (index + 1) << PAGE_CACHE_SHIFT; + else if (index == pg_end) + new_size = (index << PAGE_CACHE_SHIFT) + off_end; + else + new_size += PAGE_CACHE_SIZE; + } + + if (!(mode & FALLOC_FL_KEEP_SIZE) && + i_size_read(inode) < new_size) { + i_size_write(inode, new_size); + mark_inode_dirty(inode); + } + + return ret; +} + +static long f2fs_fallocate(struct file *file, int mode, + loff_t offset, loff_t len) +{ + struct inode *inode = file->f_path.dentry->d_inode; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + long ret; + + if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) + return -EOPNOTSUPP; + + if (mode & FALLOC_FL_PUNCH_HOLE) + ret = punch_hole(inode, offset, len, mode); + else + ret = expand_inode_data(inode, offset, len, mode); + + f2fs_balance_fs(sbi); + return ret; +} + +#define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL)) +#define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL) + +static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags) +{ + if (S_ISDIR(mode)) + return flags; + else if (S_ISREG(mode)) + return flags & F2FS_REG_FLMASK; + else + return flags & F2FS_OTHER_FLMASK; +} + +long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct f2fs_inode_info *fi = F2FS_I(inode); + unsigned int flags; + int ret; + + switch (cmd) { + case FS_IOC_GETFLAGS: + flags = fi->i_flags & FS_FL_USER_VISIBLE; + return put_user(flags, (int __user *) arg); + case FS_IOC_SETFLAGS: + { + unsigned int oldflags; + + ret = mnt_want_write(filp->f_path.mnt); + if (ret) + return ret; + + if (!inode_owner_or_capable(inode)) { + ret = -EACCES; + goto out; + } + + if (get_user(flags, (int __user *) arg)) { + ret = -EFAULT; + goto out; + } + + flags = f2fs_mask_flags(inode->i_mode, flags); + + mutex_lock(&inode->i_mutex); + + oldflags = fi->i_flags; + + if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { + if (!capable(CAP_LINUX_IMMUTABLE)) { + mutex_unlock(&inode->i_mutex); + ret = -EPERM; + goto out; + } + } + + flags = flags & FS_FL_USER_MODIFIABLE; + flags |= oldflags & ~FS_FL_USER_MODIFIABLE; + fi->i_flags = flags; + mutex_unlock(&inode->i_mutex); + + f2fs_set_inode_flags(inode); + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); +out: + mnt_drop_write(filp->f_path.mnt); + return ret; + } + default: + return -ENOTTY; + } +} + +const struct file_operations f2fs_file_operations = { + .llseek = generic_file_llseek, + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, + .open = generic_file_open, + .mmap = f2fs_file_mmap, + .fsync = f2fs_sync_file, + .fallocate = f2fs_fallocate, + .unlocked_ioctl = f2fs_ioctl, + .splice_read = generic_file_splice_read, + .splice_write = generic_file_splice_write, +}; -- cgit v0.10.2 From eb47b8009dc969a3386c983bd5e798e9f690c5d9 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:10:12 +0900 Subject: f2fs: add address space operations for data This adds address space operations for data. - F2FS supports readpages(), writepages(), and direct_IO(). - Because of out-of-place writes, f2fs_direct_IO() does not write data in place. Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c new file mode 100644 index 0000000..c2fd0a8 --- /dev/null +++ b/fs/f2fs/data.c @@ -0,0 +1,701 @@ +/** + * fs/f2fs/data.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "node.h" +#include "segment.h" + +/** + * Lock ordering for the change of data block address: + * ->data_page + * ->node_page + * update block addresses in the node page + */ +static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr) +{ + struct f2fs_node *rn; + __le32 *addr_array; + struct page *node_page = dn->node_page; + unsigned int ofs_in_node = dn->ofs_in_node; + + wait_on_page_writeback(node_page); + + rn = (struct f2fs_node *)page_address(node_page); + + /* Get physical address of data block */ + addr_array = blkaddr_in_node(rn); + addr_array[ofs_in_node] = cpu_to_le32(new_addr); + set_page_dirty(node_page); +} + +int reserve_new_block(struct dnode_of_data *dn) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb); + + if (is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)) + return -EPERM; + if (!inc_valid_block_count(sbi, dn->inode, 1)) + return -ENOSPC; + + __set_data_blkaddr(dn, NEW_ADDR); + dn->data_blkaddr = NEW_ADDR; + sync_inode_page(dn); + return 0; +} + +static int check_extent_cache(struct inode *inode, pgoff_t pgofs, + struct buffer_head *bh_result) +{ + struct f2fs_inode_info *fi = F2FS_I(inode); + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + pgoff_t start_fofs, end_fofs; + block_t start_blkaddr; + + read_lock(&fi->ext.ext_lock); + if (fi->ext.len == 0) { + read_unlock(&fi->ext.ext_lock); + return 0; + } + + sbi->total_hit_ext++; + start_fofs = fi->ext.fofs; + end_fofs = fi->ext.fofs + fi->ext.len - 1; + start_blkaddr = fi->ext.blk_addr; + + if (pgofs >= start_fofs && pgofs <= end_fofs) { + unsigned int blkbits = inode->i_sb->s_blocksize_bits; + size_t count; + + clear_buffer_new(bh_result); + map_bh(bh_result, inode->i_sb, + start_blkaddr + pgofs - start_fofs); + count = end_fofs - pgofs + 1; + if (count < (UINT_MAX >> blkbits)) + bh_result->b_size = (count << blkbits); + else + bh_result->b_size = UINT_MAX; + + sbi->read_hit_ext++; + read_unlock(&fi->ext.ext_lock); + return 1; + } + read_unlock(&fi->ext.ext_lock); + return 0; +} + +void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn) +{ + struct f2fs_inode_info *fi = F2FS_I(dn->inode); + pgoff_t fofs, start_fofs, end_fofs; + block_t start_blkaddr, end_blkaddr; + + BUG_ON(blk_addr == NEW_ADDR); + fofs = start_bidx_of_node(ofs_of_node(dn->node_page)) + dn->ofs_in_node; + + /* Update the page address in the parent node */ + __set_data_blkaddr(dn, blk_addr); + + write_lock(&fi->ext.ext_lock); + + start_fofs = fi->ext.fofs; + end_fofs = fi->ext.fofs + fi->ext.len - 1; + start_blkaddr = fi->ext.blk_addr; + end_blkaddr = fi->ext.blk_addr + fi->ext.len - 1; + + /* Drop and initialize the matched extent */ + if (fi->ext.len == 1 && fofs == start_fofs) + fi->ext.len = 0; + + /* Initial extent */ + if (fi->ext.len == 0) { + if (blk_addr != NULL_ADDR) { + fi->ext.fofs = fofs; + fi->ext.blk_addr = blk_addr; + fi->ext.len = 1; + } + goto end_update; + } + + /* Frone merge */ + if (fofs == start_fofs - 1 && blk_addr == start_blkaddr - 1) { + fi->ext.fofs--; + fi->ext.blk_addr--; + fi->ext.len++; + goto end_update; + } + + /* Back merge */ + if (fofs == end_fofs + 1 && blk_addr == end_blkaddr + 1) { + fi->ext.len++; + goto end_update; + } + + /* Split the existing extent */ + if (fi->ext.len > 1 && + fofs >= start_fofs && fofs <= end_fofs) { + if ((end_fofs - fofs) < (fi->ext.len >> 1)) { + fi->ext.len = fofs - start_fofs; + } else { + fi->ext.fofs = fofs + 1; + fi->ext.blk_addr = start_blkaddr + + fofs - start_fofs + 1; + fi->ext.len -= fofs - start_fofs + 1; + } + goto end_update; + } + write_unlock(&fi->ext.ext_lock); + return; + +end_update: + write_unlock(&fi->ext.ext_lock); + sync_inode_page(dn); + return; +} + +struct page *find_data_page(struct inode *inode, pgoff_t index) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct address_space *mapping = inode->i_mapping; + struct dnode_of_data dn; + struct page *page; + int err; + + page = find_get_page(mapping, index); + if (page && PageUptodate(page)) + return page; + f2fs_put_page(page, 0); + + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, index, RDONLY_NODE); + if (err) + return ERR_PTR(err); + f2fs_put_dnode(&dn); + + if (dn.data_blkaddr == NULL_ADDR) + return ERR_PTR(-ENOENT); + + /* By fallocate(), there is no cached page, but with NEW_ADDR */ + if (dn.data_blkaddr == NEW_ADDR) + return ERR_PTR(-EINVAL); + + page = grab_cache_page(mapping, index); + if (!page) + return ERR_PTR(-ENOMEM); + + err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); + if (err) { + f2fs_put_page(page, 1); + return ERR_PTR(err); + } + unlock_page(page); + return page; +} + +/** + * If it tries to access a hole, return an error. + * Because, the callers, functions in dir.c and GC, should be able to know + * whether this page exists or not. + */ +struct page *get_lock_data_page(struct inode *inode, pgoff_t index) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct address_space *mapping = inode->i_mapping; + struct dnode_of_data dn; + struct page *page; + int err; + + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, index, RDONLY_NODE); + if (err) + return ERR_PTR(err); + f2fs_put_dnode(&dn); + + if (dn.data_blkaddr == NULL_ADDR) + return ERR_PTR(-ENOENT); + + page = grab_cache_page(mapping, index); + if (!page) + return ERR_PTR(-ENOMEM); + + if (PageUptodate(page)) + return page; + + BUG_ON(dn.data_blkaddr == NEW_ADDR); + BUG_ON(dn.data_blkaddr == NULL_ADDR); + + err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); + if (err) { + f2fs_put_page(page, 1); + return ERR_PTR(err); + } + return page; +} + +/** + * Caller ensures that this data page is never allocated. + * A new zero-filled data page is allocated in the page cache. + */ +struct page *get_new_data_page(struct inode *inode, pgoff_t index, + bool new_i_size) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct address_space *mapping = inode->i_mapping; + struct page *page; + struct dnode_of_data dn; + int err; + + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, index, 0); + if (err) + return ERR_PTR(err); + + if (dn.data_blkaddr == NULL_ADDR) { + if (reserve_new_block(&dn)) { + f2fs_put_dnode(&dn); + return ERR_PTR(-ENOSPC); + } + } + f2fs_put_dnode(&dn); + + page = grab_cache_page(mapping, index); + if (!page) + return ERR_PTR(-ENOMEM); + + if (PageUptodate(page)) + return page; + + if (dn.data_blkaddr == NEW_ADDR) { + zero_user_segment(page, 0, PAGE_CACHE_SIZE); + } else { + err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); + if (err) { + f2fs_put_page(page, 1); + return ERR_PTR(err); + } + } + SetPageUptodate(page); + + if (new_i_size && + i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) { + i_size_write(inode, ((index + 1) << PAGE_CACHE_SHIFT)); + mark_inode_dirty_sync(inode); + } + return page; +} + +static void read_end_io(struct bio *bio, int err) +{ + const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + + do { + struct page *page = bvec->bv_page; + + if (--bvec >= bio->bi_io_vec) + prefetchw(&bvec->bv_page->flags); + + if (uptodate) { + SetPageUptodate(page); + } else { + ClearPageUptodate(page); + SetPageError(page); + } + unlock_page(page); + } while (bvec >= bio->bi_io_vec); + kfree(bio->bi_private); + bio_put(bio); +} + +/** + * Fill the locked page with data located in the block address. + * Read operation is synchronous, and caller must unlock the page. + */ +int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page, + block_t blk_addr, int type) +{ + struct block_device *bdev = sbi->sb->s_bdev; + bool sync = (type == READ_SYNC); + struct bio *bio; + + /* This page can be already read by other threads */ + if (PageUptodate(page)) { + if (!sync) + unlock_page(page); + return 0; + } + + down_read(&sbi->bio_sem); + + /* Allocate a new bio */ + bio = f2fs_bio_alloc(bdev, blk_addr << (sbi->log_blocksize - 9), + 1, GFP_NOFS | __GFP_HIGH); + + /* Initialize the bio */ + bio->bi_end_io = read_end_io; + if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { + kfree(bio->bi_private); + bio_put(bio); + up_read(&sbi->bio_sem); + return -EFAULT; + } + + submit_bio(type, bio); + up_read(&sbi->bio_sem); + + /* wait for read completion if sync */ + if (sync) { + lock_page(page); + if (PageError(page)) + return -EIO; + } + return 0; +} + +/** + * This function should be used by the data read flow only where it + * does not check the "create" flag that indicates block allocation. + * The reason for this special functionality is to exploit VFS readahead + * mechanism. + */ +static int get_data_block_ro(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + unsigned int blkbits = inode->i_sb->s_blocksize_bits; + unsigned maxblocks = bh_result->b_size >> blkbits; + struct dnode_of_data dn; + pgoff_t pgofs; + int err; + + /* Get the page offset from the block offset(iblock) */ + pgofs = (pgoff_t)(iblock >> (PAGE_CACHE_SHIFT - blkbits)); + + if (check_extent_cache(inode, pgofs, bh_result)) + return 0; + + /* When reading holes, we need its node page */ + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, pgofs, RDONLY_NODE); + if (err) + return (err == -ENOENT) ? 0 : err; + + /* It does not support data allocation */ + BUG_ON(create); + + if (dn.data_blkaddr != NEW_ADDR && dn.data_blkaddr != NULL_ADDR) { + int i; + unsigned int end_offset; + + end_offset = IS_INODE(dn.node_page) ? + ADDRS_PER_INODE : + ADDRS_PER_BLOCK; + + clear_buffer_new(bh_result); + + /* Give more consecutive addresses for the read ahead */ + for (i = 0; i < end_offset - dn.ofs_in_node; i++) + if (((datablock_addr(dn.node_page, + dn.ofs_in_node + i)) + != (dn.data_blkaddr + i)) || maxblocks == i) + break; + map_bh(bh_result, inode->i_sb, dn.data_blkaddr); + bh_result->b_size = (i << blkbits); + } + f2fs_put_dnode(&dn); + return 0; +} + +static int f2fs_read_data_page(struct file *file, struct page *page) +{ + return mpage_readpage(page, get_data_block_ro); +} + +static int f2fs_read_data_pages(struct file *file, + struct address_space *mapping, + struct list_head *pages, unsigned nr_pages) +{ + return mpage_readpages(mapping, pages, nr_pages, get_data_block_ro); +} + +int do_write_data_page(struct page *page) +{ + struct inode *inode = page->mapping->host; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + block_t old_blk_addr, new_blk_addr; + struct dnode_of_data dn; + int err = 0; + + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, page->index, RDONLY_NODE); + if (err) + return err; + + old_blk_addr = dn.data_blkaddr; + + /* This page is already truncated */ + if (old_blk_addr == NULL_ADDR) + goto out_writepage; + + set_page_writeback(page); + + /* + * If current allocation needs SSR, + * it had better in-place writes for updated data. + */ + if (old_blk_addr != NEW_ADDR && !is_cold_data(page) && + need_inplace_update(inode)) { + rewrite_data_page(F2FS_SB(inode->i_sb), page, + old_blk_addr); + } else { + write_data_page(inode, page, &dn, + old_blk_addr, &new_blk_addr); + update_extent_cache(new_blk_addr, &dn); + F2FS_I(inode)->data_version = + le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver); + } +out_writepage: + f2fs_put_dnode(&dn); + return err; +} + +static int f2fs_write_data_page(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + loff_t i_size = i_size_read(inode); + const pgoff_t end_index = ((unsigned long long) i_size) + >> PAGE_CACHE_SHIFT; + unsigned offset; + int err = 0; + + if (page->index < end_index) + goto out; + + /* + * If the offset is out-of-range of file size, + * this page does not have to be written to disk. + */ + offset = i_size & (PAGE_CACHE_SIZE - 1); + if ((page->index >= end_index + 1) || !offset) { + if (S_ISDIR(inode->i_mode)) { + dec_page_count(sbi, F2FS_DIRTY_DENTS); + inode_dec_dirty_dents(inode); + } + goto unlock_out; + } + + zero_user_segment(page, offset, PAGE_CACHE_SIZE); +out: + if (sbi->por_doing) + goto redirty_out; + + if (wbc->for_reclaim && !S_ISDIR(inode->i_mode) && !is_cold_data(page)) + goto redirty_out; + + mutex_lock_op(sbi, DATA_WRITE); + if (S_ISDIR(inode->i_mode)) { + dec_page_count(sbi, F2FS_DIRTY_DENTS); + inode_dec_dirty_dents(inode); + } + err = do_write_data_page(page); + if (err && err != -ENOENT) { + wbc->pages_skipped++; + set_page_dirty(page); + } + mutex_unlock_op(sbi, DATA_WRITE); + + if (wbc->for_reclaim) + f2fs_submit_bio(sbi, DATA, true); + + if (err == -ENOENT) + goto unlock_out; + + clear_cold_data(page); + unlock_page(page); + + if (!wbc->for_reclaim && !S_ISDIR(inode->i_mode)) + f2fs_balance_fs(sbi); + return 0; + +unlock_out: + unlock_page(page); + return (err == -ENOENT) ? 0 : err; + +redirty_out: + wbc->pages_skipped++; + set_page_dirty(page); + return AOP_WRITEPAGE_ACTIVATE; +} + +#define MAX_DESIRED_PAGES_WP 4096 + +int f2fs_write_data_pages(struct address_space *mapping, + struct writeback_control *wbc) +{ + struct inode *inode = mapping->host; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + int ret; + long excess_nrtw = 0, desired_nrtw; + + if (wbc->nr_to_write < MAX_DESIRED_PAGES_WP) { + desired_nrtw = MAX_DESIRED_PAGES_WP; + excess_nrtw = desired_nrtw - wbc->nr_to_write; + wbc->nr_to_write = desired_nrtw; + } + + if (!S_ISDIR(inode->i_mode)) + mutex_lock(&sbi->writepages); + ret = generic_writepages(mapping, wbc); + if (!S_ISDIR(inode->i_mode)) + mutex_unlock(&sbi->writepages); + f2fs_submit_bio(sbi, DATA, (wbc->sync_mode == WB_SYNC_ALL)); + + remove_dirty_dir_inode(inode); + + wbc->nr_to_write -= excess_nrtw; + return ret; +} + +static int f2fs_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + struct inode *inode = mapping->host; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct page *page; + pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT; + struct dnode_of_data dn; + int err = 0; + + /* for nobh_write_end */ + *fsdata = NULL; + + f2fs_balance_fs(sbi); + + page = grab_cache_page_write_begin(mapping, index, flags); + if (!page) + return -ENOMEM; + *pagep = page; + + mutex_lock_op(sbi, DATA_NEW); + + set_new_dnode(&dn, inode, NULL, NULL, 0); + err = get_dnode_of_data(&dn, index, 0); + if (err) { + mutex_unlock_op(sbi, DATA_NEW); + f2fs_put_page(page, 1); + return err; + } + + if (dn.data_blkaddr == NULL_ADDR) { + err = reserve_new_block(&dn); + if (err) { + f2fs_put_dnode(&dn); + mutex_unlock_op(sbi, DATA_NEW); + f2fs_put_page(page, 1); + return err; + } + } + f2fs_put_dnode(&dn); + + mutex_unlock_op(sbi, DATA_NEW); + + if ((len == PAGE_CACHE_SIZE) || PageUptodate(page)) + return 0; + + if ((pos & PAGE_CACHE_MASK) >= i_size_read(inode)) { + unsigned start = pos & (PAGE_CACHE_SIZE - 1); + unsigned end = start + len; + + /* Reading beyond i_size is simple: memset to zero */ + zero_user_segments(page, 0, start, end, PAGE_CACHE_SIZE); + return 0; + } + + if (dn.data_blkaddr == NEW_ADDR) { + zero_user_segment(page, 0, PAGE_CACHE_SIZE); + } else { + err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); + if (err) { + f2fs_put_page(page, 1); + return err; + } + } + SetPageUptodate(page); + clear_cold_data(page); + return 0; +} + +static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, loff_t offset, unsigned long nr_segs) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; + + if (rw == WRITE) + return 0; + + /* Needs synchronization with the cleaner */ + return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, + get_data_block_ro); +} + +static void f2fs_invalidate_data_page(struct page *page, unsigned long offset) +{ + struct inode *inode = page->mapping->host; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + if (S_ISDIR(inode->i_mode) && PageDirty(page)) { + dec_page_count(sbi, F2FS_DIRTY_DENTS); + inode_dec_dirty_dents(inode); + } + ClearPagePrivate(page); +} + +static int f2fs_release_data_page(struct page *page, gfp_t wait) +{ + ClearPagePrivate(page); + return 0; +} + +static int f2fs_set_data_page_dirty(struct page *page) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + + SetPageUptodate(page); + if (!PageDirty(page)) { + __set_page_dirty_nobuffers(page); + set_dirty_dir_page(inode, page); + return 1; + } + return 0; +} + +const struct address_space_operations f2fs_dblock_aops = { + .readpage = f2fs_read_data_page, + .readpages = f2fs_read_data_pages, + .writepage = f2fs_write_data_page, + .writepages = f2fs_write_data_pages, + .write_begin = f2fs_write_begin, + .write_end = nobh_write_end, + .set_page_dirty = f2fs_set_data_page_dirty, + .invalidatepage = f2fs_invalidate_data_page, + .releasepage = f2fs_release_data_page, + .direct_IO = f2fs_direct_IO, +}; -- cgit v0.10.2 From 19f99cee206cd4fe2e84176001bfd0b8b9dd4b42 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:10:40 +0900 Subject: f2fs: add core inode operations This adds core functions to get, read, write, and evict an inode. Signed-off-by: Changman Lee Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c new file mode 100644 index 0000000..94f13d2 --- /dev/null +++ b/fs/f2fs/inode.c @@ -0,0 +1,266 @@ +/** + * fs/f2fs/inode.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include + +#include "f2fs.h" +#include "node.h" + +struct f2fs_iget_args { + u64 ino; + int on_free; +}; + +void f2fs_set_inode_flags(struct inode *inode) +{ + unsigned int flags = F2FS_I(inode)->i_flags; + + inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | + S_NOATIME | S_DIRSYNC); + + if (flags & FS_SYNC_FL) + inode->i_flags |= S_SYNC; + if (flags & FS_APPEND_FL) + inode->i_flags |= S_APPEND; + if (flags & FS_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & FS_NOATIME_FL) + inode->i_flags |= S_NOATIME; + if (flags & FS_DIRSYNC_FL) + inode->i_flags |= S_DIRSYNC; +} + +static int f2fs_iget_test(struct inode *inode, void *data) +{ + struct f2fs_iget_args *args = data; + + if (inode->i_ino != args->ino) + return 0; + if (inode->i_state & (I_FREEING | I_WILL_FREE)) { + args->on_free = 1; + return 0; + } + return 1; +} + +struct inode *f2fs_iget_nowait(struct super_block *sb, unsigned long ino) +{ + struct f2fs_iget_args args = { + .ino = ino, + .on_free = 0 + }; + struct inode *inode = ilookup5(sb, ino, f2fs_iget_test, &args); + + if (inode) + return inode; + if (!args.on_free) + return f2fs_iget(sb, ino); + return ERR_PTR(-ENOENT); +} + +static int do_read_inode(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_inode_info *fi = F2FS_I(inode); + struct page *node_page; + struct f2fs_node *rn; + struct f2fs_inode *ri; + + /* Check if ino is within scope */ + check_nid_range(sbi, inode->i_ino); + + node_page = get_node_page(sbi, inode->i_ino); + if (IS_ERR(node_page)) + return PTR_ERR(node_page); + + rn = page_address(node_page); + ri = &(rn->i); + + inode->i_mode = le16_to_cpu(ri->i_mode); + i_uid_write(inode, le32_to_cpu(ri->i_uid)); + i_gid_write(inode, le32_to_cpu(ri->i_gid)); + set_nlink(inode, le32_to_cpu(ri->i_links)); + inode->i_size = le64_to_cpu(ri->i_size); + inode->i_blocks = le64_to_cpu(ri->i_blocks); + + inode->i_atime.tv_sec = le64_to_cpu(ri->i_atime); + inode->i_ctime.tv_sec = le64_to_cpu(ri->i_ctime); + inode->i_mtime.tv_sec = le64_to_cpu(ri->i_mtime); + inode->i_atime.tv_nsec = le32_to_cpu(ri->i_atime_nsec); + inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec); + inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec); + inode->i_generation = le32_to_cpu(ri->i_generation); + + fi->i_current_depth = le32_to_cpu(ri->i_current_depth); + fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid); + fi->i_flags = le32_to_cpu(ri->i_flags); + fi->flags = 0; + fi->data_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver) - 1; + fi->i_advise = ri->i_advise; + get_extent_info(&fi->ext, ri->i_ext); + f2fs_put_page(node_page, 1); + return 0; +} + +struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) +{ + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct inode *inode; + int ret; + + inode = iget_locked(sb, ino); + if (!inode) + return ERR_PTR(-ENOMEM); + if (!(inode->i_state & I_NEW)) + return inode; + if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi)) + goto make_now; + + ret = do_read_inode(inode); + if (ret) + goto bad_inode; + + if (!sbi->por_doing && inode->i_nlink == 0) { + ret = -ENOENT; + goto bad_inode; + } + +make_now: + if (ino == F2FS_NODE_INO(sbi)) { + inode->i_mapping->a_ops = &f2fs_node_aops; + mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); + } else if (ino == F2FS_META_INO(sbi)) { + inode->i_mapping->a_ops = &f2fs_meta_aops; + mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); + } else if (S_ISREG(inode->i_mode)) { + inode->i_op = &f2fs_file_inode_operations; + inode->i_fop = &f2fs_file_operations; + inode->i_mapping->a_ops = &f2fs_dblock_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &f2fs_dir_inode_operations; + inode->i_fop = &f2fs_dir_operations; + inode->i_mapping->a_ops = &f2fs_dblock_aops; + mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER_MOVABLE | + __GFP_ZERO); + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &f2fs_symlink_inode_operations; + inode->i_mapping->a_ops = &f2fs_dblock_aops; + } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || + S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { + inode->i_op = &f2fs_special_inode_operations; + init_special_inode(inode, inode->i_mode, inode->i_rdev); + } else { + ret = -EIO; + goto bad_inode; + } + unlock_new_inode(inode); + + return inode; + +bad_inode: + iget_failed(inode); + return ERR_PTR(ret); +} + +void update_inode(struct inode *inode, struct page *node_page) +{ + struct f2fs_node *rn; + struct f2fs_inode *ri; + + wait_on_page_writeback(node_page); + + rn = page_address(node_page); + ri = &(rn->i); + + ri->i_mode = cpu_to_le16(inode->i_mode); + ri->i_advise = F2FS_I(inode)->i_advise; + ri->i_uid = cpu_to_le32(i_uid_read(inode)); + ri->i_gid = cpu_to_le32(i_gid_read(inode)); + ri->i_links = cpu_to_le32(inode->i_nlink); + ri->i_size = cpu_to_le64(i_size_read(inode)); + ri->i_blocks = cpu_to_le64(inode->i_blocks); + set_raw_extent(&F2FS_I(inode)->ext, &ri->i_ext); + + ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec); + ri->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); + ri->i_mtime = cpu_to_le64(inode->i_mtime.tv_sec); + ri->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); + ri->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); + ri->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); + ri->i_current_depth = cpu_to_le32(F2FS_I(inode)->i_current_depth); + ri->i_xattr_nid = cpu_to_le32(F2FS_I(inode)->i_xattr_nid); + ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags); + ri->i_generation = cpu_to_le32(inode->i_generation); + set_page_dirty(node_page); +} + +int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct page *node_page; + bool need_lock = false; + + if (inode->i_ino == F2FS_NODE_INO(sbi) || + inode->i_ino == F2FS_META_INO(sbi)) + return 0; + + node_page = get_node_page(sbi, inode->i_ino); + if (IS_ERR(node_page)) + return PTR_ERR(node_page); + + if (!PageDirty(node_page)) { + need_lock = true; + f2fs_put_page(node_page, 1); + mutex_lock(&sbi->write_inode); + node_page = get_node_page(sbi, inode->i_ino); + if (IS_ERR(node_page)) { + mutex_unlock(&sbi->write_inode); + return PTR_ERR(node_page); + } + } + update_inode(inode, node_page); + f2fs_put_page(node_page, 1); + if (need_lock) + mutex_unlock(&sbi->write_inode); + return 0; +} + +/** + * Called at the last iput() if i_nlink is zero + */ +void f2fs_evict_inode(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + + truncate_inode_pages(&inode->i_data, 0); + + if (inode->i_ino == F2FS_NODE_INO(sbi) || + inode->i_ino == F2FS_META_INO(sbi)) + goto no_delete; + + BUG_ON(atomic_read(&F2FS_I(inode)->dirty_dents)); + remove_dirty_dir_inode(inode); + + if (inode->i_nlink || is_bad_inode(inode)) + goto no_delete; + + set_inode_flag(F2FS_I(inode), FI_NO_ALLOC); + i_size_write(inode, 0); + + if (F2FS_HAS_BLOCKS(inode)) + f2fs_truncate(inode); + + remove_inode_page(inode); +no_delete: + clear_inode(inode); +} -- cgit v0.10.2 From 57397d86c62dfee7bf1d60c9960201c78a9c4ec2 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:11:10 +0900 Subject: f2fs: add inode operations for special inodes This adds inode operations for directory, symlink, and special inodes. Signed-off-by: Changman Lee Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c new file mode 100644 index 0000000..aec362f6 --- /dev/null +++ b/fs/f2fs/namei.c @@ -0,0 +1,504 @@ +/** + * fs/f2fs/namei.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "xattr.h" +#include "acl.h" + +static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) +{ + struct super_block *sb = dir->i_sb; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + nid_t ino; + struct inode *inode; + bool nid_free = false; + int err; + + inode = new_inode(sb); + if (!inode) + return ERR_PTR(-ENOMEM); + + mutex_lock_op(sbi, NODE_NEW); + if (!alloc_nid(sbi, &ino)) { + mutex_unlock_op(sbi, NODE_NEW); + err = -ENOSPC; + goto fail; + } + mutex_unlock_op(sbi, NODE_NEW); + + inode->i_uid = current_fsuid(); + + if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } else { + inode->i_gid = current_fsgid(); + } + + inode->i_ino = ino; + inode->i_mode = mode; + inode->i_blocks = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_generation = sbi->s_next_generation++; + + err = insert_inode_locked(inode); + if (err) { + err = -EINVAL; + nid_free = true; + goto out; + } + + mark_inode_dirty(inode); + return inode; + +out: + clear_nlink(inode); + unlock_new_inode(inode); +fail: + iput(inode); + if (nid_free) + alloc_nid_failed(sbi, ino); + return ERR_PTR(err); +} + +static int is_multimedia_file(const unsigned char *s, const char *sub) +{ + int slen = strlen(s); + int sublen = strlen(sub); + int ret; + + if (sublen > slen) + return 1; + + ret = memcmp(s + slen - sublen, sub, sublen); + if (ret) { /* compare upper case */ + int i; + char upper_sub[8]; + for (i = 0; i < sublen && i < sizeof(upper_sub); i++) + upper_sub[i] = toupper(sub[i]); + return memcmp(s + slen - sublen, upper_sub, sublen); + } + + return ret; +} + +/** + * Set multimedia files as cold files for hot/cold data separation + */ +static inline void set_cold_file(struct f2fs_sb_info *sbi, struct inode *inode, + const unsigned char *name) +{ + int i; + __u8 (*extlist)[8] = sbi->raw_super->extension_list; + + int count = le32_to_cpu(sbi->raw_super->extension_count); + for (i = 0; i < count; i++) { + if (!is_multimedia_file(name, extlist[i])) { + F2FS_I(inode)->i_advise |= FADVISE_COLD_BIT; + break; + } + } +} + +static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool excl) +{ + struct super_block *sb = dir->i_sb; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct inode *inode; + nid_t ino = 0; + int err; + + inode = f2fs_new_inode(dir, mode); + if (IS_ERR(inode)) + return PTR_ERR(inode); + + if (!test_opt(sbi, DISABLE_EXT_IDENTIFY)) + set_cold_file(sbi, inode, dentry->d_name.name); + + inode->i_op = &f2fs_file_inode_operations; + inode->i_fop = &f2fs_file_operations; + inode->i_mapping->a_ops = &f2fs_dblock_aops; + ino = inode->i_ino; + + err = f2fs_add_link(dentry, inode); + if (err) + goto out; + + alloc_nid_done(sbi, ino); + + if (!sbi->por_doing) + d_instantiate(dentry, inode); + unlock_new_inode(inode); + + f2fs_balance_fs(sbi); + return 0; +out: + clear_nlink(inode); + unlock_new_inode(inode); + iput(inode); + alloc_nid_failed(sbi, ino); + return err; +} + +static int f2fs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) +{ + struct inode *inode = old_dentry->d_inode; + struct super_block *sb = dir->i_sb; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + int err; + + inode->i_ctime = CURRENT_TIME; + atomic_inc(&inode->i_count); + + set_inode_flag(F2FS_I(inode), FI_INC_LINK); + err = f2fs_add_link(dentry, inode); + if (err) + goto out; + + d_instantiate(dentry, inode); + + f2fs_balance_fs(sbi); + return 0; +out: + clear_inode_flag(F2FS_I(inode), FI_INC_LINK); + iput(inode); + return err; +} + +struct dentry *f2fs_get_parent(struct dentry *child) +{ + struct qstr dotdot = QSTR_INIT("..", 2); + unsigned long ino = f2fs_inode_by_name(child->d_inode, &dotdot); + if (!ino) + return ERR_PTR(-ENOENT); + return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino)); +} + +static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + struct inode *inode = NULL; + struct f2fs_dir_entry *de; + struct page *page; + + if (dentry->d_name.len > F2FS_MAX_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + de = f2fs_find_entry(dir, &dentry->d_name, &page); + if (de) { + nid_t ino = le32_to_cpu(de->ino); + kunmap(page); + f2fs_put_page(page, 0); + + inode = f2fs_iget(dir->i_sb, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + } + + return d_splice_alias(inode, dentry); +} + +static int f2fs_unlink(struct inode *dir, struct dentry *dentry) +{ + struct super_block *sb = dir->i_sb; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct inode *inode = dentry->d_inode; + struct f2fs_dir_entry *de; + struct page *page; + int err = -ENOENT; + + de = f2fs_find_entry(dir, &dentry->d_name, &page); + if (!de) + goto fail; + + err = check_orphan_space(sbi); + if (err) { + kunmap(page); + f2fs_put_page(page, 0); + goto fail; + } + + f2fs_delete_entry(de, page, inode); + + /* In order to evict this inode, we set it dirty */ + mark_inode_dirty(inode); + f2fs_balance_fs(sbi); +fail: + return err; +} + +static int f2fs_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) +{ + struct super_block *sb = dir->i_sb; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct inode *inode; + unsigned symlen = strlen(symname) + 1; + int err; + + inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO); + if (IS_ERR(inode)) + return PTR_ERR(inode); + + inode->i_op = &f2fs_symlink_inode_operations; + inode->i_mapping->a_ops = &f2fs_dblock_aops; + + err = f2fs_add_link(dentry, inode); + if (err) + goto out; + + err = page_symlink(inode, symname, symlen); + alloc_nid_done(sbi, inode->i_ino); + + d_instantiate(dentry, inode); + unlock_new_inode(inode); + + f2fs_balance_fs(sbi); + + return err; +out: + clear_nlink(inode); + unlock_new_inode(inode); + iput(inode); + alloc_nid_failed(sbi, inode->i_ino); + return err; +} + +static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); + struct inode *inode; + int err; + + inode = f2fs_new_inode(dir, S_IFDIR | mode); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + return err; + + inode->i_op = &f2fs_dir_inode_operations; + inode->i_fop = &f2fs_dir_operations; + inode->i_mapping->a_ops = &f2fs_dblock_aops; + mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS | __GFP_ZERO); + + set_inode_flag(F2FS_I(inode), FI_INC_LINK); + err = f2fs_add_link(dentry, inode); + if (err) + goto out_fail; + + alloc_nid_done(sbi, inode->i_ino); + + d_instantiate(dentry, inode); + unlock_new_inode(inode); + + f2fs_balance_fs(sbi); + return 0; + +out_fail: + clear_inode_flag(F2FS_I(inode), FI_INC_LINK); + clear_nlink(inode); + unlock_new_inode(inode); + iput(inode); + alloc_nid_failed(sbi, inode->i_ino); + return err; +} + +static int f2fs_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + if (f2fs_empty_dir(inode)) + return f2fs_unlink(dir, dentry); + return -ENOTEMPTY; +} + +static int f2fs_mknod(struct inode *dir, struct dentry *dentry, + umode_t mode, dev_t rdev) +{ + struct super_block *sb = dir->i_sb; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct inode *inode; + int err = 0; + + if (!new_valid_dev(rdev)) + return -EINVAL; + + inode = f2fs_new_inode(dir, mode); + if (IS_ERR(inode)) + return PTR_ERR(inode); + + init_special_inode(inode, inode->i_mode, rdev); + inode->i_op = &f2fs_special_inode_operations; + + err = f2fs_add_link(dentry, inode); + if (err) + goto out; + + alloc_nid_done(sbi, inode->i_ino); + d_instantiate(dentry, inode); + unlock_new_inode(inode); + + f2fs_balance_fs(sbi); + + return 0; +out: + clear_nlink(inode); + unlock_new_inode(inode); + iput(inode); + alloc_nid_failed(sbi, inode->i_ino); + return err; +} + +static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct super_block *sb = old_dir->i_sb; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct inode *old_inode = old_dentry->d_inode; + struct inode *new_inode = new_dentry->d_inode; + struct page *old_dir_page; + struct page *old_page; + struct f2fs_dir_entry *old_dir_entry = NULL; + struct f2fs_dir_entry *old_entry; + struct f2fs_dir_entry *new_entry; + int err = -ENOENT; + + old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); + if (!old_entry) + goto out; + + if (S_ISDIR(old_inode->i_mode)) { + err = -EIO; + old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page); + if (!old_dir_entry) + goto out_old; + } + + mutex_lock_op(sbi, RENAME); + + if (new_inode) { + struct page *new_page; + + err = -ENOTEMPTY; + if (old_dir_entry && !f2fs_empty_dir(new_inode)) + goto out_dir; + + err = -ENOENT; + new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, + &new_page); + if (!new_entry) + goto out_dir; + + f2fs_set_link(new_dir, new_entry, new_page, old_inode); + + new_inode->i_ctime = CURRENT_TIME; + if (old_dir_entry) + drop_nlink(new_inode); + drop_nlink(new_inode); + if (!new_inode->i_nlink) + add_orphan_inode(sbi, new_inode->i_ino); + f2fs_write_inode(new_inode, NULL); + } else { + err = f2fs_add_link(new_dentry, old_inode); + if (err) + goto out_dir; + + if (old_dir_entry) { + inc_nlink(new_dir); + f2fs_write_inode(new_dir, NULL); + } + } + + old_inode->i_ctime = CURRENT_TIME; + set_inode_flag(F2FS_I(old_inode), FI_NEED_CP); + mark_inode_dirty(old_inode); + + f2fs_delete_entry(old_entry, old_page, NULL); + + if (old_dir_entry) { + if (old_dir != new_dir) { + f2fs_set_link(old_inode, old_dir_entry, + old_dir_page, new_dir); + } else { + kunmap(old_dir_page); + f2fs_put_page(old_dir_page, 0); + } + drop_nlink(old_dir); + f2fs_write_inode(old_dir, NULL); + } + + mutex_unlock_op(sbi, RENAME); + + f2fs_balance_fs(sbi); + return 0; + +out_dir: + if (old_dir_entry) { + kunmap(old_dir_page); + f2fs_put_page(old_dir_page, 0); + } + mutex_unlock_op(sbi, RENAME); +out_old: + kunmap(old_page); + f2fs_put_page(old_page, 0); +out: + return err; +} + +const struct inode_operations f2fs_dir_inode_operations = { + .create = f2fs_create, + .lookup = f2fs_lookup, + .link = f2fs_link, + .unlink = f2fs_unlink, + .symlink = f2fs_symlink, + .mkdir = f2fs_mkdir, + .rmdir = f2fs_rmdir, + .mknod = f2fs_mknod, + .rename = f2fs_rename, + .setattr = f2fs_setattr, + .get_acl = f2fs_get_acl, +#ifdef CONFIG_F2FS_FS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = f2fs_listxattr, + .removexattr = generic_removexattr, +#endif +}; + +const struct inode_operations f2fs_symlink_inode_operations = { + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, + .setattr = f2fs_setattr, +#ifdef CONFIG_F2FS_FS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = f2fs_listxattr, + .removexattr = generic_removexattr, +#endif +}; + +const struct inode_operations f2fs_special_inode_operations = { + .setattr = f2fs_setattr, + .get_acl = f2fs_get_acl, +#ifdef CONFIG_F2FS_FS_XATTR + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = f2fs_listxattr, + .removexattr = generic_removexattr, +#endif +}; -- cgit v0.10.2 From 6b4ea0160ae236a6561defa28e19f973aedda9ff Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 14 Nov 2012 16:59:04 +0900 Subject: f2fs: add core directory operations this adds core functions to find, add, delete, and link dentries. Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c new file mode 100644 index 0000000..5975568 --- /dev/null +++ b/fs/f2fs/dir.c @@ -0,0 +1,672 @@ +/** + * fs/f2fs/dir.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include "f2fs.h" +#include "acl.h" + +static unsigned long dir_blocks(struct inode *inode) +{ + return ((unsigned long long) (i_size_read(inode) + PAGE_CACHE_SIZE - 1)) + >> PAGE_CACHE_SHIFT; +} + +static unsigned int dir_buckets(unsigned int level) +{ + if (level < MAX_DIR_HASH_DEPTH / 2) + return 1 << level; + else + return 1 << ((MAX_DIR_HASH_DEPTH / 2) - 1); +} + +static unsigned int bucket_blocks(unsigned int level) +{ + if (level < MAX_DIR_HASH_DEPTH / 2) + return 2; + else + return 4; +} + +static unsigned char f2fs_filetype_table[F2FS_FT_MAX] = { + [F2FS_FT_UNKNOWN] = DT_UNKNOWN, + [F2FS_FT_REG_FILE] = DT_REG, + [F2FS_FT_DIR] = DT_DIR, + [F2FS_FT_CHRDEV] = DT_CHR, + [F2FS_FT_BLKDEV] = DT_BLK, + [F2FS_FT_FIFO] = DT_FIFO, + [F2FS_FT_SOCK] = DT_SOCK, + [F2FS_FT_SYMLINK] = DT_LNK, +}; + +#define S_SHIFT 12 +static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = { + [S_IFREG >> S_SHIFT] = F2FS_FT_REG_FILE, + [S_IFDIR >> S_SHIFT] = F2FS_FT_DIR, + [S_IFCHR >> S_SHIFT] = F2FS_FT_CHRDEV, + [S_IFBLK >> S_SHIFT] = F2FS_FT_BLKDEV, + [S_IFIFO >> S_SHIFT] = F2FS_FT_FIFO, + [S_IFSOCK >> S_SHIFT] = F2FS_FT_SOCK, + [S_IFLNK >> S_SHIFT] = F2FS_FT_SYMLINK, +}; + +static void set_de_type(struct f2fs_dir_entry *de, struct inode *inode) +{ + mode_t mode = inode->i_mode; + de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; +} + +static unsigned long dir_block_index(unsigned int level, unsigned int idx) +{ + unsigned long i; + unsigned long bidx = 0; + + for (i = 0; i < level; i++) + bidx += dir_buckets(i) * bucket_blocks(i); + bidx += idx * bucket_blocks(level); + return bidx; +} + +static bool early_match_name(const char *name, int namelen, + f2fs_hash_t namehash, struct f2fs_dir_entry *de) +{ + if (le16_to_cpu(de->name_len) != namelen) + return false; + + if (le32_to_cpu(de->hash_code) != namehash) + return false; + + return true; +} + +static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, + const char *name, int namelen, int *max_slots, + f2fs_hash_t namehash, struct page **res_page) +{ + struct f2fs_dir_entry *de; + unsigned long bit_pos, end_pos, next_pos; + struct f2fs_dentry_block *dentry_blk = kmap(dentry_page); + int slots; + + bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, + NR_DENTRY_IN_BLOCK, 0); + while (bit_pos < NR_DENTRY_IN_BLOCK) { + de = &dentry_blk->dentry[bit_pos]; + slots = (le16_to_cpu(de->name_len) + F2FS_NAME_LEN - 1) / + F2FS_NAME_LEN; + + if (early_match_name(name, namelen, namehash, de)) { + if (!memcmp(dentry_blk->filename[bit_pos], + name, namelen)) { + *res_page = dentry_page; + goto found; + } + } + next_pos = bit_pos + slots; + bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, + NR_DENTRY_IN_BLOCK, next_pos); + if (bit_pos >= NR_DENTRY_IN_BLOCK) + end_pos = NR_DENTRY_IN_BLOCK; + else + end_pos = bit_pos; + if (*max_slots < end_pos - next_pos) + *max_slots = end_pos - next_pos; + } + + de = NULL; + kunmap(dentry_page); +found: + return de; +} + +static struct f2fs_dir_entry *find_in_level(struct inode *dir, + unsigned int level, const char *name, int namelen, + f2fs_hash_t namehash, struct page **res_page) +{ + int s = (namelen + F2FS_NAME_LEN - 1) / F2FS_NAME_LEN; + unsigned int nbucket, nblock; + unsigned int bidx, end_block; + struct page *dentry_page; + struct f2fs_dir_entry *de = NULL; + bool room = false; + int max_slots = 0; + + BUG_ON(level > MAX_DIR_HASH_DEPTH); + + nbucket = dir_buckets(level); + nblock = bucket_blocks(level); + + bidx = dir_block_index(level, namehash % nbucket); + end_block = bidx + nblock; + + for (; bidx < end_block; bidx++) { + /* no need to allocate new dentry pages to all the indices */ + dentry_page = find_data_page(dir, bidx); + if (IS_ERR(dentry_page)) { + room = true; + continue; + } + + de = find_in_block(dentry_page, name, namelen, + &max_slots, namehash, res_page); + if (de) + break; + + if (max_slots >= s) + room = true; + f2fs_put_page(dentry_page, 0); + } + + if (!de && room && F2FS_I(dir)->chash != namehash) { + F2FS_I(dir)->chash = namehash; + F2FS_I(dir)->clevel = level; + } + + return de; +} + +/* + * Find an entry in the specified directory with the wanted name. + * It returns the page where the entry was found (as a parameter - res_page), + * and the entry itself. Page is returned mapped and unlocked. + * Entry is guaranteed to be valid. + */ +struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, + struct qstr *child, struct page **res_page) +{ + const char *name = child->name; + int namelen = child->len; + unsigned long npages = dir_blocks(dir); + struct f2fs_dir_entry *de = NULL; + f2fs_hash_t name_hash; + unsigned int max_depth; + unsigned int level; + + if (npages == 0) + return NULL; + + *res_page = NULL; + + name_hash = f2fs_dentry_hash(name, namelen); + max_depth = F2FS_I(dir)->i_current_depth; + + for (level = 0; level < max_depth; level++) { + de = find_in_level(dir, level, name, + namelen, name_hash, res_page); + if (de) + break; + } + if (!de && F2FS_I(dir)->chash != name_hash) { + F2FS_I(dir)->chash = name_hash; + F2FS_I(dir)->clevel = level - 1; + } + return de; +} + +struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p) +{ + struct page *page = NULL; + struct f2fs_dir_entry *de = NULL; + struct f2fs_dentry_block *dentry_blk = NULL; + + page = get_lock_data_page(dir, 0); + if (IS_ERR(page)) + return NULL; + + dentry_blk = kmap(page); + de = &dentry_blk->dentry[1]; + *p = page; + unlock_page(page); + return de; +} + +ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr) +{ + ino_t res = 0; + struct f2fs_dir_entry *de; + struct page *page; + + de = f2fs_find_entry(dir, qstr, &page); + if (de) { + res = le32_to_cpu(de->ino); + kunmap(page); + f2fs_put_page(page, 0); + } + + return res; +} + +void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, + struct page *page, struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); + + mutex_lock_op(sbi, DENTRY_OPS); + lock_page(page); + wait_on_page_writeback(page); + de->ino = cpu_to_le32(inode->i_ino); + set_de_type(de, inode); + kunmap(page); + set_page_dirty(page); + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + mark_inode_dirty(dir); + f2fs_put_page(page, 1); + mutex_unlock_op(sbi, DENTRY_OPS); +} + +void init_dent_inode(struct dentry *dentry, struct page *ipage) +{ + struct inode *dir = dentry->d_parent->d_inode; + struct f2fs_node *rn; + + if (IS_ERR(ipage)) + return; + + wait_on_page_writeback(ipage); + + /* copy dentry info. to this inode page */ + rn = (struct f2fs_node *)page_address(ipage); + rn->i.i_pino = cpu_to_le32(dir->i_ino); + rn->i.i_namelen = cpu_to_le32(dentry->d_name.len); + memcpy(rn->i.i_name, dentry->d_name.name, dentry->d_name.len); + set_page_dirty(ipage); +} + +static int init_inode_metadata(struct inode *inode, struct dentry *dentry) +{ + struct inode *dir = dentry->d_parent->d_inode; + + if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { + int err; + err = new_inode_page(inode, dentry); + if (err) + return err; + + if (S_ISDIR(inode->i_mode)) { + err = f2fs_make_empty(inode, dir); + if (err) { + remove_inode_page(inode); + return err; + } + } + + err = f2fs_init_acl(inode, dir); + if (err) { + remove_inode_page(inode); + return err; + } + } else { + struct page *ipage; + ipage = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino); + if (IS_ERR(ipage)) + return PTR_ERR(ipage); + init_dent_inode(dentry, ipage); + f2fs_put_page(ipage, 1); + } + if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) { + inc_nlink(inode); + f2fs_write_inode(inode, NULL); + } + return 0; +} + +static void update_parent_metadata(struct inode *dir, struct inode *inode, + unsigned int current_depth) +{ + bool need_dir_update = false; + + if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { + if (S_ISDIR(inode->i_mode)) { + inc_nlink(dir); + need_dir_update = true; + } + clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); + } + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + if (F2FS_I(dir)->i_current_depth != current_depth) { + F2FS_I(dir)->i_current_depth = current_depth; + need_dir_update = true; + } + + if (need_dir_update) + f2fs_write_inode(dir, NULL); + else + mark_inode_dirty(dir); + + if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) + clear_inode_flag(F2FS_I(inode), FI_INC_LINK); +} + +static int room_for_filename(struct f2fs_dentry_block *dentry_blk, int slots) +{ + int bit_start = 0; + int zero_start, zero_end; +next: + zero_start = find_next_zero_bit_le(&dentry_blk->dentry_bitmap, + NR_DENTRY_IN_BLOCK, + bit_start); + if (zero_start >= NR_DENTRY_IN_BLOCK) + return NR_DENTRY_IN_BLOCK; + + zero_end = find_next_bit_le(&dentry_blk->dentry_bitmap, + NR_DENTRY_IN_BLOCK, + zero_start); + if (zero_end - zero_start >= slots) + return zero_start; + + bit_start = zero_end + 1; + + if (zero_end + 1 >= NR_DENTRY_IN_BLOCK) + return NR_DENTRY_IN_BLOCK; + goto next; +} + +int f2fs_add_link(struct dentry *dentry, struct inode *inode) +{ + unsigned int bit_pos; + unsigned int level; + unsigned int current_depth; + unsigned long bidx, block; + f2fs_hash_t dentry_hash; + struct f2fs_dir_entry *de; + unsigned int nbucket, nblock; + struct inode *dir = dentry->d_parent->d_inode; + struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; + struct page *dentry_page = NULL; + struct f2fs_dentry_block *dentry_blk = NULL; + int slots = (namelen + F2FS_NAME_LEN - 1) / F2FS_NAME_LEN; + int err = 0; + int i; + + dentry_hash = f2fs_dentry_hash(name, dentry->d_name.len); + level = 0; + current_depth = F2FS_I(dir)->i_current_depth; + if (F2FS_I(dir)->chash == dentry_hash) { + level = F2FS_I(dir)->clevel; + F2FS_I(dir)->chash = 0; + } + +start: + if (current_depth == MAX_DIR_HASH_DEPTH) + return -ENOSPC; + + /* Increase the depth, if required */ + if (level == current_depth) + ++current_depth; + + nbucket = dir_buckets(level); + nblock = bucket_blocks(level); + + bidx = dir_block_index(level, (dentry_hash % nbucket)); + + for (block = bidx; block <= (bidx + nblock - 1); block++) { + mutex_lock_op(sbi, DENTRY_OPS); + dentry_page = get_new_data_page(dir, block, true); + if (IS_ERR(dentry_page)) { + mutex_unlock_op(sbi, DENTRY_OPS); + return PTR_ERR(dentry_page); + } + + dentry_blk = kmap(dentry_page); + bit_pos = room_for_filename(dentry_blk, slots); + if (bit_pos < NR_DENTRY_IN_BLOCK) + goto add_dentry; + + kunmap(dentry_page); + f2fs_put_page(dentry_page, 1); + mutex_unlock_op(sbi, DENTRY_OPS); + } + + /* Move to next level to find the empty slot for new dentry */ + ++level; + goto start; +add_dentry: + err = init_inode_metadata(inode, dentry); + if (err) + goto fail; + + wait_on_page_writeback(dentry_page); + + de = &dentry_blk->dentry[bit_pos]; + de->hash_code = cpu_to_le32(dentry_hash); + de->name_len = cpu_to_le16(namelen); + memcpy(dentry_blk->filename[bit_pos], name, namelen); + de->ino = cpu_to_le32(inode->i_ino); + set_de_type(de, inode); + for (i = 0; i < slots; i++) + test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); + set_page_dirty(dentry_page); + update_parent_metadata(dir, inode, current_depth); +fail: + kunmap(dentry_page); + f2fs_put_page(dentry_page, 1); + mutex_unlock_op(sbi, DENTRY_OPS); + return err; +} + +/** + * It only removes the dentry from the dentry page,corresponding name + * entry in name page does not need to be touched during deletion. + */ +void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, + struct inode *inode) +{ + struct f2fs_dentry_block *dentry_blk; + unsigned int bit_pos; + struct address_space *mapping = page->mapping; + struct inode *dir = mapping->host; + struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); + int slots = (le16_to_cpu(dentry->name_len) + F2FS_NAME_LEN - 1) / + F2FS_NAME_LEN; + void *kaddr = page_address(page); + int i; + + mutex_lock_op(sbi, DENTRY_OPS); + + lock_page(page); + wait_on_page_writeback(page); + + dentry_blk = (struct f2fs_dentry_block *)kaddr; + bit_pos = dentry - (struct f2fs_dir_entry *)dentry_blk->dentry; + for (i = 0; i < slots; i++) + test_and_clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); + + /* Let's check and deallocate this dentry page */ + bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, + NR_DENTRY_IN_BLOCK, + 0); + kunmap(page); /* kunmap - pair of f2fs_find_entry */ + set_page_dirty(page); + + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + + if (inode && S_ISDIR(inode->i_mode)) { + drop_nlink(dir); + f2fs_write_inode(dir, NULL); + } else { + mark_inode_dirty(dir); + } + + if (inode) { + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + drop_nlink(inode); + if (S_ISDIR(inode->i_mode)) { + drop_nlink(inode); + i_size_write(inode, 0); + } + f2fs_write_inode(inode, NULL); + if (inode->i_nlink == 0) + add_orphan_inode(sbi, inode->i_ino); + } + + if (bit_pos == NR_DENTRY_IN_BLOCK) { + loff_t page_offset; + truncate_hole(dir, page->index, page->index + 1); + clear_page_dirty_for_io(page); + ClearPageUptodate(page); + dec_page_count(sbi, F2FS_DIRTY_DENTS); + inode_dec_dirty_dents(dir); + page_offset = page->index << PAGE_CACHE_SHIFT; + f2fs_put_page(page, 1); + } else { + f2fs_put_page(page, 1); + } + mutex_unlock_op(sbi, DENTRY_OPS); +} + +int f2fs_make_empty(struct inode *inode, struct inode *parent) +{ + struct page *dentry_page; + struct f2fs_dentry_block *dentry_blk; + struct f2fs_dir_entry *de; + void *kaddr; + + dentry_page = get_new_data_page(inode, 0, true); + if (IS_ERR(dentry_page)) + return PTR_ERR(dentry_page); + + kaddr = kmap_atomic(dentry_page); + dentry_blk = (struct f2fs_dentry_block *)kaddr; + + de = &dentry_blk->dentry[0]; + de->name_len = cpu_to_le16(1); + de->hash_code = 0; + de->ino = cpu_to_le32(inode->i_ino); + memcpy(dentry_blk->filename[0], ".", 1); + set_de_type(de, inode); + + de = &dentry_blk->dentry[1]; + de->hash_code = 0; + de->name_len = cpu_to_le16(2); + de->ino = cpu_to_le32(parent->i_ino); + memcpy(dentry_blk->filename[1], "..", 2); + set_de_type(de, inode); + + test_and_set_bit_le(0, &dentry_blk->dentry_bitmap); + test_and_set_bit_le(1, &dentry_blk->dentry_bitmap); + kunmap_atomic(kaddr); + + set_page_dirty(dentry_page); + f2fs_put_page(dentry_page, 1); + return 0; +} + +bool f2fs_empty_dir(struct inode *dir) +{ + unsigned long bidx; + struct page *dentry_page; + unsigned int bit_pos; + struct f2fs_dentry_block *dentry_blk; + unsigned long nblock = dir_blocks(dir); + + for (bidx = 0; bidx < nblock; bidx++) { + void *kaddr; + dentry_page = get_lock_data_page(dir, bidx); + if (IS_ERR(dentry_page)) { + if (PTR_ERR(dentry_page) == -ENOENT) + continue; + else + return false; + } + + kaddr = kmap_atomic(dentry_page); + dentry_blk = (struct f2fs_dentry_block *)kaddr; + if (bidx == 0) + bit_pos = 2; + else + bit_pos = 0; + bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, + NR_DENTRY_IN_BLOCK, + bit_pos); + kunmap_atomic(kaddr); + + f2fs_put_page(dentry_page, 1); + + if (bit_pos < NR_DENTRY_IN_BLOCK) + return false; + } + return true; +} + +static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + unsigned long pos = file->f_pos; + struct inode *inode = file->f_dentry->d_inode; + unsigned long npages = dir_blocks(inode); + unsigned char *types = NULL; + unsigned int bit_pos = 0, start_bit_pos = 0; + int over = 0; + struct f2fs_dentry_block *dentry_blk = NULL; + struct f2fs_dir_entry *de = NULL; + struct page *dentry_page = NULL; + unsigned int n = 0; + unsigned char d_type = DT_UNKNOWN; + int slots; + + types = f2fs_filetype_table; + bit_pos = (pos % NR_DENTRY_IN_BLOCK); + n = (pos / NR_DENTRY_IN_BLOCK); + + for ( ; n < npages; n++) { + dentry_page = get_lock_data_page(inode, n); + if (IS_ERR(dentry_page)) + continue; + + start_bit_pos = bit_pos; + dentry_blk = kmap(dentry_page); + while (bit_pos < NR_DENTRY_IN_BLOCK) { + d_type = DT_UNKNOWN; + bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, + NR_DENTRY_IN_BLOCK, + bit_pos); + if (bit_pos >= NR_DENTRY_IN_BLOCK) + break; + + de = &dentry_blk->dentry[bit_pos]; + if (types && de->file_type < F2FS_FT_MAX) + d_type = types[de->file_type]; + + over = filldir(dirent, + dentry_blk->filename[bit_pos], + le16_to_cpu(de->name_len), + (n * NR_DENTRY_IN_BLOCK) + bit_pos, + le32_to_cpu(de->ino), d_type); + if (over) { + file->f_pos += bit_pos - start_bit_pos; + goto success; + } + slots = (le16_to_cpu(de->name_len) + F2FS_NAME_LEN - 1) + / F2FS_NAME_LEN; + bit_pos += slots; + } + bit_pos = 0; + file->f_pos = (n + 1) * NR_DENTRY_IN_BLOCK; + kunmap(dentry_page); + f2fs_put_page(dentry_page, 1); + dentry_page = NULL; + } +success: + if (dentry_page && !IS_ERR(dentry_page)) { + kunmap(dentry_page); + f2fs_put_page(dentry_page, 1); + } + + return 0; +} + +const struct file_operations f2fs_dir_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .readdir = f2fs_readdir, + .fsync = f2fs_sync_file, + .unlocked_ioctl = f2fs_ioctl, +}; diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c new file mode 100644 index 0000000..098a196 --- /dev/null +++ b/fs/f2fs/hash.c @@ -0,0 +1,98 @@ +/** + * fs/f2fs/hash.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Portions of this code from linux/fs/ext3/hash.c + * + * Copyright (C) 2002 by Theodore Ts'o + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include "f2fs.h" + +/* + * Hashing code copied from ext3 + */ +#define DELTA 0x9E3779B9 + +static void TEA_transform(unsigned int buf[4], unsigned int const in[]) +{ + __u32 sum = 0; + __u32 b0 = buf[0], b1 = buf[1]; + __u32 a = in[0], b = in[1], c = in[2], d = in[3]; + int n = 16; + + do { + sum += DELTA; + b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); + b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); + } while (--n); + + buf[0] += b0; + buf[1] += b1; +} + +static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num) +{ + unsigned pad, val; + int i; + + pad = (__u32)len | ((__u32)len << 8); + pad |= pad << 16; + + val = pad; + if (len > num * 4) + len = num * 4; + for (i = 0; i < len; i++) { + if ((i % 4) == 0) + val = pad; + val = msg[i] + (val << 8); + if ((i % 4) == 3) { + *buf++ = val; + val = pad; + num--; + } + } + if (--num >= 0) + *buf++ = val; + while (--num >= 0) + *buf++ = pad; +} + +f2fs_hash_t f2fs_dentry_hash(const char *name, int len) +{ + __u32 hash, minor_hash; + f2fs_hash_t f2fs_hash; + const char *p; + __u32 in[8], buf[4]; + + /* Initialize the default seed for the hash checksum functions */ + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + + p = name; + while (len > 0) { + str2hashbuf(p, len, in, 4); + TEA_transform(buf, in); + len -= 16; + p += 16; + } + hash = buf[0]; + minor_hash = buf[1]; + + f2fs_hash = hash; + f2fs_hash &= ~F2FS_HASH_COL_BIT; + return f2fs_hash; +} -- cgit v0.10.2 From af48b85b8cd3fbb12c9b6759c16db6d69c0b03da Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:12:17 +0900 Subject: f2fs: add xattr and acl functionalities This implements xattr and acl functionalities. - F2FS uses a node page to contain use extended attributes. Signed-off-by: Changman Lee Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c new file mode 100644 index 0000000..dff2a2b --- /dev/null +++ b/fs/f2fs/acl.c @@ -0,0 +1,465 @@ +/** + * fs/f2fs/acl.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Portions of this code from linux/fs/ext2/acl.c + * + * Copyright (C) 2001-2003 Andreas Gruenbacher, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include "f2fs.h" +#include "xattr.h" +#include "acl.h" + +#define get_inode_mode(i) ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ + (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) + +static inline size_t f2fs_acl_size(int count) +{ + if (count <= 4) { + return sizeof(struct f2fs_acl_header) + + count * sizeof(struct f2fs_acl_entry_short); + } else { + return sizeof(struct f2fs_acl_header) + + 4 * sizeof(struct f2fs_acl_entry_short) + + (count - 4) * sizeof(struct f2fs_acl_entry); + } +} + +static inline int f2fs_acl_count(size_t size) +{ + ssize_t s; + size -= sizeof(struct f2fs_acl_header); + s = size - 4 * sizeof(struct f2fs_acl_entry_short); + if (s < 0) { + if (size % sizeof(struct f2fs_acl_entry_short)) + return -1; + return size / sizeof(struct f2fs_acl_entry_short); + } else { + if (s % sizeof(struct f2fs_acl_entry)) + return -1; + return s / sizeof(struct f2fs_acl_entry) + 4; + } +} + +static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size) +{ + int i, count; + struct posix_acl *acl; + struct f2fs_acl_header *hdr = (struct f2fs_acl_header *)value; + struct f2fs_acl_entry *entry = (struct f2fs_acl_entry *)(hdr + 1); + const char *end = value + size; + + if (hdr->a_version != cpu_to_le32(F2FS_ACL_VERSION)) + return ERR_PTR(-EINVAL); + + count = f2fs_acl_count(size); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + + acl = posix_acl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < count; i++) { + + if ((char *)entry > end) + goto fail; + + acl->a_entries[i].e_tag = le16_to_cpu(entry->e_tag); + acl->a_entries[i].e_perm = le16_to_cpu(entry->e_perm); + + switch (acl->a_entries[i].e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + acl->a_entries[i].e_id = ACL_UNDEFINED_ID; + entry = (struct f2fs_acl_entry *)((char *)entry + + sizeof(struct f2fs_acl_entry_short)); + break; + + case ACL_USER: + acl->a_entries[i].e_uid = + make_kuid(&init_user_ns, + le32_to_cpu(entry->e_id)); + entry = (struct f2fs_acl_entry *)((char *)entry + + sizeof(struct f2fs_acl_entry)); + break; + case ACL_GROUP: + acl->a_entries[i].e_gid = + make_kgid(&init_user_ns, + le32_to_cpu(entry->e_id)); + entry = (struct f2fs_acl_entry *)((char *)entry + + sizeof(struct f2fs_acl_entry)); + break; + default: + goto fail; + } + } + if ((char *)entry != end) + goto fail; + return acl; +fail: + posix_acl_release(acl); + return ERR_PTR(-EINVAL); +} + +static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size) +{ + struct f2fs_acl_header *f2fs_acl; + struct f2fs_acl_entry *entry; + int i; + + f2fs_acl = kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count * + sizeof(struct f2fs_acl_entry), GFP_KERNEL); + if (!f2fs_acl) + return ERR_PTR(-ENOMEM); + + f2fs_acl->a_version = cpu_to_le32(F2FS_ACL_VERSION); + entry = (struct f2fs_acl_entry *)(f2fs_acl + 1); + + for (i = 0; i < acl->a_count; i++) { + + entry->e_tag = cpu_to_le16(acl->a_entries[i].e_tag); + entry->e_perm = cpu_to_le16(acl->a_entries[i].e_perm); + + switch (acl->a_entries[i].e_tag) { + case ACL_USER: + entry->e_id = cpu_to_le32( + from_kuid(&init_user_ns, + acl->a_entries[i].e_uid)); + entry = (struct f2fs_acl_entry *)((char *)entry + + sizeof(struct f2fs_acl_entry)); + break; + case ACL_GROUP: + entry->e_id = cpu_to_le32( + from_kgid(&init_user_ns, + acl->a_entries[i].e_gid)); + entry = (struct f2fs_acl_entry *)((char *)entry + + sizeof(struct f2fs_acl_entry)); + break; + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + entry = (struct f2fs_acl_entry *)((char *)entry + + sizeof(struct f2fs_acl_entry_short)); + break; + default: + goto fail; + } + } + *size = f2fs_acl_size(acl->a_count); + return (void *)f2fs_acl; + +fail: + kfree(f2fs_acl); + return ERR_PTR(-EINVAL); +} + +struct posix_acl *f2fs_get_acl(struct inode *inode, int type) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; + void *value = NULL; + struct posix_acl *acl; + int retval; + + if (!test_opt(sbi, POSIX_ACL)) + return NULL; + + acl = get_cached_acl(inode, type); + if (acl != ACL_NOT_CACHED) + return acl; + + if (type == ACL_TYPE_ACCESS) + name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; + + retval = f2fs_getxattr(inode, name_index, "", NULL, 0); + if (retval > 0) { + value = kmalloc(retval, GFP_KERNEL); + if (!value) + return ERR_PTR(-ENOMEM); + retval = f2fs_getxattr(inode, name_index, "", value, retval); + } + + if (retval < 0) { + if (retval == -ENODATA) + acl = NULL; + else + acl = ERR_PTR(retval); + } else { + acl = f2fs_acl_from_disk(value, retval); + } + kfree(value); + if (!IS_ERR(acl)) + set_cached_acl(inode, type, acl); + + return acl; +} + +static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_inode_info *fi = F2FS_I(inode); + int name_index; + void *value = NULL; + size_t size = 0; + int error; + + if (!test_opt(sbi, POSIX_ACL)) + return 0; + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + + switch (type) { + case ACL_TYPE_ACCESS: + name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; + if (acl) { + error = posix_acl_equiv_mode(acl, &inode->i_mode); + if (error < 0) + return error; + set_acl_inode(fi, inode->i_mode); + if (error == 0) + acl = NULL; + } + break; + + case ACL_TYPE_DEFAULT: + name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; + if (!S_ISDIR(inode->i_mode)) + return acl ? -EACCES : 0; + break; + + default: + return -EINVAL; + } + + if (acl) { + value = f2fs_acl_to_disk(acl, &size); + if (IS_ERR(value)) { + cond_clear_inode_flag(fi, FI_ACL_MODE); + return (int)PTR_ERR(value); + } + } + + error = f2fs_setxattr(inode, name_index, "", value, size); + + kfree(value); + if (!error) + set_cached_acl(inode, type, acl); + + cond_clear_inode_flag(fi, FI_ACL_MODE); + return error; +} + +int f2fs_init_acl(struct inode *inode, struct inode *dir) +{ + struct posix_acl *acl = NULL; + struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); + int error = 0; + + if (!S_ISLNK(inode->i_mode)) { + if (test_opt(sbi, POSIX_ACL)) { + acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT); + if (IS_ERR(acl)) + return PTR_ERR(acl); + } + if (!acl) + inode->i_mode &= ~current_umask(); + } + + if (test_opt(sbi, POSIX_ACL) && acl) { + + if (S_ISDIR(inode->i_mode)) { + error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl); + if (error) + goto cleanup; + } + error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); + if (error < 0) + return error; + if (error > 0) + error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); + } +cleanup: + posix_acl_release(acl); + return error; +} + +int f2fs_acl_chmod(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct posix_acl *acl; + int error; + mode_t mode = get_inode_mode(inode); + + if (!test_opt(sbi, POSIX_ACL)) + return 0; + if (S_ISLNK(mode)) + return -EOPNOTSUPP; + + acl = f2fs_get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(acl) || !acl) + return PTR_ERR(acl); + + error = posix_acl_chmod(&acl, GFP_KERNEL, mode); + if (error) + return error; + error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); + posix_acl_release(acl); + return error; +} + +static size_t f2fs_xattr_list_acl(struct dentry *dentry, char *list, + size_t list_size, const char *name, size_t name_len, int type) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); + const char *xname = POSIX_ACL_XATTR_DEFAULT; + size_t size; + + if (!test_opt(sbi, POSIX_ACL)) + return 0; + + if (type == ACL_TYPE_ACCESS) + xname = POSIX_ACL_XATTR_ACCESS; + + size = strlen(xname) + 1; + if (list && size <= list_size) + memcpy(list, xname, size); + return size; +} + +static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name, + void *buffer, size_t size, int type) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); + struct posix_acl *acl; + int error; + + if (strcmp(name, "") != 0) + return -EINVAL; + if (!test_opt(sbi, POSIX_ACL)) + return -EOPNOTSUPP; + + acl = f2fs_get_acl(dentry->d_inode, type); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (!acl) + return -ENODATA; + error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); + posix_acl_release(acl); + + return error; +} + +static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, int type) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); + struct inode *inode = dentry->d_inode; + struct posix_acl *acl = NULL; + int error; + + if (strcmp(name, "") != 0) + return -EINVAL; + if (!test_opt(sbi, POSIX_ACL)) + return -EOPNOTSUPP; + if (!inode_owner_or_capable(inode)) + return -EPERM; + + if (value) { + acl = posix_acl_from_xattr(&init_user_ns, value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { + error = posix_acl_valid(acl); + if (error) + goto release_and_out; + } + } else { + acl = NULL; + } + + error = f2fs_set_acl(inode, type, acl); + +release_and_out: + posix_acl_release(acl); + return error; +} + +const struct xattr_handler f2fs_xattr_acl_default_handler = { + .prefix = POSIX_ACL_XATTR_DEFAULT, + .flags = ACL_TYPE_DEFAULT, + .list = f2fs_xattr_list_acl, + .get = f2fs_xattr_get_acl, + .set = f2fs_xattr_set_acl, +}; + +const struct xattr_handler f2fs_xattr_acl_access_handler = { + .prefix = POSIX_ACL_XATTR_ACCESS, + .flags = ACL_TYPE_ACCESS, + .list = f2fs_xattr_list_acl, + .get = f2fs_xattr_get_acl, + .set = f2fs_xattr_set_acl, +}; + +static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, + size_t list_size, const char *name, size_t name_len, int type) +{ + const char *xname = F2FS_SYSTEM_ADVISE_PREFIX; + size_t size; + + if (type != F2FS_XATTR_INDEX_ADVISE) + return 0; + + size = strlen(xname) + 1; + if (list && size <= list_size) + memcpy(list, xname, size); + return size; +} + +static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name, + void *buffer, size_t size, int type) +{ + struct inode *inode = dentry->d_inode; + + if (strcmp(name, "") != 0) + return -EINVAL; + + *((char *)buffer) = F2FS_I(inode)->i_advise; + return sizeof(char); +} + +static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, int type) +{ + struct inode *inode = dentry->d_inode; + + if (strcmp(name, "") != 0) + return -EINVAL; + if (!inode_owner_or_capable(inode)) + return -EPERM; + if (value == NULL) + return -EINVAL; + + F2FS_I(inode)->i_advise |= *(char *)value; + return 0; +} + +const struct xattr_handler f2fs_xattr_advise_handler = { + .prefix = F2FS_SYSTEM_ADVISE_PREFIX, + .flags = F2FS_XATTR_INDEX_ADVISE, + .list = f2fs_xattr_advise_list, + .get = f2fs_xattr_advise_get, + .set = f2fs_xattr_advise_set, +}; diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h new file mode 100644 index 0000000..c97675e --- /dev/null +++ b/fs/f2fs/acl.h @@ -0,0 +1,57 @@ +/** + * fs/f2fs/acl.h + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Portions of this code from linux/fs/ext2/acl.h + * + * Copyright (C) 2001-2003 Andreas Gruenbacher, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __F2FS_ACL_H__ +#define __F2FS_ACL_H__ + +#include + +#define F2FS_ACL_VERSION 0x0001 + +struct f2fs_acl_entry { + __le16 e_tag; + __le16 e_perm; + __le32 e_id; +}; + +struct f2fs_acl_entry_short { + __le16 e_tag; + __le16 e_perm; +}; + +struct f2fs_acl_header { + __le32 a_version; +}; + +#ifdef CONFIG_F2FS_FS_POSIX_ACL + +extern struct posix_acl *f2fs_get_acl(struct inode *inode, int type); +extern int f2fs_acl_chmod(struct inode *inode); +extern int f2fs_init_acl(struct inode *inode, struct inode *dir); +#else +#define f2fs_check_acl NULL +#define f2fs_get_acl NULL +#define f2fs_set_acl NULL + +static inline int f2fs_acl_chmod(struct inode *inode) +{ + return 0; +} + +static inline int f2fs_init_acl(struct inode *inode, struct inode *dir) +{ + return 0; +} +#endif +#endif /* __F2FS_ACL_H__ */ diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c new file mode 100644 index 0000000..aca50fe --- /dev/null +++ b/fs/f2fs/xattr.c @@ -0,0 +1,389 @@ +/** + * fs/f2fs/xattr.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Portions of this code from linux/fs/ext2/xattr.c + * + * Copyright (C) 2001-2003 Andreas Gruenbacher + * + * Fix by Harrison Xing . + * Extended attributes for symlinks and special files added per + * suggestion of Luka Renko . + * xattr consolidation Copyright (c) 2004 James Morris , + * Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include "f2fs.h" +#include "xattr.h" + +static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list, + size_t list_size, const char *name, size_t name_len, int type) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); + int total_len, prefix_len = 0; + const char *prefix = NULL; + + switch (type) { + case F2FS_XATTR_INDEX_USER: + if (!test_opt(sbi, XATTR_USER)) + return -EOPNOTSUPP; + prefix = XATTR_USER_PREFIX; + prefix_len = XATTR_USER_PREFIX_LEN; + break; + case F2FS_XATTR_INDEX_TRUSTED: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + prefix = XATTR_TRUSTED_PREFIX; + prefix_len = XATTR_TRUSTED_PREFIX_LEN; + break; + default: + return -EINVAL; + } + + total_len = prefix_len + name_len + 1; + if (list && total_len <= list_size) { + memcpy(list, prefix, prefix_len); + memcpy(list+prefix_len, name, name_len); + list[prefix_len + name_len] = '\0'; + } + return total_len; +} + +static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name, + void *buffer, size_t size, int type) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); + + switch (type) { + case F2FS_XATTR_INDEX_USER: + if (!test_opt(sbi, XATTR_USER)) + return -EOPNOTSUPP; + break; + case F2FS_XATTR_INDEX_TRUSTED: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + break; + default: + return -EINVAL; + } + if (strcmp(name, "") == 0) + return -EINVAL; + return f2fs_getxattr(dentry->d_inode, type, name, + buffer, size); +} + +static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, int type) +{ + struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); + + switch (type) { + case F2FS_XATTR_INDEX_USER: + if (!test_opt(sbi, XATTR_USER)) + return -EOPNOTSUPP; + break; + case F2FS_XATTR_INDEX_TRUSTED: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + break; + default: + return -EINVAL; + } + if (strcmp(name, "") == 0) + return -EINVAL; + + return f2fs_setxattr(dentry->d_inode, type, name, value, size); +} + +const struct xattr_handler f2fs_xattr_user_handler = { + .prefix = XATTR_USER_PREFIX, + .flags = F2FS_XATTR_INDEX_USER, + .list = f2fs_xattr_generic_list, + .get = f2fs_xattr_generic_get, + .set = f2fs_xattr_generic_set, +}; + +const struct xattr_handler f2fs_xattr_trusted_handler = { + .prefix = XATTR_TRUSTED_PREFIX, + .flags = F2FS_XATTR_INDEX_TRUSTED, + .list = f2fs_xattr_generic_list, + .get = f2fs_xattr_generic_get, + .set = f2fs_xattr_generic_set, +}; + +static const struct xattr_handler *f2fs_xattr_handler_map[] = { + [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler, +#ifdef CONFIG_F2FS_FS_POSIX_ACL + [F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &f2fs_xattr_acl_access_handler, + [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &f2fs_xattr_acl_default_handler, +#endif + [F2FS_XATTR_INDEX_TRUSTED] = &f2fs_xattr_trusted_handler, + [F2FS_XATTR_INDEX_ADVISE] = &f2fs_xattr_advise_handler, +}; + +const struct xattr_handler *f2fs_xattr_handlers[] = { + &f2fs_xattr_user_handler, +#ifdef CONFIG_F2FS_FS_POSIX_ACL + &f2fs_xattr_acl_access_handler, + &f2fs_xattr_acl_default_handler, +#endif + &f2fs_xattr_trusted_handler, + &f2fs_xattr_advise_handler, + NULL, +}; + +static inline const struct xattr_handler *f2fs_xattr_handler(int name_index) +{ + const struct xattr_handler *handler = NULL; + + if (name_index > 0 && name_index < ARRAY_SIZE(f2fs_xattr_handler_map)) + handler = f2fs_xattr_handler_map[name_index]; + return handler; +} + +int f2fs_getxattr(struct inode *inode, int name_index, const char *name, + void *buffer, size_t buffer_size) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_inode_info *fi = F2FS_I(inode); + struct f2fs_xattr_entry *entry; + struct page *page; + void *base_addr; + int error = 0, found = 0; + int value_len, name_len; + + if (name == NULL) + return -EINVAL; + name_len = strlen(name); + + if (!fi->i_xattr_nid) + return -ENODATA; + + page = get_node_page(sbi, fi->i_xattr_nid); + base_addr = page_address(page); + + list_for_each_xattr(entry, base_addr) { + if (entry->e_name_index != name_index) + continue; + if (entry->e_name_len != name_len) + continue; + if (!memcmp(entry->e_name, name, name_len)) { + found = 1; + break; + } + } + if (!found) { + error = -ENODATA; + goto cleanup; + } + + value_len = le16_to_cpu(entry->e_value_size); + + if (buffer && value_len > buffer_size) { + error = -ERANGE; + goto cleanup; + } + + if (buffer) { + char *pval = entry->e_name + entry->e_name_len; + memcpy(buffer, pval, value_len); + } + error = value_len; + +cleanup: + f2fs_put_page(page, 1); + return error; +} + +ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) +{ + struct inode *inode = dentry->d_inode; + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_inode_info *fi = F2FS_I(inode); + struct f2fs_xattr_entry *entry; + struct page *page; + void *base_addr; + int error = 0; + size_t rest = buffer_size; + + if (!fi->i_xattr_nid) + return 0; + + page = get_node_page(sbi, fi->i_xattr_nid); + base_addr = page_address(page); + + list_for_each_xattr(entry, base_addr) { + const struct xattr_handler *handler = + f2fs_xattr_handler(entry->e_name_index); + size_t size; + + if (!handler) + continue; + + size = handler->list(dentry, buffer, rest, entry->e_name, + entry->e_name_len, handler->flags); + if (buffer && size > rest) { + error = -ERANGE; + goto cleanup; + } + + if (buffer) + buffer += size; + rest -= size; + } + error = buffer_size - rest; +cleanup: + f2fs_put_page(page, 1); + return error; +} + +int f2fs_setxattr(struct inode *inode, int name_index, const char *name, + const void *value, size_t value_len) +{ + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + struct f2fs_inode_info *fi = F2FS_I(inode); + struct f2fs_xattr_header *header = NULL; + struct f2fs_xattr_entry *here, *last; + struct page *page; + void *base_addr; + int error, found, free, name_len, newsize; + char *pval; + + if (name == NULL) + return -EINVAL; + name_len = strlen(name); + + if (value == NULL) + value_len = 0; + + if (name_len > 255 || value_len > MAX_VALUE_LEN) + return -ERANGE; + + mutex_lock_op(sbi, NODE_NEW); + if (!fi->i_xattr_nid) { + /* Allocate new attribute block */ + struct dnode_of_data dn; + + if (!alloc_nid(sbi, &fi->i_xattr_nid)) { + mutex_unlock_op(sbi, NODE_NEW); + return -ENOSPC; + } + set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid); + mark_inode_dirty(inode); + + page = new_node_page(&dn, XATTR_NODE_OFFSET); + if (IS_ERR(page)) { + alloc_nid_failed(sbi, fi->i_xattr_nid); + fi->i_xattr_nid = 0; + mutex_unlock_op(sbi, NODE_NEW); + return PTR_ERR(page); + } + + alloc_nid_done(sbi, fi->i_xattr_nid); + base_addr = page_address(page); + header = XATTR_HDR(base_addr); + header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); + header->h_refcount = cpu_to_le32(1); + } else { + /* The inode already has an extended attribute block. */ + page = get_node_page(sbi, fi->i_xattr_nid); + if (IS_ERR(page)) { + mutex_unlock_op(sbi, NODE_NEW); + return PTR_ERR(page); + } + + base_addr = page_address(page); + header = XATTR_HDR(base_addr); + } + + if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) { + error = -EIO; + goto cleanup; + } + + /* find entry with wanted name. */ + found = 0; + list_for_each_xattr(here, base_addr) { + if (here->e_name_index != name_index) + continue; + if (here->e_name_len != name_len) + continue; + if (!memcmp(here->e_name, name, name_len)) { + found = 1; + break; + } + } + + last = here; + + while (!IS_XATTR_LAST_ENTRY(last)) + last = XATTR_NEXT_ENTRY(last); + + newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + + name_len + value_len); + + /* 1. Check space */ + if (value) { + /* If value is NULL, it is remove operation. + * In case of update operation, we caculate free. + */ + free = MIN_OFFSET - ((char *)last - (char *)header); + if (found) + free = free - ENTRY_SIZE(here); + + if (free < newsize) { + error = -ENOSPC; + goto cleanup; + } + } + + /* 2. Remove old entry */ + if (found) { + /* If entry is found, remove old entry. + * If not found, remove operation is not needed. + */ + struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here); + int oldsize = ENTRY_SIZE(here); + + memmove(here, next, (char *)last - (char *)next); + last = (struct f2fs_xattr_entry *)((char *)last - oldsize); + memset(last, 0, oldsize); + } + + /* 3. Write new entry */ + if (value) { + /* Before we come here, old entry is removed. + * We just write new entry. */ + memset(last, 0, newsize); + last->e_name_index = name_index; + last->e_name_len = name_len; + memcpy(last->e_name, name, name_len); + pval = last->e_name + name_len; + memcpy(pval, value, value_len); + last->e_value_size = cpu_to_le16(value_len); + } + + set_page_dirty(page); + f2fs_put_page(page, 1); + + if (is_inode_flag_set(fi, FI_ACL_MODE)) { + inode->i_mode = fi->i_acl_mode; + inode->i_ctime = CURRENT_TIME; + clear_inode_flag(fi, FI_ACL_MODE); + } + f2fs_write_inode(inode, NULL); + mutex_unlock_op(sbi, NODE_NEW); + + return 0; +cleanup: + f2fs_put_page(page, 1); + mutex_unlock_op(sbi, NODE_NEW); + return error; +} diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h new file mode 100644 index 0000000..29b0a08 --- /dev/null +++ b/fs/f2fs/xattr.h @@ -0,0 +1,145 @@ +/** + * fs/f2fs/xattr.h + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Portions of this code from linux/fs/ext2/xattr.h + * + * On-disk format of extended attributes for the ext2 filesystem. + * + * (C) 2001 Andreas Gruenbacher, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __F2FS_XATTR_H__ +#define __F2FS_XATTR_H__ + +#include +#include + +/* Magic value in attribute blocks */ +#define F2FS_XATTR_MAGIC 0xF2F52011 + +/* Maximum number of references to one attribute block */ +#define F2FS_XATTR_REFCOUNT_MAX 1024 + +/* Name indexes */ +#define F2FS_SYSTEM_ADVISE_PREFIX "system.advise" +#define F2FS_XATTR_INDEX_USER 1 +#define F2FS_XATTR_INDEX_POSIX_ACL_ACCESS 2 +#define F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT 3 +#define F2FS_XATTR_INDEX_TRUSTED 4 +#define F2FS_XATTR_INDEX_LUSTRE 5 +#define F2FS_XATTR_INDEX_SECURITY 6 +#define F2FS_XATTR_INDEX_ADVISE 7 + +struct f2fs_xattr_header { + __le32 h_magic; /* magic number for identification */ + __le32 h_refcount; /* reference count */ + __u32 h_reserved[4]; /* zero right now */ +}; + +struct f2fs_xattr_entry { + __u8 e_name_index; + __u8 e_name_len; + __le16 e_value_size; /* size of attribute value */ + char e_name[0]; /* attribute name */ +}; + +#define XATTR_HDR(ptr) ((struct f2fs_xattr_header *)(ptr)) +#define XATTR_ENTRY(ptr) ((struct f2fs_xattr_entry *)(ptr)) +#define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr)+1)) +#define XATTR_ROUND (3) + +#define XATTR_ALIGN(size) ((size + XATTR_ROUND) & ~XATTR_ROUND) + +#define ENTRY_SIZE(entry) (XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + \ + entry->e_name_len + le16_to_cpu(entry->e_value_size))) + +#define XATTR_NEXT_ENTRY(entry) ((struct f2fs_xattr_entry *)((char *)(entry) +\ + ENTRY_SIZE(entry))) + +#define IS_XATTR_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) + +#define list_for_each_xattr(entry, addr) \ + for (entry = XATTR_FIRST_ENTRY(addr);\ + !IS_XATTR_LAST_ENTRY(entry);\ + entry = XATTR_NEXT_ENTRY(entry)) + + +#define MIN_OFFSET XATTR_ALIGN(PAGE_SIZE - \ + sizeof(struct node_footer) - \ + sizeof(__u32)) + +#define MAX_VALUE_LEN (MIN_OFFSET - sizeof(struct f2fs_xattr_header) - \ + sizeof(struct f2fs_xattr_entry)) + +/** + * On-disk structure of f2fs_xattr + * We use only 1 block for xattr. + * + * +--------------------+ + * | f2fs_xattr_header | + * | | + * +--------------------+ + * | f2fs_xattr_entry | + * | .e_name_index = 1 | + * | .e_name_len = 3 | + * | .e_value_size = 14 | + * | .e_name = "foo" | + * | "value_of_xattr" |<- value_offs = e_name + e_name_len + * +--------------------+ + * | f2fs_xattr_entry | + * | .e_name_index = 4 | + * | .e_name = "bar" | + * +--------------------+ + * | | + * | Free | + * | | + * +--------------------+<- MIN_OFFSET + * | node_footer | + * | (nid, ino, offset) | + * +--------------------+ + * + **/ + +#ifdef CONFIG_F2FS_FS_XATTR +extern const struct xattr_handler f2fs_xattr_user_handler; +extern const struct xattr_handler f2fs_xattr_trusted_handler; +extern const struct xattr_handler f2fs_xattr_acl_access_handler; +extern const struct xattr_handler f2fs_xattr_acl_default_handler; +extern const struct xattr_handler f2fs_xattr_advise_handler; + +extern const struct xattr_handler *f2fs_xattr_handlers[]; + +extern int f2fs_setxattr(struct inode *inode, int name_index, const char *name, + const void *value, size_t value_len); +extern int f2fs_getxattr(struct inode *inode, int name_index, const char *name, + void *buffer, size_t buffer_size); +extern ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, + size_t buffer_size); + +#else + +#define f2fs_xattr_handlers NULL +static inline int f2fs_setxattr(struct inode *inode, int name_index, + const char *name, const void *value, size_t value_len) +{ + return -EOPNOTSUPP; +} +static inline int f2fs_getxattr(struct inode *inode, int name_index, + const char *name, void *buffer, size_t buffer_size) +{ + return -EOPNOTSUPP; +} +static inline ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, + size_t buffer_size) +{ + return -EOPNOTSUPP; +} +#endif + +#endif /* __F2FS_XATTR_H__ */ -- cgit v0.10.2 From 7bc0900347e069a1676d28ad6f98cafaf8cfd6e9 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:13:01 +0900 Subject: f2fs: add garbage collection functions This adds on-demand and background cleaning functions. - The basic background cleaning policy is trying to do cleaning jobs as much as possible whenever the system is idle. Once the background cleaning is done, the cleaner sleeps an amount of time not to interfere with VFS calls. The time is dynamically adjusted according to the status of whole segments, which is decreased when the following conditions are satisfied. . GC is not conducted currently, and . IO subsystem is idle by checking the number of requets in bdev's request list, and . There are enough dirty segments. Otherwise, the time is increased incrementally until to the maximum time. Note that, min and max times are 10 secs and 30 secs by default. - F2FS adopts a default victim selection policy where background cleaning uses a cost-benefit algorithm, while on-demand cleaning uses a greedy algorithm. - The method of moving data during the cleaning is slightly different between background and on-demand cleaning schemes. In the case of background cleaning, F2FS loads the data, and marks them as dirty. Then, F2FS expects that the data will be moved by flusher or VM. In the case of on-demand cleaning, F2FS should move the data right away. - In order to identify valid blocks in a victim segment, F2FS scans the bitmap of the segment managed as an SIT entry. Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c new file mode 100644 index 0000000..46774ce --- /dev/null +++ b/fs/f2fs/gc.c @@ -0,0 +1,742 @@ +/** + * fs/f2fs/gc.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "node.h" +#include "segment.h" +#include "gc.h" + +static struct kmem_cache *winode_slab; + +static int gc_thread_func(void *data) +{ + struct f2fs_sb_info *sbi = data; + wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head; + long wait_ms; + + wait_ms = GC_THREAD_MIN_SLEEP_TIME; + + do { + if (try_to_freeze()) + continue; + else + wait_event_interruptible_timeout(*wq, + kthread_should_stop(), + msecs_to_jiffies(wait_ms)); + if (kthread_should_stop()) + break; + + f2fs_balance_fs(sbi); + + if (!test_opt(sbi, BG_GC)) + continue; + + /* + * [GC triggering condition] + * 0. GC is not conducted currently. + * 1. There are enough dirty segments. + * 2. IO subsystem is idle by checking the # of writeback pages. + * 3. IO subsystem is idle by checking the # of requests in + * bdev's request list. + * + * Note) We have to avoid triggering GCs too much frequently. + * Because it is possible that some segments can be + * invalidated soon after by user update or deletion. + * So, I'd like to wait some time to collect dirty segments. + */ + if (!mutex_trylock(&sbi->gc_mutex)) + continue; + + if (!is_idle(sbi)) { + wait_ms = increase_sleep_time(wait_ms); + mutex_unlock(&sbi->gc_mutex); + continue; + } + + if (has_enough_invalid_blocks(sbi)) + wait_ms = decrease_sleep_time(wait_ms); + else + wait_ms = increase_sleep_time(wait_ms); + + sbi->bg_gc++; + + if (f2fs_gc(sbi, 1) == GC_NONE) + wait_ms = GC_THREAD_NOGC_SLEEP_TIME; + else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME) + wait_ms = GC_THREAD_MAX_SLEEP_TIME; + + } while (!kthread_should_stop()); + return 0; +} + +int start_gc_thread(struct f2fs_sb_info *sbi) +{ + struct f2fs_gc_kthread *gc_th = NULL; + + gc_th = kmalloc(sizeof(struct f2fs_gc_kthread), GFP_KERNEL); + if (!gc_th) + return -ENOMEM; + + sbi->gc_thread = gc_th; + init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head); + sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi, + GC_THREAD_NAME); + if (IS_ERR(gc_th->f2fs_gc_task)) { + kfree(gc_th); + return -ENOMEM; + } + return 0; +} + +void stop_gc_thread(struct f2fs_sb_info *sbi) +{ + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + if (!gc_th) + return; + kthread_stop(gc_th->f2fs_gc_task); + kfree(gc_th); + sbi->gc_thread = NULL; +} + +static int select_gc_type(int gc_type) +{ + return (gc_type == BG_GC) ? GC_CB : GC_GREEDY; +} + +static void select_policy(struct f2fs_sb_info *sbi, int gc_type, + int type, struct victim_sel_policy *p) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + + if (p->alloc_mode) { + p->gc_mode = GC_GREEDY; + p->dirty_segmap = dirty_i->dirty_segmap[type]; + p->ofs_unit = 1; + } else { + p->gc_mode = select_gc_type(gc_type); + p->dirty_segmap = dirty_i->dirty_segmap[DIRTY]; + p->ofs_unit = sbi->segs_per_sec; + } + p->offset = sbi->last_victim[p->gc_mode]; +} + +static unsigned int get_max_cost(struct f2fs_sb_info *sbi, + struct victim_sel_policy *p) +{ + if (p->gc_mode == GC_GREEDY) + return (1 << sbi->log_blocks_per_seg) * p->ofs_unit; + else if (p->gc_mode == GC_CB) + return UINT_MAX; + else /* No other gc_mode */ + return 0; +} + +static unsigned int check_bg_victims(struct f2fs_sb_info *sbi) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + unsigned int segno; + + /* + * If the gc_type is FG_GC, we can select victim segments + * selected by background GC before. + * Those segments guarantee they have small valid blocks. + */ + segno = find_next_bit(dirty_i->victim_segmap[BG_GC], + TOTAL_SEGS(sbi), 0); + if (segno < TOTAL_SEGS(sbi)) { + clear_bit(segno, dirty_i->victim_segmap[BG_GC]); + return segno; + } + return NULL_SEGNO; +} + +static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned int secno = GET_SECNO(sbi, segno); + unsigned int start = secno * sbi->segs_per_sec; + unsigned long long mtime = 0; + unsigned int vblocks; + unsigned char age = 0; + unsigned char u; + unsigned int i; + + for (i = 0; i < sbi->segs_per_sec; i++) + mtime += get_seg_entry(sbi, start + i)->mtime; + vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec); + + mtime = div_u64(mtime, sbi->segs_per_sec); + vblocks = div_u64(vblocks, sbi->segs_per_sec); + + u = (vblocks * 100) >> sbi->log_blocks_per_seg; + + /* Handle if the system time is changed by user */ + if (mtime < sit_i->min_mtime) + sit_i->min_mtime = mtime; + if (mtime > sit_i->max_mtime) + sit_i->max_mtime = mtime; + if (sit_i->max_mtime != sit_i->min_mtime) + age = 100 - div64_u64(100 * (mtime - sit_i->min_mtime), + sit_i->max_mtime - sit_i->min_mtime); + + return UINT_MAX - ((100 * (100 - u) * age) / (100 + u)); +} + +static unsigned int get_gc_cost(struct f2fs_sb_info *sbi, unsigned int segno, + struct victim_sel_policy *p) +{ + if (p->alloc_mode == SSR) + return get_seg_entry(sbi, segno)->ckpt_valid_blocks; + + /* alloc_mode == LFS */ + if (p->gc_mode == GC_GREEDY) + return get_valid_blocks(sbi, segno, sbi->segs_per_sec); + else + return get_cb_cost(sbi, segno); +} + +/** + * This function is called from two pathes. + * One is garbage collection and the other is SSR segment selection. + * When it is called during GC, it just gets a victim segment + * and it does not remove it from dirty seglist. + * When it is called from SSR segment selection, it finds a segment + * which has minimum valid blocks and removes it from dirty seglist. + */ +static int get_victim_by_default(struct f2fs_sb_info *sbi, + unsigned int *result, int gc_type, int type, char alloc_mode) +{ + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + struct victim_sel_policy p; + unsigned int segno; + int nsearched = 0; + + p.alloc_mode = alloc_mode; + select_policy(sbi, gc_type, type, &p); + + p.min_segno = NULL_SEGNO; + p.min_cost = get_max_cost(sbi, &p); + + mutex_lock(&dirty_i->seglist_lock); + + if (p.alloc_mode == LFS && gc_type == FG_GC) { + p.min_segno = check_bg_victims(sbi); + if (p.min_segno != NULL_SEGNO) + goto got_it; + } + + while (1) { + unsigned long cost; + + segno = find_next_bit(p.dirty_segmap, + TOTAL_SEGS(sbi), p.offset); + if (segno >= TOTAL_SEGS(sbi)) { + if (sbi->last_victim[p.gc_mode]) { + sbi->last_victim[p.gc_mode] = 0; + p.offset = 0; + continue; + } + break; + } + p.offset = ((segno / p.ofs_unit) * p.ofs_unit) + p.ofs_unit; + + if (test_bit(segno, dirty_i->victim_segmap[FG_GC])) + continue; + if (gc_type == BG_GC && + test_bit(segno, dirty_i->victim_segmap[BG_GC])) + continue; + if (IS_CURSEC(sbi, GET_SECNO(sbi, segno))) + continue; + + cost = get_gc_cost(sbi, segno, &p); + + if (p.min_cost > cost) { + p.min_segno = segno; + p.min_cost = cost; + } + + if (cost == get_max_cost(sbi, &p)) + continue; + + if (nsearched++ >= MAX_VICTIM_SEARCH) { + sbi->last_victim[p.gc_mode] = segno; + break; + } + } +got_it: + if (p.min_segno != NULL_SEGNO) { + *result = (p.min_segno / p.ofs_unit) * p.ofs_unit; + if (p.alloc_mode == LFS) { + int i; + for (i = 0; i < p.ofs_unit; i++) + set_bit(*result + i, + dirty_i->victim_segmap[gc_type]); + } + } + mutex_unlock(&dirty_i->seglist_lock); + + return (p.min_segno == NULL_SEGNO) ? 0 : 1; +} + +static const struct victim_selection default_v_ops = { + .get_victim = get_victim_by_default, +}; + +static struct inode *find_gc_inode(nid_t ino, struct list_head *ilist) +{ + struct list_head *this; + struct inode_entry *ie; + + list_for_each(this, ilist) { + ie = list_entry(this, struct inode_entry, list); + if (ie->inode->i_ino == ino) + return ie->inode; + } + return NULL; +} + +static void add_gc_inode(struct inode *inode, struct list_head *ilist) +{ + struct list_head *this; + struct inode_entry *new_ie, *ie; + + list_for_each(this, ilist) { + ie = list_entry(this, struct inode_entry, list); + if (ie->inode == inode) { + iput(inode); + return; + } + } +repeat: + new_ie = kmem_cache_alloc(winode_slab, GFP_NOFS); + if (!new_ie) { + cond_resched(); + goto repeat; + } + new_ie->inode = inode; + list_add_tail(&new_ie->list, ilist); +} + +static void put_gc_inode(struct list_head *ilist) +{ + struct inode_entry *ie, *next_ie; + list_for_each_entry_safe(ie, next_ie, ilist, list) { + iput(ie->inode); + list_del(&ie->list); + kmem_cache_free(winode_slab, ie); + } +} + +static int check_valid_map(struct f2fs_sb_info *sbi, + unsigned int segno, int offset) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct seg_entry *sentry; + int ret; + + mutex_lock(&sit_i->sentry_lock); + sentry = get_seg_entry(sbi, segno); + ret = f2fs_test_bit(offset, sentry->cur_valid_map); + mutex_unlock(&sit_i->sentry_lock); + return ret ? GC_OK : GC_NEXT; +} + +/** + * This function compares node address got in summary with that in NAT. + * On validity, copy that node with cold status, otherwise (invalid node) + * ignore that. + */ +static int gc_node_segment(struct f2fs_sb_info *sbi, + struct f2fs_summary *sum, unsigned int segno, int gc_type) +{ + bool initial = true; + struct f2fs_summary *entry; + int off; + +next_step: + entry = sum; + for (off = 0; off < sbi->blocks_per_seg; off++, entry++) { + nid_t nid = le32_to_cpu(entry->nid); + struct page *node_page; + int err; + + /* + * It makes sure that free segments are able to write + * all the dirty node pages before CP after this CP. + * So let's check the space of dirty node pages. + */ + if (should_do_checkpoint(sbi)) { + mutex_lock(&sbi->cp_mutex); + block_operations(sbi); + return GC_BLOCKED; + } + + err = check_valid_map(sbi, segno, off); + if (err == GC_ERROR) + return err; + else if (err == GC_NEXT) + continue; + + if (initial) { + ra_node_page(sbi, nid); + continue; + } + node_page = get_node_page(sbi, nid); + if (IS_ERR(node_page)) + continue; + + /* set page dirty and write it */ + if (!PageWriteback(node_page)) + set_page_dirty(node_page); + f2fs_put_page(node_page, 1); + stat_inc_node_blk_count(sbi, 1); + } + if (initial) { + initial = false; + goto next_step; + } + + if (gc_type == FG_GC) { + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .for_reclaim = 0, + }; + sync_node_pages(sbi, 0, &wbc); + } + return GC_DONE; +} + +/** + * Calculate start block index that this node page contains + */ +block_t start_bidx_of_node(unsigned int node_ofs) +{ + block_t start_bidx; + unsigned int bidx, indirect_blks; + int dec; + + indirect_blks = 2 * NIDS_PER_BLOCK + 4; + + start_bidx = 1; + if (node_ofs == 0) { + start_bidx = 0; + } else if (node_ofs <= 2) { + bidx = node_ofs - 1; + } else if (node_ofs <= indirect_blks) { + dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1); + bidx = node_ofs - 2 - dec; + } else { + dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1); + bidx = node_ofs - 5 - dec; + } + + if (start_bidx) + start_bidx = bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE; + return start_bidx; +} + +static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, + struct node_info *dni, block_t blkaddr, unsigned int *nofs) +{ + struct page *node_page; + nid_t nid; + unsigned int ofs_in_node; + block_t source_blkaddr; + + nid = le32_to_cpu(sum->nid); + ofs_in_node = le16_to_cpu(sum->ofs_in_node); + + node_page = get_node_page(sbi, nid); + if (IS_ERR(node_page)) + return GC_NEXT; + + get_node_info(sbi, nid, dni); + + if (sum->version != dni->version) { + f2fs_put_page(node_page, 1); + return GC_NEXT; + } + + *nofs = ofs_of_node(node_page); + source_blkaddr = datablock_addr(node_page, ofs_in_node); + f2fs_put_page(node_page, 1); + + if (source_blkaddr != blkaddr) + return GC_NEXT; + return GC_OK; +} + +static void move_data_page(struct inode *inode, struct page *page, int gc_type) +{ + if (page->mapping != inode->i_mapping) + goto out; + + if (inode != page->mapping->host) + goto out; + + if (PageWriteback(page)) + goto out; + + if (gc_type == BG_GC) { + set_page_dirty(page); + set_cold_data(page); + } else { + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); + mutex_lock_op(sbi, DATA_WRITE); + if (clear_page_dirty_for_io(page) && + S_ISDIR(inode->i_mode)) { + dec_page_count(sbi, F2FS_DIRTY_DENTS); + inode_dec_dirty_dents(inode); + } + set_cold_data(page); + do_write_data_page(page); + mutex_unlock_op(sbi, DATA_WRITE); + clear_cold_data(page); + } +out: + f2fs_put_page(page, 1); +} + +/** + * This function tries to get parent node of victim data block, and identifies + * data block validity. If the block is valid, copy that with cold status and + * modify parent node. + * If the parent node is not valid or the data block address is different, + * the victim data block is ignored. + */ +static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, + struct list_head *ilist, unsigned int segno, int gc_type) +{ + struct super_block *sb = sbi->sb; + struct f2fs_summary *entry; + block_t start_addr; + int err, off; + int phase = 0; + + start_addr = START_BLOCK(sbi, segno); + +next_step: + entry = sum; + for (off = 0; off < sbi->blocks_per_seg; off++, entry++) { + struct page *data_page; + struct inode *inode; + struct node_info dni; /* dnode info for the data */ + unsigned int ofs_in_node, nofs; + block_t start_bidx; + + /* + * It makes sure that free segments are able to write + * all the dirty node pages before CP after this CP. + * So let's check the space of dirty node pages. + */ + if (should_do_checkpoint(sbi)) { + mutex_lock(&sbi->cp_mutex); + block_operations(sbi); + err = GC_BLOCKED; + goto stop; + } + + err = check_valid_map(sbi, segno, off); + if (err == GC_ERROR) + goto stop; + else if (err == GC_NEXT) + continue; + + if (phase == 0) { + ra_node_page(sbi, le32_to_cpu(entry->nid)); + continue; + } + + /* Get an inode by ino with checking validity */ + err = check_dnode(sbi, entry, &dni, start_addr + off, &nofs); + if (err == GC_ERROR) + goto stop; + else if (err == GC_NEXT) + continue; + + if (phase == 1) { + ra_node_page(sbi, dni.ino); + continue; + } + + start_bidx = start_bidx_of_node(nofs); + ofs_in_node = le16_to_cpu(entry->ofs_in_node); + + if (phase == 2) { + inode = f2fs_iget_nowait(sb, dni.ino); + if (IS_ERR(inode)) + continue; + + data_page = find_data_page(inode, + start_bidx + ofs_in_node); + if (IS_ERR(data_page)) + goto next_iput; + + f2fs_put_page(data_page, 0); + add_gc_inode(inode, ilist); + } else { + inode = find_gc_inode(dni.ino, ilist); + if (inode) { + data_page = get_lock_data_page(inode, + start_bidx + ofs_in_node); + if (IS_ERR(data_page)) + continue; + move_data_page(inode, data_page, gc_type); + stat_inc_data_blk_count(sbi, 1); + } + } + continue; +next_iput: + iput(inode); + } + if (++phase < 4) + goto next_step; + err = GC_DONE; +stop: + if (gc_type == FG_GC) + f2fs_submit_bio(sbi, DATA, true); + return err; +} + +static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim, + int gc_type, int type) +{ + struct sit_info *sit_i = SIT_I(sbi); + int ret; + mutex_lock(&sit_i->sentry_lock); + ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type, type, LFS); + mutex_unlock(&sit_i->sentry_lock); + return ret; +} + +static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno, + struct list_head *ilist, int gc_type) +{ + struct page *sum_page; + struct f2fs_summary_block *sum; + int ret = GC_DONE; + + /* read segment summary of victim */ + sum_page = get_sum_page(sbi, segno); + if (IS_ERR(sum_page)) + return GC_ERROR; + + /* + * CP needs to lock sum_page. In this time, we don't need + * to lock this page, because this summary page is not gone anywhere. + * Also, this page is not gonna be updated before GC is done. + */ + unlock_page(sum_page); + sum = page_address(sum_page); + + switch (GET_SUM_TYPE((&sum->footer))) { + case SUM_TYPE_NODE: + ret = gc_node_segment(sbi, sum->entries, segno, gc_type); + break; + case SUM_TYPE_DATA: + ret = gc_data_segment(sbi, sum->entries, ilist, segno, gc_type); + break; + } + stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer))); + stat_inc_call_count(sbi->stat_info); + + f2fs_put_page(sum_page, 0); + return ret; +} + +int f2fs_gc(struct f2fs_sb_info *sbi, int nGC) +{ + unsigned int segno; + int old_free_secs, cur_free_secs; + int gc_status, nfree; + struct list_head ilist; + int gc_type = BG_GC; + + INIT_LIST_HEAD(&ilist); +gc_more: + nfree = 0; + gc_status = GC_NONE; + + if (has_not_enough_free_secs(sbi)) + old_free_secs = reserved_sections(sbi); + else + old_free_secs = free_sections(sbi); + + while (sbi->sb->s_flags & MS_ACTIVE) { + int i; + if (has_not_enough_free_secs(sbi)) + gc_type = FG_GC; + + cur_free_secs = free_sections(sbi) + nfree; + + /* We got free space successfully. */ + if (nGC < cur_free_secs - old_free_secs) + break; + + if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE)) + break; + + for (i = 0; i < sbi->segs_per_sec; i++) { + /* + * do_garbage_collect will give us three gc_status: + * GC_ERROR, GC_DONE, and GC_BLOCKED. + * If GC is finished uncleanly, we have to return + * the victim to dirty segment list. + */ + gc_status = do_garbage_collect(sbi, segno + i, + &ilist, gc_type); + if (gc_status != GC_DONE) + goto stop; + nfree++; + } + } +stop: + if (has_not_enough_free_secs(sbi) || gc_status == GC_BLOCKED) { + write_checkpoint(sbi, (gc_status == GC_BLOCKED), false); + if (nfree) + goto gc_more; + } + mutex_unlock(&sbi->gc_mutex); + + put_gc_inode(&ilist); + BUG_ON(!list_empty(&ilist)); + return gc_status; +} + +void build_gc_manager(struct f2fs_sb_info *sbi) +{ + DIRTY_I(sbi)->v_ops = &default_v_ops; +} + +int create_gc_caches(void) +{ + winode_slab = f2fs_kmem_cache_create("f2fs_gc_inodes", + sizeof(struct inode_entry), NULL); + if (!winode_slab) + return -ENOMEM; + return 0; +} + +void destroy_gc_caches(void) +{ + kmem_cache_destroy(winode_slab); +} diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h new file mode 100644 index 0000000..cf42a55 --- /dev/null +++ b/fs/f2fs/gc.h @@ -0,0 +1,117 @@ +/** + * fs/f2fs/gc.h + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define GC_THREAD_NAME "f2fs_gc_task" +#define GC_THREAD_MIN_WB_PAGES 1 /* + * a threshold to determine + * whether IO subsystem is idle + * or not + */ +#define GC_THREAD_MIN_SLEEP_TIME 10000 /* milliseconds */ +#define GC_THREAD_MAX_SLEEP_TIME 30000 +#define GC_THREAD_NOGC_SLEEP_TIME 10000 +#define LIMIT_INVALID_BLOCK 40 /* percentage over total user space */ +#define LIMIT_FREE_BLOCK 40 /* percentage over invalid + free space */ + +/* Search max. number of dirty segments to select a victim segment */ +#define MAX_VICTIM_SEARCH 20 + +enum { + GC_NONE = 0, + GC_ERROR, + GC_OK, + GC_NEXT, + GC_BLOCKED, + GC_DONE, +}; + +struct f2fs_gc_kthread { + struct task_struct *f2fs_gc_task; + wait_queue_head_t gc_wait_queue_head; +}; + +struct inode_entry { + struct list_head list; + struct inode *inode; +}; + +/** + * inline functions + */ +static inline block_t free_user_blocks(struct f2fs_sb_info *sbi) +{ + if (free_segments(sbi) < overprovision_segments(sbi)) + return 0; + else + return (free_segments(sbi) - overprovision_segments(sbi)) + << sbi->log_blocks_per_seg; +} + +static inline block_t limit_invalid_user_blocks(struct f2fs_sb_info *sbi) +{ + return (long)(sbi->user_block_count * LIMIT_INVALID_BLOCK) / 100; +} + +static inline block_t limit_free_user_blocks(struct f2fs_sb_info *sbi) +{ + block_t reclaimable_user_blocks = sbi->user_block_count - + written_block_count(sbi); + return (long)(reclaimable_user_blocks * LIMIT_FREE_BLOCK) / 100; +} + +static inline long increase_sleep_time(long wait) +{ + wait += GC_THREAD_MIN_SLEEP_TIME; + if (wait > GC_THREAD_MAX_SLEEP_TIME) + wait = GC_THREAD_MAX_SLEEP_TIME; + return wait; +} + +static inline long decrease_sleep_time(long wait) +{ + wait -= GC_THREAD_MIN_SLEEP_TIME; + if (wait <= GC_THREAD_MIN_SLEEP_TIME) + wait = GC_THREAD_MIN_SLEEP_TIME; + return wait; +} + +static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi) +{ + block_t invalid_user_blocks = sbi->user_block_count - + written_block_count(sbi); + /* + * Background GC is triggered with the following condition. + * 1. There are a number of invalid blocks. + * 2. There is not enough free space. + */ + if (invalid_user_blocks > limit_invalid_user_blocks(sbi) && + free_user_blocks(sbi) < limit_free_user_blocks(sbi)) + return true; + return false; +} + +static inline int is_idle(struct f2fs_sb_info *sbi) +{ + struct block_device *bdev = sbi->sb->s_bdev; + struct request_queue *q = bdev_get_queue(bdev); + struct request_list *rl = &q->root_rl; + return !(rl->count[BLK_RW_SYNC]) && !(rl->count[BLK_RW_ASYNC]); +} + +static inline bool should_do_checkpoint(struct f2fs_sb_info *sbi) +{ + unsigned int pages_per_sec = sbi->segs_per_sec * + (1 << sbi->log_blocks_per_seg); + int node_secs = ((get_pages(sbi, F2FS_DIRTY_NODES) + pages_per_sec - 1) + >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; + int dent_secs = ((get_pages(sbi, F2FS_DIRTY_DENTS) + pages_per_sec - 1) + >> sbi->log_blocks_per_seg) / sbi->segs_per_sec; + return free_sections(sbi) <= (node_secs + 2 * dent_secs + 2); +} -- cgit v0.10.2 From d624c96fb3249e5d3dcf4e60a805e5e6b0dd7d91 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:13:32 +0900 Subject: f2fs: add recovery routines for roll-forward This adds roll-forward routines to recover fsynced data. - F2FS uses basically roll-back model with checkpointing. - In order to implement fsync(), there are two approaches as follows. 1. A roll-back model with checkpointing at every fsync() : This is a naive method, but suffers from very low performance. 2. A roll-forward model : F2FS adopts this model where all the fsynced data should be recovered, which were written after checkpointing was done. In order to figure out the data, F2FS keeps a "fsync" mark in direct node blocks. In addition, F2FS remains the location of next node block in each direct node block for reconstructing the chain of node blocks during the recovery. - In order to enhance the performance, F2FS keeps a "dentry" mark also in direct node blocks. If this is set during the recovery, F2FS replays adding a dentry. Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c new file mode 100644 index 0000000..7a43df0 --- /dev/null +++ b/fs/f2fs/recovery.c @@ -0,0 +1,375 @@ +/** + * fs/f2fs/recovery.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include "f2fs.h" +#include "node.h" +#include "segment.h" + +static struct kmem_cache *fsync_entry_slab; + +bool space_for_roll_forward(struct f2fs_sb_info *sbi) +{ + if (sbi->last_valid_block_count + sbi->alloc_valid_block_count + > sbi->user_block_count) + return false; + return true; +} + +static struct fsync_inode_entry *get_fsync_inode(struct list_head *head, + nid_t ino) +{ + struct list_head *this; + struct fsync_inode_entry *entry; + + list_for_each(this, head) { + entry = list_entry(this, struct fsync_inode_entry, list); + if (entry->inode->i_ino == ino) + return entry; + } + return NULL; +} + +static int recover_dentry(struct page *ipage, struct inode *inode) +{ + struct f2fs_node *raw_node = (struct f2fs_node *)kmap(ipage); + struct f2fs_inode *raw_inode = &(raw_node->i); + struct dentry dent, parent; + struct f2fs_dir_entry *de; + struct page *page; + struct inode *dir; + int err = 0; + + if (!is_dent_dnode(ipage)) + goto out; + + dir = f2fs_iget(inode->i_sb, le32_to_cpu(raw_inode->i_pino)); + if (IS_ERR(dir)) { + err = -EINVAL; + goto out; + } + + parent.d_inode = dir; + dent.d_parent = &parent; + dent.d_name.len = le32_to_cpu(raw_inode->i_namelen); + dent.d_name.name = raw_inode->i_name; + + de = f2fs_find_entry(dir, &dent.d_name, &page); + if (de) { + kunmap(page); + f2fs_put_page(page, 0); + } else { + f2fs_add_link(&dent, inode); + } + iput(dir); +out: + kunmap(ipage); + return err; +} + +static int recover_inode(struct inode *inode, struct page *node_page) +{ + void *kaddr = page_address(node_page); + struct f2fs_node *raw_node = (struct f2fs_node *)kaddr; + struct f2fs_inode *raw_inode = &(raw_node->i); + + inode->i_mode = le32_to_cpu(raw_inode->i_mode); + i_size_write(inode, le64_to_cpu(raw_inode->i_size)); + inode->i_atime.tv_sec = le64_to_cpu(raw_inode->i_mtime); + inode->i_ctime.tv_sec = le64_to_cpu(raw_inode->i_ctime); + inode->i_mtime.tv_sec = le64_to_cpu(raw_inode->i_mtime); + inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); + inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec); + inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); + + return recover_dentry(node_page, inode); +} + +static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) +{ + unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver); + struct curseg_info *curseg; + struct page *page; + block_t blkaddr; + int err = 0; + + /* get node pages in the current segment */ + curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); + blkaddr = START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff; + + /* read node page */ + page = alloc_page(GFP_F2FS_ZERO); + if (IS_ERR(page)) + return PTR_ERR(page); + lock_page(page); + + while (1) { + struct fsync_inode_entry *entry; + + if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC)) + goto out; + + if (cp_ver != cpver_of_node(page)) + goto out; + + if (!is_fsync_dnode(page)) + goto next; + + entry = get_fsync_inode(head, ino_of_node(page)); + if (entry) { + entry->blkaddr = blkaddr; + if (IS_INODE(page) && is_dent_dnode(page)) + set_inode_flag(F2FS_I(entry->inode), + FI_INC_LINK); + } else { + if (IS_INODE(page) && is_dent_dnode(page)) { + if (recover_inode_page(sbi, page)) { + err = -ENOMEM; + goto out; + } + } + + /* add this fsync inode to the list */ + entry = kmem_cache_alloc(fsync_entry_slab, GFP_NOFS); + if (!entry) { + err = -ENOMEM; + goto out; + } + + INIT_LIST_HEAD(&entry->list); + list_add_tail(&entry->list, head); + + entry->inode = f2fs_iget(sbi->sb, ino_of_node(page)); + if (IS_ERR(entry->inode)) { + err = PTR_ERR(entry->inode); + goto out; + } + entry->blkaddr = blkaddr; + } + if (IS_INODE(page)) { + err = recover_inode(entry->inode, page); + if (err) + goto out; + } +next: + /* check next segment */ + blkaddr = next_blkaddr_of_node(page); + ClearPageUptodate(page); + } +out: + unlock_page(page); + __free_pages(page, 0); + return err; +} + +static void destroy_fsync_dnodes(struct f2fs_sb_info *sbi, + struct list_head *head) +{ + struct list_head *this; + struct fsync_inode_entry *entry; + list_for_each(this, head) { + entry = list_entry(this, struct fsync_inode_entry, list); + iput(entry->inode); + list_del(&entry->list); + kmem_cache_free(fsync_entry_slab, entry); + } +} + +static void check_index_in_prev_nodes(struct f2fs_sb_info *sbi, + block_t blkaddr) +{ + struct seg_entry *sentry; + unsigned int segno = GET_SEGNO(sbi, blkaddr); + unsigned short blkoff = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & + (sbi->blocks_per_seg - 1); + struct f2fs_summary sum; + nid_t ino; + void *kaddr; + struct inode *inode; + struct page *node_page; + block_t bidx; + int i; + + sentry = get_seg_entry(sbi, segno); + if (!f2fs_test_bit(blkoff, sentry->cur_valid_map)) + return; + + /* Get the previous summary */ + for (i = CURSEG_WARM_DATA; i <= CURSEG_COLD_DATA; i++) { + struct curseg_info *curseg = CURSEG_I(sbi, i); + if (curseg->segno == segno) { + sum = curseg->sum_blk->entries[blkoff]; + break; + } + } + if (i > CURSEG_COLD_DATA) { + struct page *sum_page = get_sum_page(sbi, segno); + struct f2fs_summary_block *sum_node; + kaddr = page_address(sum_page); + sum_node = (struct f2fs_summary_block *)kaddr; + sum = sum_node->entries[blkoff]; + f2fs_put_page(sum_page, 1); + } + + /* Get the node page */ + node_page = get_node_page(sbi, le32_to_cpu(sum.nid)); + bidx = start_bidx_of_node(ofs_of_node(node_page)) + + le16_to_cpu(sum.ofs_in_node); + ino = ino_of_node(node_page); + f2fs_put_page(node_page, 1); + + /* Deallocate previous index in the node page */ + inode = f2fs_iget_nowait(sbi->sb, ino); + truncate_hole(inode, bidx, bidx + 1); + iput(inode); +} + +static void do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, + struct page *page, block_t blkaddr) +{ + unsigned int start, end; + struct dnode_of_data dn; + struct f2fs_summary sum; + struct node_info ni; + + start = start_bidx_of_node(ofs_of_node(page)); + if (IS_INODE(page)) + end = start + ADDRS_PER_INODE; + else + end = start + ADDRS_PER_BLOCK; + + set_new_dnode(&dn, inode, NULL, NULL, 0); + if (get_dnode_of_data(&dn, start, 0)) + return; + + wait_on_page_writeback(dn.node_page); + + get_node_info(sbi, dn.nid, &ni); + BUG_ON(ni.ino != ino_of_node(page)); + BUG_ON(ofs_of_node(dn.node_page) != ofs_of_node(page)); + + for (; start < end; start++) { + block_t src, dest; + + src = datablock_addr(dn.node_page, dn.ofs_in_node); + dest = datablock_addr(page, dn.ofs_in_node); + + if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR) { + if (src == NULL_ADDR) { + int err = reserve_new_block(&dn); + /* We should not get -ENOSPC */ + BUG_ON(err); + } + + /* Check the previous node page having this index */ + check_index_in_prev_nodes(sbi, dest); + + set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version); + + /* write dummy data page */ + recover_data_page(sbi, NULL, &sum, src, dest); + update_extent_cache(dest, &dn); + } + dn.ofs_in_node++; + } + + /* write node page in place */ + set_summary(&sum, dn.nid, 0, 0); + if (IS_INODE(dn.node_page)) + sync_inode_page(&dn); + + copy_node_footer(dn.node_page, page); + fill_node_footer(dn.node_page, dn.nid, ni.ino, + ofs_of_node(page), false); + set_page_dirty(dn.node_page); + + recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr); + f2fs_put_dnode(&dn); +} + +static void recover_data(struct f2fs_sb_info *sbi, + struct list_head *head, int type) +{ + unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver); + struct curseg_info *curseg; + struct page *page; + block_t blkaddr; + + /* get node pages in the current segment */ + curseg = CURSEG_I(sbi, type); + blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); + + /* read node page */ + page = alloc_page(GFP_NOFS | __GFP_ZERO); + if (IS_ERR(page)) + return; + lock_page(page); + + while (1) { + struct fsync_inode_entry *entry; + + if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC)) + goto out; + + if (cp_ver != cpver_of_node(page)) + goto out; + + entry = get_fsync_inode(head, ino_of_node(page)); + if (!entry) + goto next; + + do_recover_data(sbi, entry->inode, page, blkaddr); + + if (entry->blkaddr == blkaddr) { + iput(entry->inode); + list_del(&entry->list); + kmem_cache_free(fsync_entry_slab, entry); + } +next: + /* check next segment */ + blkaddr = next_blkaddr_of_node(page); + ClearPageUptodate(page); + } +out: + unlock_page(page); + __free_pages(page, 0); + + allocate_new_segments(sbi); +} + +void recover_fsync_data(struct f2fs_sb_info *sbi) +{ + struct list_head inode_list; + + fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", + sizeof(struct fsync_inode_entry), NULL); + if (unlikely(!fsync_entry_slab)) + return; + + INIT_LIST_HEAD(&inode_list); + + /* step #1: find fsynced inode numbers */ + if (find_fsync_dnodes(sbi, &inode_list)) + goto out; + + if (list_empty(&inode_list)) + goto out; + + /* step #2: recover data */ + sbi->por_doing = 1; + recover_data(sbi, &inode_list, CURSEG_WARM_NODE); + sbi->por_doing = 0; + BUG_ON(!list_empty(&inode_list)); +out: + destroy_fsync_dnodes(sbi, &inode_list); + kmem_cache_destroy(fsync_entry_slab); + write_checkpoint(sbi, false, false); +} -- cgit v0.10.2 From 902829aa0b722511369e4e6193e66390bc58e0a2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 3 Nov 2012 06:50:41 +0900 Subject: f2fs: move proc files to debugfs This moves all of the f2fs debugging files into debugfs. The files are located in /sys/kernel/debug/f2fs/ Note, I think we are generating all of the same information in each of the files for every unique f2fs filesystem in the machine. This copies the functionality that was present in the proc files, but this should be fixed up in the future. Signed-off-by: Greg Kroah-Hartman [jaegeuk.kim@samsung.com: merged 3 debugfs entries into a *status* entry] Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c new file mode 100644 index 0000000..a56181c --- /dev/null +++ b/fs/f2fs/debug.c @@ -0,0 +1,361 @@ +/** + * f2fs debugging statistics + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * Copyright (c) 2012 Linux Foundation + * Copyright (c) 2012 Greg Kroah-Hartman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "f2fs.h" +#include "node.h" +#include "segment.h" +#include "gc.h" + +static LIST_HEAD(f2fs_stat_list); +static struct dentry *debugfs_root; + +void update_general_status(struct f2fs_sb_info *sbi) +{ + struct f2fs_stat_info *si = sbi->stat_info; + int i; + + /* valid check of the segment numbers */ + si->hit_ext = sbi->read_hit_ext; + si->total_ext = sbi->total_hit_ext; + si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES); + si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS); + si->ndirty_dirs = sbi->n_dirty_dirs; + si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META); + si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; + si->rsvd_segs = reserved_segments(sbi); + si->overp_segs = overprovision_segments(sbi); + si->valid_count = valid_user_blocks(sbi); + si->valid_node_count = valid_node_count(sbi); + si->valid_inode_count = valid_inode_count(sbi); + si->utilization = utilization(sbi); + + si->free_segs = free_segments(sbi); + si->free_secs = free_sections(sbi); + si->prefree_count = prefree_segments(sbi); + si->dirty_count = dirty_segments(sbi); + si->node_pages = sbi->node_inode->i_mapping->nrpages; + si->meta_pages = sbi->meta_inode->i_mapping->nrpages; + si->nats = NM_I(sbi)->nat_cnt; + si->sits = SIT_I(sbi)->dirty_sentries; + si->fnids = NM_I(sbi)->fcnt; + si->bg_gc = sbi->bg_gc; + si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) + * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) + / 2; + si->util_valid = (int)(written_block_count(sbi) >> + sbi->log_blocks_per_seg) + * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) + / 2; + si->util_invalid = 50 - si->util_free - si->util_valid; + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) { + struct curseg_info *curseg = CURSEG_I(sbi, i); + si->curseg[i] = curseg->segno; + si->cursec[i] = curseg->segno / sbi->segs_per_sec; + si->curzone[i] = si->cursec[i] / sbi->secs_per_zone; + } + + for (i = 0; i < 2; i++) { + si->segment_count[i] = sbi->segment_count[i]; + si->block_count[i] = sbi->block_count[i]; + } +} + +/** + * This function calculates BDF of every segments + */ +static void update_sit_info(struct f2fs_sb_info *sbi) +{ + struct f2fs_stat_info *si = sbi->stat_info; + unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist; + struct sit_info *sit_i = SIT_I(sbi); + unsigned int segno, vblocks; + int ndirty = 0; + + bimodal = 0; + total_vblocks = 0; + blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg); + hblks_per_sec = blks_per_sec / 2; + mutex_lock(&sit_i->sentry_lock); + for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) { + vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec); + dist = abs(vblocks - hblks_per_sec); + bimodal += dist * dist; + + if (vblocks > 0 && vblocks < blks_per_sec) { + total_vblocks += vblocks; + ndirty++; + } + } + mutex_unlock(&sit_i->sentry_lock); + dist = sbi->total_sections * hblks_per_sec * hblks_per_sec / 100; + si->bimodal = bimodal / dist; + if (si->dirty_count) + si->avg_vblocks = total_vblocks / ndirty; + else + si->avg_vblocks = 0; +} + +/** + * This function calculates memory footprint. + */ +static void update_mem_info(struct f2fs_sb_info *sbi) +{ + struct f2fs_stat_info *si = sbi->stat_info; + unsigned npages; + + if (si->base_mem) + goto get_cache; + + si->base_mem = sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize; + si->base_mem += 2 * sizeof(struct f2fs_inode_info); + si->base_mem += sizeof(*sbi->ckpt); + + /* build sm */ + si->base_mem += sizeof(struct f2fs_sm_info); + + /* build sit */ + si->base_mem += sizeof(struct sit_info); + si->base_mem += TOTAL_SEGS(sbi) * sizeof(struct seg_entry); + si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi)); + si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * TOTAL_SEGS(sbi); + if (sbi->segs_per_sec > 1) + si->base_mem += sbi->total_sections * + sizeof(struct sec_entry); + si->base_mem += __bitmap_size(sbi, SIT_BITMAP); + + /* build free segmap */ + si->base_mem += sizeof(struct free_segmap_info); + si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi)); + si->base_mem += f2fs_bitmap_size(sbi->total_sections); + + /* build curseg */ + si->base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE; + si->base_mem += PAGE_CACHE_SIZE * NR_CURSEG_TYPE; + + /* build dirty segmap */ + si->base_mem += sizeof(struct dirty_seglist_info); + si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi)); + si->base_mem += 2 * f2fs_bitmap_size(TOTAL_SEGS(sbi)); + + /* buld nm */ + si->base_mem += sizeof(struct f2fs_nm_info); + si->base_mem += __bitmap_size(sbi, NAT_BITMAP); + + /* build gc */ + si->base_mem += sizeof(struct f2fs_gc_kthread); + +get_cache: + /* free nids */ + si->cache_mem = NM_I(sbi)->fcnt; + si->cache_mem += NM_I(sbi)->nat_cnt; + npages = sbi->node_inode->i_mapping->nrpages; + si->cache_mem += npages << PAGE_CACHE_SHIFT; + npages = sbi->meta_inode->i_mapping->nrpages; + si->cache_mem += npages << PAGE_CACHE_SHIFT; + si->cache_mem += sbi->n_orphans * sizeof(struct orphan_inode_entry); + si->cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry); +} + +static int stat_show(struct seq_file *s, void *v) +{ + struct f2fs_stat_info *si, *next; + int i = 0; + int j; + + list_for_each_entry_safe(si, next, &f2fs_stat_list, stat_list) { + + mutex_lock(&si->stat_lock); + if (!si->sbi) { + mutex_unlock(&si->stat_lock); + continue; + } + update_general_status(si->sbi); + + seq_printf(s, "\n=====[ partition info. #%d ]=====\n", i++); + seq_printf(s, "[SB: 1] [CP: 2] [NAT: %d] [SIT: %d] ", + si->nat_area_segs, si->sit_area_segs); + seq_printf(s, "[SSA: %d] [MAIN: %d", + si->ssa_area_segs, si->main_area_segs); + seq_printf(s, "(OverProv:%d Resv:%d)]\n\n", + si->overp_segs, si->rsvd_segs); + seq_printf(s, "Utilization: %d%% (%d valid blocks)\n", + si->utilization, si->valid_count); + seq_printf(s, " - Node: %u (Inode: %u, ", + si->valid_node_count, si->valid_inode_count); + seq_printf(s, "Other: %u)\n - Data: %u\n", + si->valid_node_count - si->valid_inode_count, + si->valid_count - si->valid_node_count); + seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n", + si->main_area_segs, si->main_area_sections, + si->main_area_zones); + seq_printf(s, " - COLD data: %d, %d, %d\n", + si->curseg[CURSEG_COLD_DATA], + si->cursec[CURSEG_COLD_DATA], + si->curzone[CURSEG_COLD_DATA]); + seq_printf(s, " - WARM data: %d, %d, %d\n", + si->curseg[CURSEG_WARM_DATA], + si->cursec[CURSEG_WARM_DATA], + si->curzone[CURSEG_WARM_DATA]); + seq_printf(s, " - HOT data: %d, %d, %d\n", + si->curseg[CURSEG_HOT_DATA], + si->cursec[CURSEG_HOT_DATA], + si->curzone[CURSEG_HOT_DATA]); + seq_printf(s, " - Dir dnode: %d, %d, %d\n", + si->curseg[CURSEG_HOT_NODE], + si->cursec[CURSEG_HOT_NODE], + si->curzone[CURSEG_HOT_NODE]); + seq_printf(s, " - File dnode: %d, %d, %d\n", + si->curseg[CURSEG_WARM_NODE], + si->cursec[CURSEG_WARM_NODE], + si->curzone[CURSEG_WARM_NODE]); + seq_printf(s, " - Indir nodes: %d, %d, %d\n", + si->curseg[CURSEG_COLD_NODE], + si->cursec[CURSEG_COLD_NODE], + si->curzone[CURSEG_COLD_NODE]); + seq_printf(s, "\n - Valid: %d\n - Dirty: %d\n", + si->main_area_segs - si->dirty_count - + si->prefree_count - si->free_segs, + si->dirty_count); + seq_printf(s, " - Prefree: %d\n - Free: %d (%d)\n\n", + si->prefree_count, si->free_segs, si->free_secs); + seq_printf(s, "GC calls: %d (BG: %d)\n", + si->call_count, si->bg_gc); + seq_printf(s, " - data segments : %d\n", si->data_segs); + seq_printf(s, " - node segments : %d\n", si->node_segs); + seq_printf(s, "Try to move %d blocks\n", si->tot_blks); + seq_printf(s, " - data blocks : %d\n", si->data_blks); + seq_printf(s, " - node blocks : %d\n", si->node_blks); + seq_printf(s, "\nExtent Hit Ratio: %d / %d\n", + si->hit_ext, si->total_ext); + seq_printf(s, "\nBalancing F2FS Async:\n"); + seq_printf(s, " - nodes %4d in %4d\n", + si->ndirty_node, si->node_pages); + seq_printf(s, " - dents %4d in dirs:%4d\n", + si->ndirty_dent, si->ndirty_dirs); + seq_printf(s, " - meta %4d in %4d\n", + si->ndirty_meta, si->meta_pages); + seq_printf(s, " - NATs %5d > %lu\n", + si->nats, NM_WOUT_THRESHOLD); + seq_printf(s, " - SITs: %5d\n - free_nids: %5d\n", + si->sits, si->fnids); + seq_printf(s, "\nDistribution of User Blocks:"); + seq_printf(s, " [ valid | invalid | free ]\n"); + seq_printf(s, " ["); + + for (j = 0; j < si->util_valid; j++) + seq_printf(s, "-"); + seq_printf(s, "|"); + + for (j = 0; j < si->util_invalid; j++) + seq_printf(s, "-"); + seq_printf(s, "|"); + + for (j = 0; j < si->util_free; j++) + seq_printf(s, "-"); + seq_printf(s, "]\n\n"); + seq_printf(s, "SSR: %u blocks in %u segments\n", + si->block_count[SSR], si->segment_count[SSR]); + seq_printf(s, "LFS: %u blocks in %u segments\n", + si->block_count[LFS], si->segment_count[LFS]); + + /* segment usage info */ + update_sit_info(si->sbi); + seq_printf(s, "\nBDF: %u, avg. vblocks: %u\n", + si->bimodal, si->avg_vblocks); + + /* memory footprint */ + update_mem_info(si->sbi); + seq_printf(s, "\nMemory: %u KB = static: %u + cached: %u\n", + (si->base_mem + si->cache_mem) >> 10, + si->base_mem >> 10, si->cache_mem >> 10); + mutex_unlock(&si->stat_lock); + } + return 0; +} + +static int stat_open(struct inode *inode, struct file *file) +{ + return single_open(file, stat_show, inode->i_private); +} + +static const struct file_operations stat_fops = { + .open = stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int init_stats(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); + struct f2fs_stat_info *si; + + sbi->stat_info = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL); + if (!sbi->stat_info) + return -ENOMEM; + + si = sbi->stat_info; + mutex_init(&si->stat_lock); + list_add_tail(&si->stat_list, &f2fs_stat_list); + + si->all_area_segs = le32_to_cpu(raw_super->segment_count); + si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit); + si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat); + si->ssa_area_segs = le32_to_cpu(raw_super->segment_count_ssa); + si->main_area_segs = le32_to_cpu(raw_super->segment_count_main); + si->main_area_sections = le32_to_cpu(raw_super->section_count); + si->main_area_zones = si->main_area_sections / + le32_to_cpu(raw_super->secs_per_zone); + si->sbi = sbi; + return 0; +} + +int f2fs_build_stats(struct f2fs_sb_info *sbi) +{ + int retval; + + retval = init_stats(sbi); + if (retval) + return retval; + + if (!debugfs_root) + debugfs_root = debugfs_create_dir("f2fs", NULL); + + debugfs_create_file("status", S_IRUGO, debugfs_root, NULL, &stat_fops); + return 0; +} + +void f2fs_destroy_stats(struct f2fs_sb_info *sbi) +{ + struct f2fs_stat_info *si = sbi->stat_info; + + list_del(&si->stat_list); + mutex_lock(&si->stat_lock); + si->sbi = NULL; + mutex_unlock(&si->stat_lock); + kfree(sbi->stat_info); +} + +void destroy_root_stats(void) +{ + debugfs_remove_recursive(debugfs_root); + debugfs_root = NULL; +} -- cgit v0.10.2 From a14d53937cc850d5631e0f809986751770ef65ac Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 2 Nov 2012 17:25:27 +0900 Subject: f2fs: update Kconfig and Makefile This adds Makefile and Kconfig for f2fs, and updates Makefile and Kconfig files in the fs directory. Signed-off-by: Jaegeuk Kim diff --git a/fs/Kconfig b/fs/Kconfig index f95ae3a..e352b37 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -220,6 +220,7 @@ source "fs/pstore/Kconfig" source "fs/sysv/Kconfig" source "fs/ufs/Kconfig" source "fs/exofs/Kconfig" +source "fs/f2fs/Kconfig" endif # MISC_FILESYSTEMS diff --git a/fs/Makefile b/fs/Makefile index 1d7af79..9d53192 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -123,6 +123,7 @@ obj-$(CONFIG_DEBUG_FS) += debugfs/ obj-$(CONFIG_OCFS2_FS) += ocfs2/ obj-$(CONFIG_BTRFS_FS) += btrfs/ obj-$(CONFIG_GFS2_FS) += gfs2/ +obj-$(CONFIG_F2FS_FS) += f2fs/ obj-y += exofs/ # Multiple modules obj-$(CONFIG_CEPH_FS) += ceph/ obj-$(CONFIG_PSTORE) += pstore/ diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig new file mode 100644 index 0000000..37a6b8e --- /dev/null +++ b/fs/f2fs/Kconfig @@ -0,0 +1,52 @@ +config F2FS_FS + tristate "F2FS filesystem support (EXPERIMENTAL)" + help + F2FS is based on Log-structured File System (LFS), which supports + versatile "flash-friendly" features. The design has been focused on + addressing the fundamental issues in LFS, which are snowball effect + of wandering tree and high cleaning overhead. + + Since flash-based storages show different characteristics according to + the internal geometry or flash memory management schemes aka FTL, F2FS + and tools support various parameters not only for configuring on-disk + layout, but also for selecting allocation and cleaning algorithms. + + If unsure, say N. + +config F2FS_STAT_FS + bool "F2FS Status Information" + depends on F2FS_FS && DEBUG_FS + default y + help + /sys/kernel/debug/f2fs/ contains information about all the partitions + mounted as f2fs. Each file shows the whole f2fs information. + + /sys/kernel/debug/f2fs/status includes: + - major file system information managed by f2fs currently + - average SIT information about whole segments + - current memory footprint consumed by f2fs. + +config F2FS_FS_XATTR + bool "F2FS extended attributes" + depends on F2FS_FS + default y + help + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + for details). + + If unsure, say N. + +config F2FS_FS_POSIX_ACL + bool "F2FS Access Control Lists" + depends on F2FS_FS_XATTR + select FS_POSIX_ACL + default y + help + Posix Access Control Lists (ACLs) support permissions for users and + gourps beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the POSIX ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile new file mode 100644 index 0000000..27a0820 --- /dev/null +++ b/fs/f2fs/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_F2FS_FS) += f2fs.o + +f2fs-y := dir.o file.o inode.o namei.o hash.o super.o +f2fs-y += checkpoint.o gc.o data.o node.o segment.o recovery.o +f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o +f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o +f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o -- cgit v0.10.2 From 5bb446a2890f4dfd62ce4d9fcc982f8ea3c20010 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 27 Nov 2012 14:36:14 +0900 Subject: f2fs: update the f2fs document I moved the f2fs-tools.git into kernel.org. And I added a new mailing list, linux-f2fs-devel@lists.sourceforge.net. Signed-off-by: Jaegeuk Kim diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index 6ce5407..dee3960 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -19,7 +19,11 @@ F2FS and its tools support various parameters not only for configuring on-disk layout, but also for selecting allocation and cleaning algorithms. The file system formatting tool, "mkfs.f2fs", is available from the following -download page: http://sourceforge.net/projects/f2fs-tools/ +git tree: +>> git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git + +For reporting bugs and sending patches, please use the following mailing list: +>> linux-f2fs-devel@lists.sourceforge.net ================================================================================ BACKGROUND AND DESIGN ISSUES -- cgit v0.10.2 From cf0e3a64cad19acd5904946d0647d751c1671620 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 27 Nov 2012 16:02:16 +0530 Subject: f2fs: remove unneeded version.h header file from f2fs.h Including is not necessary. Signed-off-by: Sachin Kamat diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 7aa70b5..d3f5a70 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From 25ca923b2a766b9c93b63777ead351137533a623 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 28 Nov 2012 16:12:41 +0900 Subject: f2fs: fix endian conversion bugs reported by sparse This patch should resolve the bugs reported by the sparse tool. Initial reports were written by "kbuild test robot" managed by fengguang.wu. In my local machines, I've tested also by running: > make C=2 CF="-D__CHECK_ENDIAN__" Accordingly, I've found lots of warnings and bugs related to the endian conversion. And I've fixed all at this moment. Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index ab743f9..7c18f8e 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -268,7 +268,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) { block_t start_blk, orphan_blkaddr, i, j; - if (!(F2FS_CKPT(sbi)->ckpt_flags & CP_ORPHAN_PRESENT_FLAG)) + if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG)) return 0; sbi->por_doing = 1; @@ -287,7 +287,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) f2fs_put_page(page, 1); } /* clear Orphan Flag */ - F2FS_CKPT(sbi)->ckpt_flags &= (~CP_ORPHAN_PRESENT_FLAG); + clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG); sbi->por_doing = 0; return 0; } @@ -376,7 +376,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, pre_version = le64_to_cpu(cp_block->checkpoint_ver); /* Read the 2nd cp block in this CP pack */ - cp_addr += le64_to_cpu(cp_block->cp_pack_total_block_count) - 1; + cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1; cp_page_2 = get_meta_page(sbi, cp_addr); cp_block = (struct f2fs_checkpoint *)page_address(cp_page_2); @@ -605,8 +605,8 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) block_t start_blk; struct page *cp_page; unsigned int data_sum_blocks, orphan_blocks; + unsigned int crc32 = 0; void *kaddr; - __u32 crc32 = 0; int i; /* Flush all the NAT/SIT pages */ @@ -646,33 +646,35 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) /* 2 cp + n data seg summary + orphan inode blocks */ data_sum_blocks = npages_for_summary_flush(sbi); if (data_sum_blocks < 3) - ckpt->ckpt_flags |= CP_COMPACT_SUM_FLAG; + set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); else - ckpt->ckpt_flags &= (~CP_COMPACT_SUM_FLAG); + clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); orphan_blocks = (sbi->n_orphans + F2FS_ORPHANS_PER_BLOCK - 1) / F2FS_ORPHANS_PER_BLOCK; - ckpt->cp_pack_start_sum = 1 + orphan_blocks; - ckpt->cp_pack_total_block_count = 2 + data_sum_blocks + orphan_blocks; + ckpt->cp_pack_start_sum = cpu_to_le32(1 + orphan_blocks); if (is_umount) { - ckpt->ckpt_flags |= CP_UMOUNT_FLAG; - ckpt->cp_pack_total_block_count += NR_CURSEG_NODE_TYPE; + set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); + ckpt->cp_pack_total_block_count = cpu_to_le32(2 + + data_sum_blocks + orphan_blocks + NR_CURSEG_NODE_TYPE); } else { - ckpt->ckpt_flags &= (~CP_UMOUNT_FLAG); + clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG); + ckpt->cp_pack_total_block_count = cpu_to_le32(2 + + data_sum_blocks + orphan_blocks); } if (sbi->n_orphans) - ckpt->ckpt_flags |= CP_ORPHAN_PRESENT_FLAG; + set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); else - ckpt->ckpt_flags &= (~CP_ORPHAN_PRESENT_FLAG); + clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); /* update SIT/NAT bitmap */ get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP)); get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP)); crc32 = f2fs_crc32(ckpt, le32_to_cpu(ckpt->checksum_offset)); - *(__u32 *)((unsigned char *)ckpt + + *(__le32 *)((unsigned char *)ckpt + le32_to_cpu(ckpt->checksum_offset)) = cpu_to_le32(crc32); @@ -716,7 +718,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) sbi->alloc_valid_block_count = 0; /* Here, we only have one bio having CP pack */ - if (sbi->ckpt->ckpt_flags & CP_ERROR_FLAG) + if (is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) sbi->sb->s_flags |= MS_RDONLY; else sync_meta_pages(sbi, META_FLUSH, LONG_MAX); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index c2fd0a8..5635cc5 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -545,7 +545,7 @@ redirty_out: #define MAX_DESIRED_PAGES_WP 4096 -int f2fs_write_data_pages(struct address_space *mapping, +static int f2fs_write_data_pages(struct address_space *mapping, struct writeback_control *wbc) { struct inode *inode = mapping->host; diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index a56181c..fb62960 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -27,7 +27,7 @@ static LIST_HEAD(f2fs_stat_list); static struct dentry *debugfs_root; -void update_general_status(struct f2fs_sb_info *sbi) +static void update_general_status(struct f2fs_sb_info *sbi) { struct f2fs_stat_info *si = sbi->stat_info; int i; diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 5975568..5ec7a06 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -80,7 +80,7 @@ static bool early_match_name(const char *name, int namelen, if (le16_to_cpu(de->name_len) != namelen) return false; - if (le32_to_cpu(de->hash_code) != namehash) + if (de->hash_code != namehash) return false; return true; @@ -143,7 +143,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, nbucket = dir_buckets(level); nblock = bucket_blocks(level); - bidx = dir_block_index(level, namehash % nbucket); + bidx = dir_block_index(level, le32_to_cpu(namehash) % nbucket); end_block = bidx + nblock; for (; bidx < end_block; bidx++) { @@ -406,7 +406,7 @@ start: nbucket = dir_buckets(level); nblock = bucket_blocks(level); - bidx = dir_block_index(level, (dentry_hash % nbucket)); + bidx = dir_block_index(level, (le32_to_cpu(dentry_hash) % nbucket)); for (block = bidx; block <= (bidx + nblock - 1); block++) { mutex_lock_op(sbi, DENTRY_OPS); @@ -437,7 +437,7 @@ add_dentry: wait_on_page_writeback(dentry_page); de = &dentry_blk->dentry[bit_pos]; - de->hash_code = cpu_to_le32(dentry_hash); + de->hash_code = dentry_hash; de->name_len = cpu_to_le16(namelen); memcpy(dentry_blk->filename[bit_pos], name, namelen); de->ino = cpu_to_le32(inode->i_ino); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d3f5a70..8d7fde1 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -463,6 +463,26 @@ static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi) sbi->s_dirty = 0; } +static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) +{ + unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); + return ckpt_flags & f; +} + +static inline void set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) +{ + unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); + ckpt_flags |= f; + cp->ckpt_flags = cpu_to_le32(ckpt_flags); +} + +static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) +{ + unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); + ckpt_flags &= (~f); + cp->ckpt_flags = cpu_to_le32(ckpt_flags); +} + static inline void mutex_lock_op(struct f2fs_sb_info *sbi, enum lock_type t) { mutex_lock_nested(&sbi->fs_lock[t], t); @@ -577,7 +597,8 @@ static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag) static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); - int offset = (flag == NAT_BITMAP) ? ckpt->sit_ver_bitmap_bytesize : 0; + int offset = (flag == NAT_BITMAP) ? + le32_to_cpu(ckpt->sit_ver_bitmap_bytesize) : 0; return &ckpt->sit_nat_version_bitmap + offset; } @@ -587,7 +608,7 @@ static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi) struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); unsigned long long ckpt_version = le64_to_cpu(ckpt->checkpoint_ver); - start_addr = le64_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); + start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); /* * odd numbered checkpoint should at cp segment 0 diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c index 098a196..beb155e 100644 --- a/fs/f2fs/hash.c +++ b/fs/f2fs/hash.c @@ -92,7 +92,6 @@ f2fs_hash_t f2fs_dentry_hash(const char *name, int len) hash = buf[0]; minor_hash = buf[1]; - f2fs_hash = hash; - f2fs_hash &= ~F2FS_HASH_COL_BIT; + f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT); return f2fs_hash; } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 216f04d..5d421fe 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1445,8 +1445,8 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) memcpy(dst, src, (unsigned long)&src->i.i_ext - (unsigned long)&src->i); dst->i.i_size = 0; - dst->i.i_blocks = 1; - dst->i.i_links = 1; + dst->i.i_blocks = cpu_to_le64(1); + dst->i.i_links = cpu_to_le32(1); dst->i.i_xattr_nid = 0; new_ni = old_ni; diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 5d525ed..0ab92d6 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -177,7 +177,7 @@ static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr) void *kaddr = page_address(page); struct f2fs_node *rn = (struct f2fs_node *)kaddr; rn->footer.cp_ver = ckpt->checkpoint_ver; - rn->footer.next_blkaddr = blkaddr; + rn->footer.next_blkaddr = cpu_to_le32(blkaddr); } static inline nid_t ino_of_node(struct page *node_page) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 7a43df0..222a7bb 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -81,7 +81,7 @@ static int recover_inode(struct inode *inode, struct page *node_page) struct f2fs_node *raw_node = (struct f2fs_node *)kaddr; struct f2fs_inode *raw_inode = &(raw_node->i); - inode->i_mode = le32_to_cpu(raw_inode->i_mode); + inode->i_mode = le16_to_cpu(raw_inode->i_mode); i_size_write(inode, le64_to_cpu(raw_inode->i_size)); inode->i_atime.tv_sec = le64_to_cpu(raw_inode->i_mtime); inode->i_ctime.tv_sec = le64_to_cpu(raw_inode->i_ctime); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index ed7c079..d973c56 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -630,7 +630,7 @@ static void f2fs_end_io_write(struct bio *bio, int err) SetPageError(page); if (page->mapping) set_bit(AS_EIO, &page->mapping->flags); - p->sbi->ckpt->ckpt_flags |= CP_ERROR_FLAG; + set_ckpt_flags(p->sbi->ckpt, CP_ERROR_FLAG); set_page_dirty(page); } end_page_writeback(page); @@ -1067,7 +1067,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) segno = le32_to_cpu(ckpt->cur_data_segno[type]); blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - CURSEG_HOT_DATA]); - if (ckpt->ckpt_flags & CP_UMOUNT_FLAG) + if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type); else blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); @@ -1076,7 +1076,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) CURSEG_HOT_NODE]); blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - CURSEG_HOT_NODE]); - if (ckpt->ckpt_flags & CP_UMOUNT_FLAG) + if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, type - CURSEG_HOT_NODE); else @@ -1087,7 +1087,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) sum = (struct f2fs_summary_block *)page_address(new); if (IS_NODESEG(type)) { - if (ckpt->ckpt_flags & CP_UMOUNT_FLAG) { + if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) { struct f2fs_summary *ns = &sum->entries[0]; int i; for (i = 0; i < sbi->blocks_per_seg; i++, ns++) { @@ -1119,7 +1119,7 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi) { int type = CURSEG_HOT_DATA; - if (sbi->ckpt->ckpt_flags & CP_COMPACT_SUM_FLAG) { + if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { /* restore for compacted data summary */ if (read_compacted_summaries(sbi)) return -EINVAL; @@ -1208,7 +1208,7 @@ static void write_normal_summaries(struct f2fs_sb_info *sbi, void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) { - if (sbi->ckpt->ckpt_flags & CP_COMPACT_SUM_FLAG) + if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) write_compacted_summaries(sbi, start_blk); else write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA); @@ -1216,7 +1216,7 @@ void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) { - if (sbi->ckpt->ckpt_flags & CP_UMOUNT_FLAG) + if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); return; } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 8661c93..878bf38 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -89,7 +89,7 @@ static void f2fs_i_callback(struct rcu_head *head) kmem_cache_free(f2fs_inode_cachep, F2FS_I(inode)); } -void f2fs_destroy_inode(struct inode *inode) +static void f2fs_destroy_inode(struct inode *inode) { call_rcu(&inode->i_rcu, f2fs_i_callback); } @@ -445,7 +445,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) if (sanity_check_raw_super(raw_super)) goto free_sb_buf; - sb->s_maxbytes = max_file_size(raw_super->log_blocksize); + sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize)); sb->s_max_links = F2FS_LINK_MAX; get_random_bytes(&sbi->s_next_generation, sizeof(u32)); @@ -527,7 +527,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) /* if there are nt orphan nodes free them */ err = -EINVAL; - if (!(sbi->ckpt->ckpt_flags & CP_UMOUNT_FLAG) && + if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) && recover_orphan_inodes(sbi)) goto free_node_inode; @@ -547,7 +547,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) } /* recover fsynced data */ - if (!(sbi->ckpt->ckpt_flags & CP_UMOUNT_FLAG) && + if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) && !test_opt(sbi, DISABLE_ROLL_FORWARD)) recover_fsync_data(sbi); diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 1429ece..c2fbbc3 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -272,8 +272,8 @@ struct f2fs_sit_block { * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node) */ #define ENTRIES_IN_SUM 512 -#define SUMMARY_SIZE (sizeof(struct f2fs_summary)) -#define SUM_FOOTER_SIZE (sizeof(struct summary_footer)) +#define SUMMARY_SIZE (7) /* sizeof(struct summary) */ +#define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */ #define SUM_ENTRY_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM) /* a summary entry for a 4KB-sized block in a segment */ @@ -297,7 +297,7 @@ struct summary_footer { __u32 check_sum; /* summary checksum */ } __packed; -#define SUM_JOURNAL_SIZE (PAGE_CACHE_SIZE - SUM_FOOTER_SIZE -\ +#define SUM_JOURNAL_SIZE (F2FS_BLKSIZE - SUM_FOOTER_SIZE -\ SUM_ENTRY_SIZE) #define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ sizeof(struct nat_journal_entry)) -- cgit v0.10.2 From 0a8165d7c2cf1395059db20ab07665baf3758fcd Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 29 Nov 2012 13:28:09 +0900 Subject: f2fs: adjust kernel coding style As pointed out by Randy Dunlap, this patch removes all usage of "/**" for comment blocks. Instead, just use "/*". Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index dff2a2b..1ac9a4b 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/acl.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h index c97675e..80f4306 100644 --- a/fs/f2fs/acl.h +++ b/fs/f2fs/acl.h @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/acl.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 7c18f8e..6ef36c3 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/checkpoint.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -24,7 +24,7 @@ static struct kmem_cache *orphan_entry_slab; static struct kmem_cache *inode_entry_slab; -/** +/* * We guarantee no failure on the returned page. */ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) @@ -44,7 +44,7 @@ repeat: return page; } -/** +/* * We guarantee no failure on the returned page. */ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) @@ -543,7 +543,7 @@ retry: goto retry; } -/** +/* * Freeze all the FS-operations for checkpoint. */ void block_operations(struct f2fs_sb_info *sbi) @@ -727,7 +727,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount) F2FS_RESET_SB_DIRT(sbi); } -/** +/* * We guarantee that this checkpoint procedure should not fail. */ void write_checkpoint(struct f2fs_sb_info *sbi, bool blocked, bool is_umount) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 5635cc5..444c2a6 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/data.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -21,7 +21,7 @@ #include "node.h" #include "segment.h" -/** +/* * Lock ordering for the change of data block address: * ->data_page * ->node_page @@ -207,7 +207,7 @@ struct page *find_data_page(struct inode *inode, pgoff_t index) return page; } -/** +/* * If it tries to access a hole, return an error. * Because, the callers, functions in dir.c and GC, should be able to know * whether this page exists or not. @@ -247,7 +247,7 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index) return page; } -/** +/* * Caller ensures that this data page is never allocated. * A new zero-filled data page is allocated in the page cache. */ @@ -322,7 +322,7 @@ static void read_end_io(struct bio *bio, int err) bio_put(bio); } -/** +/* * Fill the locked page with data located in the block address. * Read operation is synchronous, and caller must unlock the page. */ @@ -367,7 +367,7 @@ int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page, return 0; } -/** +/* * This function should be used by the data read flow only where it * does not check the "create" flag that indicates block allocation. * The reason for this special functionality is to exploit VFS readahead diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index fb62960..0e0380a 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -1,4 +1,4 @@ -/** +/* * f2fs debugging statistics * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -78,7 +78,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) } } -/** +/* * This function calculates BDF of every segments */ static void update_sit_info(struct f2fs_sb_info *sbi) @@ -113,7 +113,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi) si->avg_vblocks = 0; } -/** +/* * This function calculates memory footprint. */ static void update_mem_info(struct f2fs_sb_info *sbi) diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 5ec7a06..089eb67 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/dir.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -453,7 +453,7 @@ fail: return err; } -/** +/* * It only removes the dentry from the dentry page,corresponding name * entry in name page does not need to be touched during deletion. */ diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 8d7fde1..8c3f1ef 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/f2fs.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index f5ae36d..c1a108f 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/file.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 46774ce..3271be4 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/gc.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -213,7 +213,7 @@ static unsigned int get_gc_cost(struct f2fs_sb_info *sbi, unsigned int segno, return get_cb_cost(sbi, segno); } -/** +/* * This function is called from two pathes. * One is garbage collection and the other is SSR segment selection. * When it is called during GC, it just gets a victim segment @@ -359,7 +359,7 @@ static int check_valid_map(struct f2fs_sb_info *sbi, return ret ? GC_OK : GC_NEXT; } -/** +/* * This function compares node address got in summary with that in NAT. * On validity, copy that node with cold status, otherwise (invalid node) * ignore that. @@ -425,7 +425,7 @@ next_step: return GC_DONE; } -/** +/* * Calculate start block index that this node page contains */ block_t start_bidx_of_node(unsigned int node_ofs) @@ -516,7 +516,7 @@ out: f2fs_put_page(page, 1); } -/** +/* * This function tries to get parent node of victim data block, and identifies * data block validity. If the block is valid, copy that with cold status and * modify parent node. diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h index cf42a55..b026d93 100644 --- a/fs/f2fs/gc.h +++ b/fs/f2fs/gc.h @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/gc.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -42,7 +42,7 @@ struct inode_entry { struct inode *inode; }; -/** +/* * inline functions */ static inline block_t free_user_blocks(struct f2fs_sb_info *sbi) diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c index beb155e..a60f042 100644 --- a/fs/f2fs/hash.c +++ b/fs/f2fs/hash.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/hash.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 94f13d2..aa4ef4f 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/inode.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -235,7 +235,7 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) return 0; } -/** +/* * Called at the last iput() if i_nlink is zero */ void f2fs_evict_inode(struct inode *inode) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index aec362f6..63efd77 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/namei.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -96,7 +96,7 @@ static int is_multimedia_file(const unsigned char *s, const char *sub) return ret; } -/** +/* * Set multimedia files as cold files for hot/cold data separation */ static inline void set_cold_file(struct f2fs_sb_info *sbi, struct inode *inode, diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 5d421fe..25d3036 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/node.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -81,7 +81,7 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid) return dst_page; } -/** +/* * Readahead NAT pages */ static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid) @@ -251,7 +251,7 @@ static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink) return nr_shrink; } -/** +/* * This function returns always success */ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) @@ -302,7 +302,7 @@ cache: cache_nat_entry(NM_I(sbi), nid, &ne); } -/** +/* * The maximum depth is four. * Offset[0] will have raw inode offset. */ @@ -649,7 +649,7 @@ fail: return err; } -/** +/* * All the block addresses of data and nodes should be nullified. */ int truncate_inode_blocks(struct inode *inode, pgoff_t from) @@ -860,7 +860,7 @@ static int read_node_page(struct page *page, int type) return f2fs_readpage(sbi, page, ni.blk_addr, type); } -/** +/* * Readahead a node page */ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) @@ -910,7 +910,7 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) return page; } -/** +/* * Return a locked page for the desired node page. * And, readahead MAX_RA_NODE number of node pages. */ @@ -1186,7 +1186,7 @@ static int f2fs_release_node_page(struct page *page, gfp_t wait) return 0; } -/** +/* * Structure of the f2fs node operations */ const struct address_space_operations f2fs_node_aops = { @@ -1386,7 +1386,7 @@ retry: return true; } -/** +/* * alloc_nid() should be called prior to this function. */ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid) @@ -1403,7 +1403,7 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid) spin_unlock(&nm_i->free_nid_list_lock); } -/** +/* * alloc_nid() should be called prior to this function. */ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid) @@ -1545,7 +1545,7 @@ retry: return true; } -/** +/* * This function is called during the checkpointing process. */ void flush_nat_entries(struct f2fs_sb_info *sbi) diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 0ab92d6..afdb130 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/node.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 222a7bb..b07e9b6 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/recovery.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index d973c56..a177eb3 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/segment.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -36,7 +36,7 @@ static int need_to_flush(struct f2fs_sb_info *sbi) return 0; } -/** +/* * This function balances dirty node and dentry pages. * In addition, it controls garbage collection. */ @@ -105,7 +105,7 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, } } -/** +/* * Should not occur error such as -ENOMEM. * Adding dirty entry into seglist is not critical operation. * If a given segment is one of current working segments, it won't be added. @@ -136,7 +136,7 @@ void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) return; } -/** +/* * Should call clear_prefree_segments after checkpoint is done. */ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) @@ -269,7 +269,7 @@ void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) mutex_unlock(&sit_i->sentry_lock); } -/** +/* * This function should be resided under the curseg_mutex lock */ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, @@ -282,7 +282,7 @@ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, return; } -/** +/* * Calculate the number of current summary pages for writing */ int npages_for_summary_flush(struct f2fs_sb_info *sbi) @@ -309,7 +309,7 @@ int npages_for_summary_flush(struct f2fs_sb_info *sbi) return 3; } -/** +/* * Caller should put this summary page */ struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno) @@ -371,7 +371,7 @@ next: return NULL_SEGNO; } -/** +/* * Find a new segment from the free segments bitmap to right order * This function should be returned with success, otherwise BUG */ @@ -483,7 +483,7 @@ static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) __set_sit_entry_type(sbi, type, curseg->segno, modified); } -/** +/* * Allocate a current working segment. * This function always allocates a free segment in LFS manner. */ @@ -520,7 +520,7 @@ static void __next_free_blkoff(struct f2fs_sb_info *sbi, seg->next_blkoff = ofs; } -/** +/* * If a segment is written by LFS manner, next block offset is just obtained * by increasing the current block offset. However, if a segment is written by * SSR manner, next block offset obtained by calling __next_free_blkoff @@ -534,7 +534,7 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, seg->next_blkoff++; } -/** +/* * This function always allocates a used segment (from dirty seglist) by SSR * manner, so it should recover the existing segment information of valid blocks */ @@ -1310,7 +1310,7 @@ static bool flush_sits_in_journal(struct f2fs_sb_info *sbi) return 0; } -/** +/* * CP calls this function, which flushes SIT entries including sit_journal, * and moves prefree segs to free segs. */ @@ -1624,7 +1624,7 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi) return init_victim_segmap(sbi); } -/** +/* * Update min, max modified time for cost-benefit GC algorithm */ static void init_min_max_mtime(struct f2fs_sb_info *sbi) diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index e380a8e..2c445f8 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/segment.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 878bf38..4360600 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/super.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index aca50fe..5324d1e 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/xattr.c * * Copyright (c) 2012 Samsung Electronics Co., Ltd. diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index 29b0a08..49c9558 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -1,4 +1,4 @@ -/** +/* * fs/f2fs/xattr.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. @@ -77,7 +77,7 @@ struct f2fs_xattr_entry { #define MAX_VALUE_LEN (MIN_OFFSET - sizeof(struct f2fs_xattr_header) - \ sizeof(struct f2fs_xattr_entry)) -/** +/* * On-disk structure of f2fs_xattr * We use only 1 block for xattr. * -- cgit v0.10.2 From 573ea5fcf0a65fea4811f82edd6dc6045c04edda Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 30 Nov 2012 17:32:08 +0900 Subject: f2fs: resolve build failures There exist two build failures reported by Randy Dunlap as follows. (on i386) a. (config-r8857) ERROR: "f2fs_xattr_advise_handler" [fs/f2fs/f2fs.ko] undefined! Key configs in (config-r8857) are as follows. CONFIG_F2FS_FS=m # CONFIG_F2FS_STAT_FS is not set CONFIG_F2FS_FS_XATTR=y # CONFIG_F2FS_FS_POSIX_ACL is not set The error was occurred due to the function location that we made a mistake. Recently we added a new functionality for users to indicate cold files explicitly through xattr operations (i.e., f2fs_xattr_advise_handler). This handler should have been added in xattr.c instead of acl.c in order to avoid an undefined operation like in this case where XATTR is set and ACL is not set. b. (config-r8855) fs/f2fs/file.c: In function 'f2fs_vm_page_mkwrite': fs/f2fs/file.c:97:2: error: implicit declaration of function 'block_page_mkwrite_return' Key config in (config-r8855) is CONFIG_BLOCK. Obviously, f2fs works on top of the block device so that we should consider carefully a sort of config dependencies. The reason why this error was occurred was that f2fs_vm_page_mkwrite() calls block_page_mkwrite_return() which is enalbed only if CONFIG_BLOCK is set. Reported-by: Randy Dunlap Signed-off-by: Jaegeuk Kim Acked-by: Randy Dunlap diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index 37a6b8e..fd27e7e 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig @@ -1,5 +1,6 @@ config F2FS_FS tristate "F2FS filesystem support (EXPERIMENTAL)" + depends on BLOCK help F2FS is based on Log-structured File System (LFS), which supports versatile "flash-friendly" features. The design has been focused on diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index 1ac9a4b..fed74d1 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -412,54 +412,3 @@ const struct xattr_handler f2fs_xattr_acl_access_handler = { .get = f2fs_xattr_get_acl, .set = f2fs_xattr_set_acl, }; - -static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, - size_t list_size, const char *name, size_t name_len, int type) -{ - const char *xname = F2FS_SYSTEM_ADVISE_PREFIX; - size_t size; - - if (type != F2FS_XATTR_INDEX_ADVISE) - return 0; - - size = strlen(xname) + 1; - if (list && size <= list_size) - memcpy(list, xname, size); - return size; -} - -static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - struct inode *inode = dentry->d_inode; - - if (strcmp(name, "") != 0) - return -EINVAL; - - *((char *)buffer) = F2FS_I(inode)->i_advise; - return sizeof(char); -} - -static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - struct inode *inode = dentry->d_inode; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!inode_owner_or_capable(inode)) - return -EPERM; - if (value == NULL) - return -EINVAL; - - F2FS_I(inode)->i_advise |= *(char *)value; - return 0; -} - -const struct xattr_handler f2fs_xattr_advise_handler = { - .prefix = F2FS_SYSTEM_ADVISE_PREFIX, - .flags = F2FS_XATTR_INDEX_ADVISE, - .list = f2fs_xattr_advise_list, - .get = f2fs_xattr_advise_get, - .set = f2fs_xattr_advise_set, -}; diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 5324d1e..7d52e8d 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -102,6 +102,49 @@ static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name, return f2fs_setxattr(dentry->d_inode, type, name, value, size); } +static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list, + size_t list_size, const char *name, size_t name_len, int type) +{ + const char *xname = F2FS_SYSTEM_ADVISE_PREFIX; + size_t size; + + if (type != F2FS_XATTR_INDEX_ADVISE) + return 0; + + size = strlen(xname) + 1; + if (list && size <= list_size) + memcpy(list, xname, size); + return size; +} + +static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name, + void *buffer, size_t size, int type) +{ + struct inode *inode = dentry->d_inode; + + if (strcmp(name, "") != 0) + return -EINVAL; + + *((char *)buffer) = F2FS_I(inode)->i_advise; + return sizeof(char); +} + +static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags, int type) +{ + struct inode *inode = dentry->d_inode; + + if (strcmp(name, "") != 0) + return -EINVAL; + if (!inode_owner_or_capable(inode)) + return -EPERM; + if (value == NULL) + return -EINVAL; + + F2FS_I(inode)->i_advise |= *(char *)value; + return 0; +} + const struct xattr_handler f2fs_xattr_user_handler = { .prefix = XATTR_USER_PREFIX, .flags = F2FS_XATTR_INDEX_USER, @@ -118,6 +161,14 @@ const struct xattr_handler f2fs_xattr_trusted_handler = { .set = f2fs_xattr_generic_set, }; +const struct xattr_handler f2fs_xattr_advise_handler = { + .prefix = F2FS_SYSTEM_ADVISE_PREFIX, + .flags = F2FS_XATTR_INDEX_ADVISE, + .list = f2fs_xattr_advise_list, + .get = f2fs_xattr_advise_get, + .set = f2fs_xattr_advise_set, +}; + static const struct xattr_handler *f2fs_xattr_handler_map[] = { [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler, #ifdef CONFIG_F2FS_FS_POSIX_ACL -- cgit v0.10.2 From be4124f8720ef83757a66caa46f6045f0292d1f4 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 1 Dec 2012 10:55:12 +0900 Subject: f2fs: fix the compiler warning for uninitialized use of variable When CONFIG_CC_OPTIMIZE_FOR_SIZE is enabled in the kernel, -Os optimisation flag is passed to gcc for compilation, and somehow while trying to optimize the code, compiler is might not able to see the initialisation of variable ne struct variable inside the get_node_info() function and results into following warning: fs/f2fs/node.c: In function 'get_node_info': fs/f2fs/node.c:175:3: warning: 'ne.block_addr' may be used uninitialized in this function [-Wuninitialized] fs/f2fs/node.c:265:24: note: 'ne.block_addr' was declared here fs/f2fs/node.c:176:3: warning: 'ne.ino' may be used uninitialized in this function [-Wuninitialized] fs/f2fs/node.c:265:24: note: 'ne.ino' was declared here fs/f2fs/node.c:177:3: warning: 'ne.version' may be used uninitialized in this function [-Wuninitialized] fs/f2fs/node.c:265:24: note: 'ne.version' was declared here Hence, lets initialise the ne struct variable to zero, which will remove this warning and also doing this does not seems to making any impact on the code behavior. Signed-off-by: Namjae Jeon Signed-off-by: Pankaj Kumar diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 25d3036..1987036 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -266,6 +266,7 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) struct nat_entry *e; int i; + memset(&ne, 0, sizeof(struct f2fs_nat_entry)); ni->nid = nid; /* Check nat cache */ -- cgit v0.10.2 From 72ce6094c0d3c1f0025eb118bb9406206f277479 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 1 Dec 2012 10:55:32 +0900 Subject: f2fs: show error in case of invalid mount arguments print the invalid argument/value from parse_options in case of mount failure. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 4360600..5830e53 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -311,6 +311,8 @@ static int parse_options(struct f2fs_sb_info *sbi, char *options) set_opt(sbi, DISABLE_EXT_IDENTIFY); break; default: + pr_err("Unrecognized mount option \"%s\" or missing value\n", + p); return -EINVAL; } } -- cgit v0.10.2 From 154a086529b50236782a2d4365a1d1c359adc7af Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 1 Dec 2012 10:55:45 +0900 Subject: f2fs: remove unneeded memset from init_once Since, __GFP_ZERO is used while f2fs inode allocation, so we do not need memset for f2fs_inode_info, as this is already zeroed out. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 5830e53..1386732 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -57,7 +57,6 @@ static void init_once(void *foo) { struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo; - memset(fi, 0, sizeof(*fi)); inode_init_once(&fi->vfs_inode); } -- cgit v0.10.2 From 1fa95b0b6798164a31c1048efdf62b71038eb3d5 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 1 Dec 2012 10:56:01 +0900 Subject: f2fs: check read only condition before beginning write out If the filesystem is mounted as read-only then return from that point itself instead of first doing a writeout/wait and then checking for read-only condition. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index c1a108f..89241c5 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -132,14 +132,15 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) .for_reclaim = 0, }; + if (inode->i_sb->s_flags & MS_RDONLY) + return 0; + ret = filemap_write_and_wait_range(inode->i_mapping, start, end); if (ret) return ret; mutex_lock(&inode->i_mutex); - if (inode->i_sb->s_flags & MS_RDONLY) - goto out; if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) goto out; -- cgit v0.10.2 From 1042d60f917d78ef1a6eaea297a1020484d4bf74 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 1 Dec 2012 10:56:13 +0900 Subject: f2fs: remove unneeded initialization No need to initialize "struct f2fs_gc_kthread *gc_th = NULL", as gc_th = NULL, will be taken care by the return values of kmalloc(). And fix codes in other places. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 3271be4..644aa38 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -89,7 +89,7 @@ static int gc_thread_func(void *data) int start_gc_thread(struct f2fs_sb_info *sbi) { - struct f2fs_gc_kthread *gc_th = NULL; + struct f2fs_gc_kthread *gc_th; gc_th = kmalloc(sizeof(struct f2fs_gc_kthread), GFP_KERNEL); if (!gc_th) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index a177eb3..969df1a 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1489,7 +1489,7 @@ static int build_free_segmap(struct f2fs_sb_info *sbi) static int build_curseg(struct f2fs_sb_info *sbi) { - struct curseg_info *array = NULL; + struct curseg_info *array; int i; array = kzalloc(sizeof(*array) * NR_CURSEG_TYPE, GFP_KERNEL); @@ -1656,7 +1656,7 @@ int build_segment_manager(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); - struct f2fs_sm_info *sm_info = NULL; + struct f2fs_sm_info *sm_info; int err; sm_info = kzalloc(sizeof(struct f2fs_sm_info), GFP_KERNEL); -- cgit v0.10.2 From 61412b64b965af72798000c3c921e88db31216b1 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 1 Dec 2012 10:56:25 +0900 Subject: f2fs: move error condition for mkdir at proper place In function f2fs_mkdir, err is being initialized without even checking if there was any error in new inode creation. So, instead check the inode error and make use of error/return condition. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 63efd77..2d720ca 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -287,9 +287,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) int err; inode = f2fs_new_inode(dir, S_IFDIR | mode); - err = PTR_ERR(inode); if (IS_ERR(inode)) - return err; + return PTR_ERR(inode); inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; -- cgit v0.10.2 From 705f814e34e08f6169439014a2916fd5afbdf232 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 2 Dec 2012 08:11:38 -0500 Subject: f2fs: remove unused variable The variables node_page and page_offset are initialized but never used otherwise, so remove those unused variables. Signed-off-by: Wei Yongjun diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 089eb67..2a20c50 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -509,13 +509,11 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, } if (bit_pos == NR_DENTRY_IN_BLOCK) { - loff_t page_offset; truncate_hole(dir, page->index, page->index + 1); clear_page_dirty_for_io(page); ClearPageUptodate(page); dec_page_count(sbi, F2FS_DIRTY_DENTS); inode_dec_dirty_dents(dir); - page_offset = page->index << PAGE_CACHE_SHIFT; f2fs_put_page(page, 1); } else { f2fs_put_page(page, 1); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 89241c5..f9e085d 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -30,7 +30,6 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page = vmf->page; struct inode *inode = vma->vm_file->f_path.dentry->d_inode; struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - struct page *node_page; block_t old_blk_addr; struct dnode_of_data dn; int err; @@ -50,7 +49,6 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, } old_blk_addr = dn.data_blkaddr; - node_page = dn.node_page; if (old_blk_addr == NULL_ADDR) { err = reserve_new_block(&dn); -- cgit v0.10.2 From d08ab08d140de247eb812ce2c3c4b323620e4609 Mon Sep 17 00:00:00 2001 From: Huajun Li Date: Wed, 5 Dec 2012 16:45:32 +0800 Subject: f2fs: fix a typo in f2fs documentation In f2fs_fs.h, one f2fs inode contains 923 data block pointers, while f2fs documentation says it is 929. Fix this inconsistence. Signed-off-by: Huajun Li diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index dee3960..8fbd8b4 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -253,7 +253,7 @@ Index Structure The key data structure to manage the data locations is a "node". Similar to traditional file structures, F2FS has three types of node: inode, direct node, -indirect node. F2FS assigns 4KB to an inode block which contains 929 data block +indirect node. F2FS assigns 4KB to an inode block which contains 923 data block indices, two direct node pointers, two indirect node pointers, and one double indirect node pointer as described below. One direct node block contains 1018 data blocks, and one indirect node block contains also 1018 node blocks. Thus, -- cgit v0.10.2 From c212991a6bc3ba120d41205a294c5b89f05f1535 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 8 Dec 2012 14:53:40 +0900 Subject: f2fs: rewrite f2fs_bio_alloc to make it simpler Since, GFP_NOFS(__GFP_WAIT) is used for allocation requests of bio in f2fs. So, there is no chance of returning NULL from the BIO allocation. Making the bio allocation routine for f2fs simpler. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 969df1a..8894b39 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -647,28 +647,18 @@ struct bio *f2fs_bio_alloc(struct block_device *bdev, sector_t first_sector, int nr_vecs, gfp_t gfp_flags) { struct bio *bio; -repeat: + /* allocate new bio */ bio = bio_alloc(gfp_flags, nr_vecs); - if (bio == NULL && (current->flags & PF_MEMALLOC)) { - while (!bio && (nr_vecs /= 2)) - bio = bio_alloc(gfp_flags, nr_vecs); - } - if (bio) { - bio->bi_bdev = bdev; - bio->bi_sector = first_sector; + bio->bi_bdev = bdev; + bio->bi_sector = first_sector; retry: - bio->bi_private = kmalloc(sizeof(struct bio_private), - GFP_NOFS | __GFP_HIGH); - if (!bio->bi_private) { - cond_resched(); - goto retry; - } - } - if (bio == NULL) { + bio->bi_private = kmalloc(sizeof(struct bio_private), + GFP_NOFS | __GFP_HIGH); + if (!bio->bi_private) { cond_resched(); - goto repeat; + goto retry; } return bio; } -- cgit v0.10.2 From a0d42539e1d6c818222822dedd92a1674040e20c Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 8 Dec 2012 14:54:18 +0900 Subject: f2fs: make use of GFP_F2FS_ZERO for setting gfp_mask Since, GFP_NOFS and __GFP_ZERO is being used to set gfp_mask. We can instead make use of already predefined macro GFP_F2FS_ZERO. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 2d720ca..89b7675 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -293,7 +293,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; - mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS | __GFP_ZERO); + mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO); set_inode_flag(F2FS_I(inode), FI_INC_LINK); err = f2fs_add_link(dentry, inode); -- cgit v0.10.2 From 508198be3c2f7f8929101bb0daeb8f0039c1dc7f Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 8 Dec 2012 14:54:35 +0900 Subject: f2fs: remove redundant call to f2fs_put_page in delete entry Since, we anyway need to put the page after deleting entry. So, there is no need to make same call under different conditions. Move out the f2fs_put_page from the two conditions and call at once. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 2a20c50..fc02d8b 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -514,10 +514,9 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, ClearPageUptodate(page); dec_page_count(sbi, F2FS_DIRTY_DENTS); inode_dec_dirty_dents(dir); - f2fs_put_page(page, 1); - } else { - f2fs_put_page(page, 1); } + f2fs_put_page(page, 1); + mutex_unlock_op(sbi, DENTRY_OPS); } -- cgit v0.10.2 From 457d08ee4fd91c8df17917ff2d32565e6adacbfc Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 8 Dec 2012 14:54:50 +0900 Subject: f2fs: introduce accessor to retrieve number of dentry slots Simplify code by providing the accessor macro to retrieve the number of dentry slots for a given filename length. Signed-off-by: Namjae Jeon Signed-off-by: Amit Sahrawat diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index fc02d8b..d900c08 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -99,8 +99,7 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, NR_DENTRY_IN_BLOCK, 0); while (bit_pos < NR_DENTRY_IN_BLOCK) { de = &dentry_blk->dentry[bit_pos]; - slots = (le16_to_cpu(de->name_len) + F2FS_NAME_LEN - 1) / - F2FS_NAME_LEN; + slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); if (early_match_name(name, namelen, namehash, de)) { if (!memcmp(dentry_blk->filename[bit_pos], @@ -130,7 +129,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, unsigned int level, const char *name, int namelen, f2fs_hash_t namehash, struct page **res_page) { - int s = (namelen + F2FS_NAME_LEN - 1) / F2FS_NAME_LEN; + int s = GET_DENTRY_SLOTS(namelen); unsigned int nbucket, nblock; unsigned int bidx, end_block; struct page *dentry_page; @@ -383,7 +382,7 @@ int f2fs_add_link(struct dentry *dentry, struct inode *inode) int namelen = dentry->d_name.len; struct page *dentry_page = NULL; struct f2fs_dentry_block *dentry_blk = NULL; - int slots = (namelen + F2FS_NAME_LEN - 1) / F2FS_NAME_LEN; + int slots = GET_DENTRY_SLOTS(namelen); int err = 0; int i; @@ -465,8 +464,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, struct address_space *mapping = page->mapping; struct inode *dir = mapping->host; struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); - int slots = (le16_to_cpu(dentry->name_len) + F2FS_NAME_LEN - 1) / - F2FS_NAME_LEN; + int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len)); void *kaddr = page_address(page); int i; @@ -641,8 +639,7 @@ static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir) file->f_pos += bit_pos - start_bit_pos; goto success; } - slots = (le16_to_cpu(de->name_len) + F2FS_NAME_LEN - 1) - / F2FS_NAME_LEN; + slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); bit_pos += slots; } bit_pos = 0; diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index c2fbbc3..f9a12f6 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -363,6 +363,9 @@ typedef __le32 f2fs_hash_t; /* One directory entry slot covers 8bytes-long file name */ #define F2FS_NAME_LEN 8 +#define F2FS_NAME_LEN_BITS 3 + +#define GET_DENTRY_SLOTS(x) ((x + F2FS_NAME_LEN - 1) >> F2FS_NAME_LEN_BITS) /* the number of dentry in a block */ #define NR_DENTRY_IN_BLOCK 214 -- cgit v0.10.2 From 3cd8a23948b29301f8f67b8d70c5c18fabbc05e1 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 10 Dec 2012 09:26:05 +0900 Subject: f2fs: cleanup the f2fs_bio_alloc routine Do cleanup more for better code readability. - Change the parameter set of f2fs_bio_alloc() This function should allocate a bio only since it is not something like f2fs_bio_init(). Instead, the caller should initialize the allocated bio. - Introduce SECTOR_FROM_BLOCK This macro translates a block address to its sector address. Signed-off-by: Jaegeuk Kim Reviewed-by: Namjae Jeon diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 444c2a6..655aeab 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -343,11 +343,12 @@ int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page, down_read(&sbi->bio_sem); /* Allocate a new bio */ - bio = f2fs_bio_alloc(bdev, blk_addr << (sbi->log_blocksize - 9), - 1, GFP_NOFS | __GFP_HIGH); + bio = f2fs_bio_alloc(bdev, 1); /* Initialize the bio */ + bio->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); bio->bi_end_io = read_end_io; + if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { kfree(bio->bi_private); bio_put(bio); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 8c3f1ef..2bce3a6 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -924,7 +924,7 @@ void clear_prefree_segments(struct f2fs_sb_info *); int npages_for_summary_flush(struct f2fs_sb_info *); void allocate_new_segments(struct f2fs_sb_info *); struct page *get_sum_page(struct f2fs_sb_info *, unsigned int); -struct bio *f2fs_bio_alloc(struct block_device *, sector_t, int, gfp_t); +struct bio *f2fs_bio_alloc(struct block_device *, int); void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync); int write_meta_page(struct f2fs_sb_info *, struct page *, struct writeback_control *); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 8894b39..1b26e4e 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -643,23 +643,21 @@ static void f2fs_end_io_write(struct bio *bio, int err) bio_put(bio); } -struct bio *f2fs_bio_alloc(struct block_device *bdev, sector_t first_sector, - int nr_vecs, gfp_t gfp_flags) +struct bio *f2fs_bio_alloc(struct block_device *bdev, int npages) { struct bio *bio; - - /* allocate new bio */ - bio = bio_alloc(gfp_flags, nr_vecs); - - bio->bi_bdev = bdev; - bio->bi_sector = first_sector; + struct bio_private *priv; retry: - bio->bi_private = kmalloc(sizeof(struct bio_private), - GFP_NOFS | __GFP_HIGH); - if (!bio->bi_private) { + priv = kmalloc(sizeof(struct bio_private), GFP_NOFS); + if (!priv) { cond_resched(); goto retry; } + + /* No failure on bio allocation */ + bio = bio_alloc(GFP_NOIO, npages); + bio->bi_bdev = bdev; + bio->bi_private = priv; return bio; } @@ -711,10 +709,15 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page, if (sbi->bio[type] && sbi->last_block_in_bio[type] != blk_addr - 1) do_submit_bio(sbi, type, false); alloc_new: - if (sbi->bio[type] == NULL) - sbi->bio[type] = f2fs_bio_alloc(bdev, - blk_addr << (sbi->log_blocksize - 9), - bio_get_nr_vecs(bdev), GFP_NOFS | __GFP_HIGH); + if (sbi->bio[type] == NULL) { + sbi->bio[type] = f2fs_bio_alloc(bdev, bio_get_nr_vecs(bdev)); + sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); + /* + * The end_io will be assigned at the sumbission phase. + * Until then, let bio_add_page() merge consecutive IOs as much + * as possible. + */ + } if (bio_add_page(sbi->bio[type], page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 2c445f8..0948405 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -82,6 +82,9 @@ (BITS_TO_LONGS(nr) * sizeof(unsigned long)) #define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments) +#define SECTOR_FROM_BLOCK(sbi, blk_addr) \ + (blk_addr << ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE)) + /* during checkpoint, bio_private is used to synchronize the last bio */ struct bio_private { struct f2fs_sb_info *sbi; -- cgit v0.10.2 From 6666e6aa9f36b2bfd6b30072c07b34f2a24becf1 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 10 Dec 2012 17:52:48 +0900 Subject: f2fs: fix tracking parent inode number Previously, f2fs didn't track the parent inode number correctly which is stored in each f2fs_inode. In the case of the following scenario, a bug can be occured. Let's suppose there are one directory, "/b", and two files, "/a" and "/b/a". - pino of "/a" is ROOT_INO. - pino of "/b/a" is DIR_B_INO. Then, # sync : The inode pages of "/a" and "/b/a" contain the parent inode numbers as ROOT_INO and DIR_B_INO respectively. # mv /a /b/a : The parent inode number of "/a" should be changed to DIR_B_INO, but f2fs didn't do that. Ref. f2fs_set_link(). In order to fix this clearly, I added i_pino in f2fs_inode_info, and whenever it needs to be changed like in f2fs_add_link() and f2fs_set_link(), it is updated temporarily in f2fs_inode_info. And later, f2fs_write_inode() stores the latest information to the inode pages. For power-off-recovery, f2fs_sync_file() triggers simply f2fs_write_inode(). Signed-off-by: Jaegeuk Kim diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index d900c08..b4e24f3 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -256,13 +256,16 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, set_page_dirty(page); dir->i_mtime = dir->i_ctime = CURRENT_TIME; mark_inode_dirty(dir); + + /* update parent inode number before releasing dentry page */ + F2FS_I(inode)->i_pino = dir->i_ino; + f2fs_put_page(page, 1); mutex_unlock_op(sbi, DENTRY_OPS); } void init_dent_inode(struct dentry *dentry, struct page *ipage) { - struct inode *dir = dentry->d_parent->d_inode; struct f2fs_node *rn; if (IS_ERR(ipage)) @@ -272,7 +275,6 @@ void init_dent_inode(struct dentry *dentry, struct page *ipage) /* copy dentry info. to this inode page */ rn = (struct f2fs_node *)page_address(ipage); - rn->i.i_pino = cpu_to_le32(dir->i_ino); rn->i.i_namelen = cpu_to_le32(dentry->d_name.len); memcpy(rn->i.i_name, dentry->d_name.name, dentry->d_name.len); set_page_dirty(ipage); @@ -444,7 +446,11 @@ add_dentry: for (i = 0; i < slots; i++) test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); set_page_dirty(dentry_page); + update_parent_metadata(dir, inode, current_depth); + + /* update parent inode number before releasing dentry page */ + F2FS_I(inode)->i_pino = dir->i_ino; fail: kunmap(dentry_page); f2fs_put_page(dentry_page, 1); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 2bce3a6..a18d63d 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -136,6 +136,7 @@ struct f2fs_inode_info { unsigned long i_flags; /* keep an inode flags for ioctl */ unsigned char i_advise; /* use to give file attribute hints */ unsigned int i_current_depth; /* use only in directory structure */ + unsigned int i_pino; /* parent inode number */ umode_t i_acl_mode; /* keep file acl mode temporarily */ /* Use below internally in f2fs*/ diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index aa4ef4f..df5fb38 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -107,6 +107,7 @@ static int do_read_inode(struct inode *inode) fi->flags = 0; fi->data_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver) - 1; fi->i_advise = ri->i_advise; + fi->i_pino = le32_to_cpu(ri->i_pino); get_extent_info(&fi->ext, ri->i_ext); f2fs_put_page(node_page, 1); return 0; @@ -200,6 +201,7 @@ void update_inode(struct inode *inode, struct page *node_page) ri->i_current_depth = cpu_to_le32(F2FS_I(inode)->i_current_depth); ri->i_xattr_nid = cpu_to_le32(F2FS_I(inode)->i_xattr_nid); ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags); + ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino); ri->i_generation = cpu_to_le32(inode->i_generation); set_page_dirty(node_page); } -- cgit v0.10.2 From 59a09917c95e5209135b4f1a87f1263d6ef40fdb Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 28 Nov 2012 16:23:00 +0000 Subject: slub: Use correct cpu_slab on dead cpu Pass a kmem_cache_cpu pointer into unfreeze partials so that a different kmem_cache_cpu structure than the local one can be specified. Acked-by: David Rientjes Signed-off-by: Christoph Lameter Signed-off-by: Pekka Enberg diff --git a/mm/slub.c b/mm/slub.c index b2ada3d..33576b0 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1869,12 +1869,14 @@ redo: /* * Unfreeze all the cpu partial slabs. * - * This function must be called with interrupt disabled. + * This function must be called with interrupts disabled + * for the cpu using c (or some other guarantee must be there + * to guarantee no concurrent accesses). */ -static void unfreeze_partials(struct kmem_cache *s) +static void unfreeze_partials(struct kmem_cache *s, + struct kmem_cache_cpu *c) { struct kmem_cache_node *n = NULL, *n2 = NULL; - struct kmem_cache_cpu *c = this_cpu_ptr(s->cpu_slab); struct page *page, *discard_page = NULL; while ((page = c->partial)) { @@ -1960,7 +1962,7 @@ static int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain) * set to the per node partial list. */ local_irq_save(flags); - unfreeze_partials(s); + unfreeze_partials(s, this_cpu_ptr(s->cpu_slab)); local_irq_restore(flags); oldpage = NULL; pobjects = 0; @@ -2003,7 +2005,7 @@ static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu) if (c->page) flush_slab(s, c); - unfreeze_partials(s); + unfreeze_partials(s, c); } } -- cgit v0.10.2 From 3c58346525d82625e68e24f071804c2dc057b6f4 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 28 Nov 2012 16:23:01 +0000 Subject: slab: Simplify bootstrap The nodelists field in kmem_cache is pointing to the first unused object in the array field when bootstrap is complete. A problem with the current approach is that the statically sized kmem_cache structure use on boot can only contain NR_CPUS entries. If the number of nodes plus the number of cpus is greater then we would overwrite memory following the kmem_cache_boot definition. Increase the size of the array field to ensure that also the node pointers fit into the array field. Once we do that we no longer need the kmem_cache_nodelists array and we can then also use that structure elsewhere. Acked-by: Glauber Costa Signed-off-by: Christoph Lameter Signed-off-by: Pekka Enberg diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h index cc290f0..45c0356 100644 --- a/include/linux/slab_def.h +++ b/include/linux/slab_def.h @@ -89,9 +89,13 @@ struct kmem_cache { * (see kmem_cache_init()) * We still use [NR_CPUS] and not [1] or [0] because cache_cache * is statically defined, so we reserve the max number of cpus. + * + * We also need to guarantee that the list is able to accomodate a + * pointer for each node since "nodelists" uses the remainder of + * available pointers. */ struct kmem_list3 **nodelists; - struct array_cache *array[NR_CPUS]; + struct array_cache *array[NR_CPUS + MAX_NUMNODES]; /* * Do not add fields after array[] */ diff --git a/mm/slab.c b/mm/slab.c index e26bff5..c7ea523 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -553,9 +553,7 @@ static struct arraycache_init initarray_generic = { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; /* internal cache of cache description objs */ -static struct kmem_list3 *kmem_cache_nodelists[MAX_NUMNODES]; static struct kmem_cache kmem_cache_boot = { - .nodelists = kmem_cache_nodelists, .batchcount = 1, .limit = BOOT_CPUCACHE_ENTRIES, .shared = 1, @@ -1560,6 +1558,15 @@ static void __init set_up_list3s(struct kmem_cache *cachep, int index) } /* + * The memory after the last cpu cache pointer is used for the + * the nodelists pointer. + */ +static void setup_nodelists_pointer(struct kmem_cache *cachep) +{ + cachep->nodelists = (struct kmem_list3 **)&cachep->array[nr_cpu_ids]; +} + +/* * Initialisation. Called after the page allocator have been initialised and * before smp_init(). */ @@ -1573,15 +1580,14 @@ void __init kmem_cache_init(void) int node; kmem_cache = &kmem_cache_boot; + setup_nodelists_pointer(kmem_cache); if (num_possible_nodes() == 1) use_alien_caches = 0; - for (i = 0; i < NUM_INIT_LISTS; i++) { + for (i = 0; i < NUM_INIT_LISTS; i++) kmem_list3_init(&initkmem_list3[i]); - if (i < MAX_NUMNODES) - kmem_cache->nodelists[i] = NULL; - } + set_up_list3s(kmem_cache, CACHE_CACHE); /* @@ -1619,7 +1625,6 @@ void __init kmem_cache_init(void) list_add(&kmem_cache->list, &slab_caches); kmem_cache->colour_off = cache_line_size(); kmem_cache->array[smp_processor_id()] = &initarray_cache.cache; - kmem_cache->nodelists[node] = &initkmem_list3[CACHE_CACHE + node]; /* * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids @@ -2422,7 +2427,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) else gfp = GFP_NOWAIT; - cachep->nodelists = (struct kmem_list3 **)&cachep->array[nr_cpu_ids]; + setup_nodelists_pointer(cachep); #if DEBUG /* -- cgit v0.10.2 From 45530c4474d258b822e2639c786606d8257aad8b Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 28 Nov 2012 16:23:07 +0000 Subject: mm, sl[au]b: create common functions for boot slab creation Use a special function to create kmalloc caches and use that function in SLAB and SLUB. Acked-by: Joonsoo Kim Reviewed-by: Glauber Costa Acked-by: David Rientjes Signed-off-by: Christoph Lameter Signed-off-by: Pekka Enberg diff --git a/mm/slab.c b/mm/slab.c index c7ea523..e351ace 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1659,23 +1659,13 @@ void __init kmem_cache_init(void) * bug. */ - sizes[INDEX_AC].cs_cachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); - sizes[INDEX_AC].cs_cachep->name = names[INDEX_AC].name; - sizes[INDEX_AC].cs_cachep->size = sizes[INDEX_AC].cs_size; - sizes[INDEX_AC].cs_cachep->object_size = sizes[INDEX_AC].cs_size; - sizes[INDEX_AC].cs_cachep->align = ARCH_KMALLOC_MINALIGN; - __kmem_cache_create(sizes[INDEX_AC].cs_cachep, ARCH_KMALLOC_FLAGS|SLAB_PANIC); - list_add(&sizes[INDEX_AC].cs_cachep->list, &slab_caches); - - if (INDEX_AC != INDEX_L3) { - sizes[INDEX_L3].cs_cachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); - sizes[INDEX_L3].cs_cachep->name = names[INDEX_L3].name; - sizes[INDEX_L3].cs_cachep->size = sizes[INDEX_L3].cs_size; - sizes[INDEX_L3].cs_cachep->object_size = sizes[INDEX_L3].cs_size; - sizes[INDEX_L3].cs_cachep->align = ARCH_KMALLOC_MINALIGN; - __kmem_cache_create(sizes[INDEX_L3].cs_cachep, ARCH_KMALLOC_FLAGS|SLAB_PANIC); - list_add(&sizes[INDEX_L3].cs_cachep->list, &slab_caches); - } + sizes[INDEX_AC].cs_cachep = create_kmalloc_cache(names[INDEX_AC].name, + sizes[INDEX_AC].cs_size, ARCH_KMALLOC_FLAGS); + + if (INDEX_AC != INDEX_L3) + sizes[INDEX_L3].cs_cachep = + create_kmalloc_cache(names[INDEX_L3].name, + sizes[INDEX_L3].cs_size, ARCH_KMALLOC_FLAGS); slab_early_init = 0; @@ -1687,24 +1677,14 @@ void __init kmem_cache_init(void) * Note for systems short on memory removing the alignment will * allow tighter packing of the smaller caches. */ - if (!sizes->cs_cachep) { - sizes->cs_cachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); - sizes->cs_cachep->name = names->name; - sizes->cs_cachep->size = sizes->cs_size; - sizes->cs_cachep->object_size = sizes->cs_size; - sizes->cs_cachep->align = ARCH_KMALLOC_MINALIGN; - __kmem_cache_create(sizes->cs_cachep, ARCH_KMALLOC_FLAGS|SLAB_PANIC); - list_add(&sizes->cs_cachep->list, &slab_caches); - } + if (!sizes->cs_cachep) + sizes->cs_cachep = create_kmalloc_cache(names->name, + sizes->cs_size, ARCH_KMALLOC_FLAGS); + #ifdef CONFIG_ZONE_DMA - sizes->cs_dmacachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); - sizes->cs_dmacachep->name = names->name_dma; - sizes->cs_dmacachep->size = sizes->cs_size; - sizes->cs_dmacachep->object_size = sizes->cs_size; - sizes->cs_dmacachep->align = ARCH_KMALLOC_MINALIGN; - __kmem_cache_create(sizes->cs_dmacachep, - ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA| SLAB_PANIC); - list_add(&sizes->cs_dmacachep->list, &slab_caches); + sizes->cs_dmacachep = create_kmalloc_cache( + names->name_dma, sizes->cs_size, + SLAB_CACHE_DMA|ARCH_KMALLOC_FLAGS); #endif sizes++; names++; diff --git a/mm/slab.h b/mm/slab.h index 66a62d3..492eafa 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -35,6 +35,11 @@ extern struct kmem_cache *kmem_cache; /* Functions provided by the slab allocators */ extern int __kmem_cache_create(struct kmem_cache *, unsigned long flags); +extern struct kmem_cache *create_kmalloc_cache(const char *name, size_t size, + unsigned long flags); +extern void create_boot_cache(struct kmem_cache *, const char *name, + size_t size, unsigned long flags); + #ifdef CONFIG_SLUB struct kmem_cache *__kmem_cache_alias(const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *)); diff --git a/mm/slab_common.c b/mm/slab_common.c index b705be7..497b45c 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -202,6 +202,42 @@ int slab_is_available(void) return slab_state >= UP; } +#ifndef CONFIG_SLOB +/* Create a cache during boot when no slab services are available yet */ +void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t size, + unsigned long flags) +{ + int err; + + s->name = name; + s->size = s->object_size = size; + s->align = ARCH_KMALLOC_MINALIGN; + err = __kmem_cache_create(s, flags); + + if (err) + panic("Creation of kmalloc slab %s size=%zd failed. Reason %d\n", + name, size, err); + + s->refcount = -1; /* Exempt from merging for now */ +} + +struct kmem_cache *__init create_kmalloc_cache(const char *name, size_t size, + unsigned long flags) +{ + struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); + + if (!s) + panic("Out of memory when creating slab %s\n", name); + + create_boot_cache(s, name, size, flags); + list_add(&s->list, &slab_caches); + s->refcount = 1; + return s; +} + +#endif /* !CONFIG_SLOB */ + + #ifdef CONFIG_SLABINFO static void print_slabinfo_header(struct seq_file *m) { diff --git a/mm/slub.c b/mm/slub.c index 33576b0..1be172c 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -3245,32 +3245,6 @@ static int __init setup_slub_nomerge(char *str) __setup("slub_nomerge", setup_slub_nomerge); -static struct kmem_cache *__init create_kmalloc_cache(const char *name, - int size, unsigned int flags) -{ - struct kmem_cache *s; - - s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); - - s->name = name; - s->size = s->object_size = size; - s->align = ARCH_KMALLOC_MINALIGN; - - /* - * This function is called with IRQs disabled during early-boot on - * single CPU so there's no need to take slab_mutex here. - */ - if (kmem_cache_open(s, flags)) - goto panic; - - list_add(&s->list, &slab_caches); - return s; - -panic: - panic("Creation of kmalloc slab %s size=%d failed.\n", name, size); - return NULL; -} - /* * Conversion table for small slabs sizes / 8 to the index in the * kmalloc array. This is necessary for slabs < 192 since we have non power @@ -3948,6 +3922,10 @@ int __kmem_cache_create(struct kmem_cache *s, unsigned long flags) if (err) return err; + /* Mutex is not taken during early boot */ + if (slab_state <= UP) + return 0; + mutex_unlock(&slab_mutex); err = sysfs_slab_add(s); mutex_lock(&slab_mutex); @@ -5249,13 +5227,8 @@ static int sysfs_slab_add(struct kmem_cache *s) { int err; const char *name; - int unmergeable; - - if (slab_state < FULL) - /* Defer until later */ - return 0; + int unmergeable = slab_unmergeable(s); - unmergeable = slab_unmergeable(s); if (unmergeable) { /* * Slabcache can never be merged so we can use the name proper. -- cgit v0.10.2 From dffb4d605c23110e3ad54b8c9f244a8235c013c2 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 28 Nov 2012 16:23:07 +0000 Subject: slub: Use statically allocated kmem_cache boot structure for bootstrap Simplify bootstrap by statically allocated two kmem_cache structures. These are freed after bootup is complete. Allows us to no longer worry about calculations of sizes of kmem_cache structures during bootstrap. Reviewed-by: Glauber Costa Signed-off-by: Christoph Lameter Signed-off-by: Pekka Enberg diff --git a/mm/slub.c b/mm/slub.c index 1be172c..c82453a 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -176,8 +176,6 @@ static inline int kmem_cache_debug(struct kmem_cache *s) #define __OBJECT_POISON 0x80000000UL /* Poison object */ #define __CMPXCHG_DOUBLE 0x40000000UL /* Use cmpxchg_double */ -static int kmem_size = sizeof(struct kmem_cache); - #ifdef CONFIG_SMP static struct notifier_block slab_notifier; #endif @@ -3634,15 +3632,16 @@ static int slab_memory_callback(struct notifier_block *self, /* * Used for early kmem_cache structures that were allocated using - * the page allocator + * the page allocator. Allocate them properly then fix up the pointers + * that may be pointing to the wrong kmem_cache structure. */ -static void __init kmem_cache_bootstrap_fixup(struct kmem_cache *s) +static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache) { int node; + struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); - list_add(&s->list, &slab_caches); - s->refcount = -1; + memcpy(s, static_cache, kmem_cache->object_size); for_each_node_state(node, N_NORMAL_MEMORY) { struct kmem_cache_node *n = get_node(s, node); @@ -3658,70 +3657,44 @@ static void __init kmem_cache_bootstrap_fixup(struct kmem_cache *s) #endif } } + list_add(&s->list, &slab_caches); + return s; } void __init kmem_cache_init(void) { + static __initdata struct kmem_cache boot_kmem_cache, + boot_kmem_cache_node; int i; - int caches = 0; - struct kmem_cache *temp_kmem_cache; - int order; - struct kmem_cache *temp_kmem_cache_node; - unsigned long kmalloc_size; + int caches = 2; if (debug_guardpage_minorder()) slub_max_order = 0; - kmem_size = offsetof(struct kmem_cache, node) + - nr_node_ids * sizeof(struct kmem_cache_node *); - - /* Allocate two kmem_caches from the page allocator */ - kmalloc_size = ALIGN(kmem_size, cache_line_size()); - order = get_order(2 * kmalloc_size); - kmem_cache = (void *)__get_free_pages(GFP_NOWAIT | __GFP_ZERO, order); + kmem_cache_node = &boot_kmem_cache_node; + kmem_cache = &boot_kmem_cache; - /* - * Must first have the slab cache available for the allocations of the - * struct kmem_cache_node's. There is special bootstrap code in - * kmem_cache_open for slab_state == DOWN. - */ - kmem_cache_node = (void *)kmem_cache + kmalloc_size; - - kmem_cache_node->name = "kmem_cache_node"; - kmem_cache_node->size = kmem_cache_node->object_size = - sizeof(struct kmem_cache_node); - kmem_cache_open(kmem_cache_node, SLAB_HWCACHE_ALIGN | SLAB_PANIC); + create_boot_cache(kmem_cache_node, "kmem_cache_node", + sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN); hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI); /* Able to allocate the per node structures */ slab_state = PARTIAL; - temp_kmem_cache = kmem_cache; - kmem_cache->name = "kmem_cache"; - kmem_cache->size = kmem_cache->object_size = kmem_size; - kmem_cache_open(kmem_cache, SLAB_HWCACHE_ALIGN | SLAB_PANIC); + create_boot_cache(kmem_cache, "kmem_cache", + offsetof(struct kmem_cache, node) + + nr_node_ids * sizeof(struct kmem_cache_node *), + SLAB_HWCACHE_ALIGN); - kmem_cache = kmem_cache_alloc(kmem_cache, GFP_NOWAIT); - memcpy(kmem_cache, temp_kmem_cache, kmem_size); + kmem_cache = bootstrap(&boot_kmem_cache); /* * Allocate kmem_cache_node properly from the kmem_cache slab. * kmem_cache_node is separately allocated so no need to * update any list pointers. */ - temp_kmem_cache_node = kmem_cache_node; - - kmem_cache_node = kmem_cache_alloc(kmem_cache, GFP_NOWAIT); - memcpy(kmem_cache_node, temp_kmem_cache_node, kmem_size); - - kmem_cache_bootstrap_fixup(kmem_cache_node); - - caches++; - kmem_cache_bootstrap_fixup(kmem_cache); - caches++; - /* Free temporary boot structure */ - free_pages((unsigned long)temp_kmem_cache, order); + kmem_cache_node = bootstrap(&boot_kmem_cache_node); /* Now we can use the kmem_cache to allocate kmalloc slabs */ -- cgit v0.10.2 From 2f9baa9fcf8d0a204ca129a671d6086cc100faab Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 28 Nov 2012 16:23:09 +0000 Subject: slab: Use the new create_boot_cache function to simplify bootstrap Simplify setup and reduce code in kmem_cache_init(). This allows us to get rid of initarray_cache as well as the manual setup code for the kmem_cache and kmem_cache_node arrays during bootstrap. We introduce a new bootstrap state "PARTIAL" for slab that signals the creation of a kmem_cache boot cache. Signed-off-by: Christoph Lameter Signed-off-by: Pekka Enberg diff --git a/mm/slab.c b/mm/slab.c index e351ace..e1790e5 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -547,8 +547,6 @@ static struct cache_names __initdata cache_names[] = { #undef CACHE }; -static struct arraycache_init initarray_cache __initdata = - { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; static struct arraycache_init initarray_generic = { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; @@ -1572,12 +1570,9 @@ static void setup_nodelists_pointer(struct kmem_cache *cachep) */ void __init kmem_cache_init(void) { - size_t left_over; struct cache_sizes *sizes; struct cache_names *names; int i; - int order; - int node; kmem_cache = &kmem_cache_boot; setup_nodelists_pointer(kmem_cache); @@ -1618,36 +1613,16 @@ void __init kmem_cache_init(void) * 6) Resize the head arrays of the kmalloc caches to their final sizes. */ - node = numa_mem_id(); - /* 1) create the kmem_cache */ - INIT_LIST_HEAD(&slab_caches); - list_add(&kmem_cache->list, &slab_caches); - kmem_cache->colour_off = cache_line_size(); - kmem_cache->array[smp_processor_id()] = &initarray_cache.cache; /* * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids */ - kmem_cache->size = offsetof(struct kmem_cache, array[nr_cpu_ids]) + - nr_node_ids * sizeof(struct kmem_list3 *); - kmem_cache->object_size = kmem_cache->size; - kmem_cache->size = ALIGN(kmem_cache->object_size, - cache_line_size()); - kmem_cache->reciprocal_buffer_size = - reciprocal_value(kmem_cache->size); - - for (order = 0; order < MAX_ORDER; order++) { - cache_estimate(order, kmem_cache->size, - cache_line_size(), 0, &left_over, &kmem_cache->num); - if (kmem_cache->num) - break; - } - BUG_ON(!kmem_cache->num); - kmem_cache->gfporder = order; - kmem_cache->colour = left_over / kmem_cache->colour_off; - kmem_cache->slab_size = ALIGN(kmem_cache->num * sizeof(kmem_bufctl_t) + - sizeof(struct slab), cache_line_size()); + create_boot_cache(kmem_cache, "kmem_cache", + offsetof(struct kmem_cache, array[nr_cpu_ids]) + + nr_node_ids * sizeof(struct kmem_list3 *), + SLAB_HWCACHE_ALIGN); + list_add(&kmem_cache->list, &slab_caches); /* 2+3) create the kmalloc caches */ sizes = malloc_sizes; @@ -1695,7 +1670,6 @@ void __init kmem_cache_init(void) ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT); - BUG_ON(cpu_cache_get(kmem_cache) != &initarray_cache.cache); memcpy(ptr, cpu_cache_get(kmem_cache), sizeof(struct arraycache_init)); /* @@ -2250,7 +2224,15 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp) if (slab_state == DOWN) { /* - * Note: the first kmem_cache_create must create the cache + * Note: Creation of first cache (kmem_cache). + * The setup_list3s is taken care + * of by the caller of __kmem_cache_create + */ + cachep->array[smp_processor_id()] = &initarray_generic.cache; + slab_state = PARTIAL; + } else if (slab_state == PARTIAL) { + /* + * Note: the second kmem_cache_create must create the cache * that's used by kmalloc(24), otherwise the creation of * further caches will BUG(). */ @@ -2258,7 +2240,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp) /* * If the cache that's used by kmalloc(sizeof(kmem_list3)) is - * the first cache, then we need to set up all its list3s, + * the second cache, then we need to set up all its list3s, * otherwise the creation of further caches will BUG(). */ set_up_list3s(cachep, SIZE_AC); @@ -2267,6 +2249,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp) else slab_state = PARTIAL_ARRAYCACHE; } else { + /* Remaining boot caches */ cachep->array[smp_processor_id()] = kmalloc(sizeof(struct arraycache_init), gfp); -- cgit v0.10.2 From 4590685546a374fb0f60682ce0e3a6fd48911d46 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 28 Nov 2012 16:23:16 +0000 Subject: mm/sl[aou]b: Common alignment code Extract the code to do object alignment from the allocators. Do the alignment calculations in slab_common so that the __kmem_cache_create functions of the allocators do not have to deal with alignment. Signed-off-by: Christoph Lameter Signed-off-by: Pekka Enberg diff --git a/mm/slab.c b/mm/slab.c index e1790e5..2c3a2e0 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2337,22 +2337,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) size &= ~(BYTES_PER_WORD - 1); } - /* calculate the final buffer alignment: */ - - /* 1) arch recommendation: can be overridden for debug */ - if (flags & SLAB_HWCACHE_ALIGN) { - /* - * Default alignment: as specified by the arch code. Except if - * an object is really small, then squeeze multiple objects into - * one cacheline. - */ - ralign = cache_line_size(); - while (size <= ralign / 2) - ralign /= 2; - } else { - ralign = BYTES_PER_WORD; - } - /* * Redzoning and user store require word alignment or possibly larger. * Note this will be overridden by architecture or caller mandated @@ -2369,10 +2353,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) size &= ~(REDZONE_ALIGN - 1); } - /* 2) arch mandated alignment */ - if (ralign < ARCH_SLAB_MINALIGN) { - ralign = ARCH_SLAB_MINALIGN; - } /* 3) caller mandated alignment */ if (ralign < cachep->align) { ralign = cachep->align; diff --git a/mm/slab.h b/mm/slab.h index 492eafa..1cb9c9e 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -32,6 +32,9 @@ extern struct list_head slab_caches; /* The slab cache that manages slab cache information */ extern struct kmem_cache *kmem_cache; +unsigned long calculate_alignment(unsigned long flags, + unsigned long align, unsigned long size); + /* Functions provided by the slab allocators */ extern int __kmem_cache_create(struct kmem_cache *, unsigned long flags); diff --git a/mm/slab_common.c b/mm/slab_common.c index 497b45c..a8e76d7 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -73,6 +73,34 @@ static inline int kmem_cache_sanity_check(const char *name, size_t size) #endif /* + * Figure out what the alignment of the objects will be given a set of + * flags, a user specified alignment and the size of the objects. + */ +unsigned long calculate_alignment(unsigned long flags, + unsigned long align, unsigned long size) +{ + /* + * If the user wants hardware cache aligned objects then follow that + * suggestion if the object is sufficiently large. + * + * The hardware cache alignment cannot override the specified + * alignment though. If that is greater then use it. + */ + if (flags & SLAB_HWCACHE_ALIGN) { + unsigned long ralign = cache_line_size(); + while (size <= ralign / 2) + ralign /= 2; + align = max(align, ralign); + } + + if (align < ARCH_SLAB_MINALIGN) + align = ARCH_SLAB_MINALIGN; + + return ALIGN(align, sizeof(void *)); +} + + +/* * kmem_cache_create - Create a cache. * @name: A string which is used in /proc/slabinfo to identify this cache. * @size: The size of objects to be created in this cache. @@ -124,7 +152,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL); if (s) { s->object_size = s->size = size; - s->align = align; + s->align = calculate_alignment(flags, align, size); s->ctor = ctor; s->name = kstrdup(name, GFP_KERNEL); if (!s->name) { @@ -211,7 +239,7 @@ void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t siz s->name = name; s->size = s->object_size = size; - s->align = ARCH_KMALLOC_MINALIGN; + s->align = calculate_alignment(flags, ARCH_KMALLOC_MINALIGN, size); err = __kmem_cache_create(s, flags); if (err) diff --git a/mm/slob.c b/mm/slob.c index 87e16c4..795bab7 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -123,7 +123,6 @@ static inline void clear_slob_page_free(struct page *sp) #define SLOB_UNIT sizeof(slob_t) #define SLOB_UNITS(size) (((size) + SLOB_UNIT - 1)/SLOB_UNIT) -#define SLOB_ALIGN L1_CACHE_BYTES /* * struct slob_rcu is inserted at the tail of allocated slob blocks, which @@ -527,20 +526,11 @@ EXPORT_SYMBOL(ksize); int __kmem_cache_create(struct kmem_cache *c, unsigned long flags) { - size_t align = c->size; - if (flags & SLAB_DESTROY_BY_RCU) { /* leave room for rcu footer at the end of object */ c->size += sizeof(struct slob_rcu); } c->flags = flags; - /* ignore alignment unless it's forced */ - c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0; - if (c->align < ARCH_SLAB_MINALIGN) - c->align = ARCH_SLAB_MINALIGN; - if (c->align < align) - c->align = align; - return 0; } diff --git a/mm/slub.c b/mm/slub.c index c82453a..9640edd 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2760,32 +2760,6 @@ static inline int calculate_order(int size, int reserved) return -ENOSYS; } -/* - * Figure out what the alignment of the objects will be. - */ -static unsigned long calculate_alignment(unsigned long flags, - unsigned long align, unsigned long size) -{ - /* - * If the user wants hardware cache aligned objects then follow that - * suggestion if the object is sufficiently large. - * - * The hardware cache alignment cannot override the specified - * alignment though. If that is greater then use it. - */ - if (flags & SLAB_HWCACHE_ALIGN) { - unsigned long ralign = cache_line_size(); - while (size <= ralign / 2) - ralign /= 2; - align = max(align, ralign); - } - - if (align < ARCH_SLAB_MINALIGN) - align = ARCH_SLAB_MINALIGN; - - return ALIGN(align, sizeof(void *)); -} - static void init_kmem_cache_node(struct kmem_cache_node *n) { @@ -2919,7 +2893,6 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) { unsigned long flags = s->flags; unsigned long size = s->object_size; - unsigned long align = s->align; int order; /* @@ -2991,19 +2964,11 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) #endif /* - * Determine the alignment based on various parameters that the - * user specified and the dynamic determination of cache line size - * on bootup. - */ - align = calculate_alignment(flags, align, s->object_size); - s->align = align; - - /* * SLUB stores one object immediately after another beginning from * offset 0. In order to align the objects we have to simply size * each object to conform to the alignment. */ - size = ALIGN(size, align); + size = ALIGN(size, s->align); s->size = size; if (forced_order >= 0) order = forced_order; @@ -3032,7 +2997,6 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) s->max = s->oo; return !!oo_objects(s->oo); - } static int kmem_cache_open(struct kmem_cache *s, unsigned long flags) -- cgit v0.10.2 From 596585090a6d7f0a62b4e5864ad8cedf1af964d1 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Tue, 11 Dec 2012 00:11:45 +0900 Subject: scripts/tags.sh: Support subarch for ARM Current tags.sh doesn't handle subarch for ARM. There are too many subarch on ARM, it is hard that we locate some functions which are defined in every subarch with tags util family. Therefore support subarch for removing this unconvenience. We can use ARM subarch functionality like below. "make cscope O=. SRCARCH=arm SUBARCH=xxx" Signed-off-by: Joonsoo Kim Signed-off-by: Michal Marek diff --git a/scripts/tags.sh b/scripts/tags.sh index 79fdafb..8fb18d1 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -48,13 +48,14 @@ find_arch_sources() for i in $archincludedir; do prune="$prune -wholename $i -prune -o" done - find ${tree}arch/$1 $ignore $prune -name "$2" -print; + find ${tree}arch/$1 $ignore $subarchprune $prune -name "$2" -print; } # find sources in arch/$1/include find_arch_include_sources() { - include=$(find ${tree}arch/$1/ -name include -type d); + include=$(find ${tree}arch/$1/ $subarchprune \ + -name include -type d -print); if [ -n "$include" ]; then archincludedir="$archincludedir $include" find $include $ignore -name "$2" -print; @@ -234,6 +235,21 @@ if [ "${ARCH}" = "um" ]; then else archinclude=${SUBARCH} fi +elif [ "${SRCARCH}" = "arm" -a "${SUBARCH}" != "" ]; then + subarchdir=$(find ${tree}arch/$SRCARCH/ -name "mach-*" -type d -o \ + -name "plat-*" -type d); + for i in $subarchdir; do + case "$i" in + *"mach-"${SUBARCH}) + ;; + *"plat-"${SUBARCH}) + ;; + *) + subarchprune="$subarchprune \ + -wholename $i -prune -o" + ;; + esac + done fi remove_structs= -- cgit v0.10.2 From 923e02ecf3f8db19d52176723fefa0ffe6e9a3cd Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Tue, 11 Dec 2012 00:11:46 +0900 Subject: scripts/tags.sh: Support compiled source We usually have interst in compiled files only, because they are strongly related to individual's work. Current tags.sh can't select compiled files, so support it. We can use this functionality like below. "make cscope O=. SRCARCH=xxxx COMPILED_SOURCE=compiled" It must be executed after building the kernel. Signed-off-by: Joonsoo Kim Signed-off-by: Michal Marek diff --git a/scripts/tags.sh b/scripts/tags.sh index 8fb18d1..08f06c0 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -96,6 +96,32 @@ all_sources() find_other_sources '*.[chS]' } +all_compiled_sources() +{ + for i in $(all_sources); do + case "$i" in + *.[cS]) + j=${i/\.[cS]/\.o} + if [ -e $j ]; then + echo $i + fi + ;; + *) + echo $i + ;; + esac + done +} + +all_target_sources() +{ + if [ -n "$COMPILED_SOURCE" ]; then + all_compiled_sources + else + all_sources + fi +} + all_kconfigs() { for arch in $ALLSOURCE_ARCHS; do @@ -111,18 +137,18 @@ all_defconfigs() docscope() { - (echo \-k; echo \-q; all_sources) > cscope.files + (echo \-k; echo \-q; all_target_sources) > cscope.files cscope -b -f cscope.out } dogtags() { - all_sources | gtags -i -f - + all_target_sources | gtags -i -f - } exuberant() { - all_sources | xargs $1 -a \ + all_target_sources | xargs $1 -a \ -I __initdata,__exitdata,__acquires,__releases \ -I __read_mostly,____cacheline_aligned \ -I ____cacheline_aligned_in_smp \ @@ -174,7 +200,7 @@ exuberant() emacs() { - all_sources | xargs $1 -a \ + all_target_sources | xargs $1 -a \ --regex='/^(ENTRY|_GLOBAL)(\([^)]*\)).*/\2/' \ --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/' \ --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1/' \ @@ -221,11 +247,10 @@ xtags() elif $1 --version 2>&1 | grep -iq emacs; then emacs $1 else - all_sources | xargs $1 -a + all_target_sources | xargs $1 -a fi } - # Support um (which uses SUBARCH) if [ "${ARCH}" = "um" ]; then if [ "$SUBARCH" = "i386" ]; then -- cgit v0.10.2 From 7d3e91a89b7adbc2831334def9e494dd9892f9af Mon Sep 17 00:00:00 2001 From: Sven Wegener Date: Sat, 8 Dec 2012 15:30:18 +0100 Subject: NFSv4: Check for buffer length in __nfs4_get_acl_uncached Commit 1f1ea6c "NFSv4: Fix buffer overflow checking in __nfs4_get_acl_uncached" accidently dropped the checking for too small result buffer length. If someone uses getxattr on "system.nfs4_acl" on an NFSv4 mount supporting ACLs, the ACL has not been cached and the buffer suplied is too short, we still copy the complete ACL, resulting in kernel and user space memory corruption. Signed-off-by: Sven Wegener Cc: stable@kernel.org Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5eec442..05e5f6f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3937,8 +3937,13 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu goto out_free; } nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len); - if (buf) + if (buf) { + if (res.acl_len > buflen) { + ret = -ERANGE; + goto out_free; + } _copy_from_pages(buf, pages, res.acl_data_offset, res.acl_len); + } out_ok: ret = res.acl_len; out_free: -- cgit v0.10.2 From 81d9bce5309288086b58b4d97a644e495fef75f2 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 10 Dec 2012 09:25:48 -0500 Subject: nfs: don't extend writes to cover entire page if pagecache is invalid Jian reported that the following sequence would leave "testfile" with corrupt data: # mount localhost:/export /mnt/nfs/ -o vers=3 # echo abc > /mnt/nfs/testfile; echo def >> /export/testfile; echo ghi >> /mnt/nfs/testfile # cat -v /export/testfile abc ^@^@^@^@ghi While there's no locking involved here, the operations are serialized, so CTO should prevent corruption. The first write to the file is fine and writes 4 bytes. The file is then extended on the server. When it's reopened a GETATTR is issued and the size change is noticed. This causes NFS_INO_INVALID_DATA to be set on the file. Because the file is opened for write only, nfs_want_read_modify_write() returns 0 to nfs_write_begin(). nfs_updatepage then calls nfs_write_pageuptodate() to see if it should extend the nfs_page to cover the whole page. NFS_INO_INVALID_DATA is still set on the file at that point, but that flag is ignored and nfs_pageuptodate erroneously extends the write to cover the whole page, with the write done on the server side filled in with zeroes. This patch just has that function check for NFS_INO_INVALID_DATA in addition to NFS_INO_REVAL_PAGECACHE. This fixes the bug, but looking over the code, I wonder if we might have a similar bug in nfs_revalidate_size(). The difference between those two flags is very subtle, so it seems like we ought to be checking for NFS_INO_INVALID_DATA in most of the places that we look for NFS_INO_REVAL_PAGECACHE. I believe this is regression introduced by commit 8d197a568. The code did check for NFS_INO_INVALID_DATA prior to that patch. Original bug report is here: https://bugzilla.redhat.com/show_bug.cgi?id=885743 Cc: # 3.5+ Reported-by: Jian Li Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust diff --git a/fs/nfs/write.c b/fs/nfs/write.c index f710e39..eecd8b8 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -884,7 +884,7 @@ static bool nfs_write_pageuptodate(struct page *page, struct inode *inode) { if (nfs_have_delegated_attributes(inode)) goto out; - if (NFS_I(inode)->cache_validity & NFS_INO_REVAL_PAGECACHE) + if (NFS_I(inode)->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE)) return false; out: return PageUptodate(page) != 0; -- cgit v0.10.2 From 85563073741bd7935a6900d567ddaf907192270d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 11 Dec 2012 10:31:12 -0500 Subject: NFSv4.1: Handle NFS4ERR_BADSLOT errors correctly Most (all) NFS4ERR_BADSLOT errors are due to the client failing to respect the server's sr_highest_slotid limit. This mainly happens due to reordered RPC requests. The way to handle it is simply to drop the slot that we're using, and retry using the new highest_slotid limits. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 92bd799..a4692e9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -422,6 +422,7 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * struct nfs4_slot *slot; unsigned long timestamp; struct nfs_client *clp; + int ret = 1; /* * sr_status remains 1 if an RPC level error occurred. The server @@ -462,6 +463,16 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * slot->slot_nr, slot->seq_nr); goto out_retry; + case -NFS4ERR_BADSLOT: + /* + * The slot id we used was probably retired. Try again + * using a different slot id. + */ + if (rpc_restart_call_prepare(task)) { + task->tk_status = 0; + ret = 0; + } + break; default: /* Just update the slot sequence no. */ ++slot->seq_nr; @@ -470,7 +481,7 @@ out: /* The session may be reset by one of the error handlers. */ dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); nfs41_sequence_free_slot(res); - return 1; + return ret; out_retry: if (!rpc_restart_call(task)) goto out; -- cgit v0.10.2 From af402ab2b0369c2b1acf4cde72c5ed5050c74e5b Mon Sep 17 00:00:00 2001 From: Idan Kedar Date: Fri, 30 Nov 2012 16:03:31 +0200 Subject: exofs: clean up the correct page collection on write error if ore_write() fails, we would unlock the pages of pcol, which is now empty, rather than pcol_copy which owns the pages when ore_write() is called. this means that no pages will actually be unlocked (pcol.nr_pages == 0) and the writing process (more accurately, the syncing process) will hang waiting for a writeback notification that never comes. moreover, if ore_write() fails, pcol_free() is called for pcol, whereas pcol_copy is the object owning the ore_io_state, thus leaking the ore_io_state. [Boaz] I have simplified Idan's original patch a bit, everything else still holds Signed-off-by: Idan Kedar Signed-off-by: Boaz Harrosh diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index b561810..1634b94 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -676,8 +676,10 @@ static int write_exec(struct page_collect *pcol) return 0; err: - _unlock_pcol_pages(pcol, ret, WRITE); - pcol_free(pcol); + if (!pcol_copy) /* Failed before ownership transfer */ + pcol_copy = pcol; + _unlock_pcol_pages(pcol_copy, ret, WRITE); + pcol_free(pcol_copy); kfree(pcol_copy); return ret; -- cgit v0.10.2 From b0ef9647a0cd6cfd63fed48fbbe6005e4ba92571 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 11 Dec 2012 12:10:14 -0500 Subject: NFSv4.1: Be conservative about the client highest slotid If the server sends us a target that looks like an outlier, but is lower than the existing target, then respect it anyway. However defer actually updating the generation counter until we get a target that doesn't look like an outlier. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c index ed5aa9f..1e6c87c 100644 --- a/fs/nfs/nfs4session.c +++ b/fs/nfs/nfs4session.c @@ -273,20 +273,28 @@ void nfs41_wake_slot_table(struct nfs4_slot_table *tbl) } } +static void nfs41_set_max_slotid_locked(struct nfs4_slot_table *tbl, + u32 target_highest_slotid) +{ + u32 max_slotid; + + max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, target_highest_slotid); + if (max_slotid > tbl->server_highest_slotid) + max_slotid = tbl->server_highest_slotid; + if (max_slotid > tbl->target_highest_slotid) + max_slotid = tbl->target_highest_slotid; + tbl->max_slotid = max_slotid; + nfs41_wake_slot_table(tbl); +} + /* Update the client's idea of target_highest_slotid */ static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, u32 target_highest_slotid) { - unsigned int max_slotid; - if (tbl->target_highest_slotid == target_highest_slotid) return; tbl->target_highest_slotid = target_highest_slotid; tbl->generation++; - - max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid); - tbl->max_slotid = max_slotid; - nfs41_wake_slot_table(tbl); } void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, @@ -296,6 +304,7 @@ void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, nfs41_set_target_slotid_locked(tbl, target_highest_slotid); tbl->d_target_highest_slotid = 0; tbl->d2_target_highest_slotid = 0; + nfs41_set_max_slotid_locked(tbl, target_highest_slotid); spin_unlock(&tbl->slot_tbl_lock); } @@ -370,6 +379,7 @@ void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); if (tbl->generation == slot->generation) nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid); + nfs41_set_max_slotid_locked(tbl, res->sr_target_highest_slotid); spin_unlock(&tbl->slot_tbl_lock); } -- cgit v0.10.2 From d8153d4d8b7b6141770e1416c4a338161205ed1b Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Tue, 14 Jun 2011 17:29:45 +0200 Subject: inotify, fanotify: replace fsnotify_put_group() with fsnotify_destroy_group() Currently in fsnotify_put_group() the ref count of a group is decremented and if it becomes 0 fsnotify_destroy_group() is called. Since a groups ref count is only at group creation set to 1 and never increased after that a call to fsnotify_put_group() always results in a call to fsnotify_destroy_group(). With this patch fsnotify_destroy_group() is called directly. Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index d438036..82ae6d7 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -415,7 +415,7 @@ static int fanotify_release(struct inode *ignored, struct file *file) wake_up(&group->fanotify_data.access_waitq); #endif /* matches the fanotify_init->fsnotify_alloc_group */ - fsnotify_put_group(group); + fsnotify_destroy_group(group); return 0; } @@ -728,13 +728,13 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) break; default: fd = -EINVAL; - goto out_put_group; + goto out_destroy_group; } if (flags & FAN_UNLIMITED_QUEUE) { fd = -EPERM; if (!capable(CAP_SYS_ADMIN)) - goto out_put_group; + goto out_destroy_group; group->max_events = UINT_MAX; } else { group->max_events = FANOTIFY_DEFAULT_MAX_EVENTS; @@ -743,7 +743,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) if (flags & FAN_UNLIMITED_MARKS) { fd = -EPERM; if (!capable(CAP_SYS_ADMIN)) - goto out_put_group; + goto out_destroy_group; group->fanotify_data.max_marks = UINT_MAX; } else { group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS; @@ -751,12 +751,12 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); if (fd < 0) - goto out_put_group; + goto out_destroy_group; return fd; -out_put_group: - fsnotify_put_group(group); +out_destroy_group: + fsnotify_destroy_group(group); return fd; } diff --git a/fs/notify/group.c b/fs/notify/group.c index 63fc294..cfda328 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c @@ -50,7 +50,7 @@ void fsnotify_final_destroy_group(struct fsnotify_group *group) * situtation, the fsnotify_final_destroy_group will get called when that final * mark is freed. */ -static void fsnotify_destroy_group(struct fsnotify_group *group) +void fsnotify_destroy_group(struct fsnotify_group *group) { /* clear all inode marks for this group */ fsnotify_clear_marks_by_group(group); diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 8445fbc..dbafbfc 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -293,10 +293,8 @@ static int inotify_release(struct inode *ignored, struct file *file) pr_debug("%s: group=%p\n", __func__, group); - fsnotify_clear_marks_by_group(group); - /* free this group, matching get was inotify_init->fsnotify_obtain_group */ - fsnotify_put_group(group); + fsnotify_destroy_group(group); return 0; } @@ -712,7 +710,7 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events) if (atomic_inc_return(&group->inotify_data.user->inotify_devs) > inotify_max_user_instances) { - fsnotify_put_group(group); + fsnotify_destroy_group(group); return ERR_PTR(-EMFILE); } @@ -741,7 +739,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags) ret = anon_inode_getfd("inotify", &inotify_fops, group, O_RDONLY | flags); if (ret < 0) - fsnotify_put_group(group); + fsnotify_destroy_group(group); return ret; } diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 63d966d..d2ad345 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -364,7 +364,8 @@ static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops); /* drop reference on a group from fsnotify_alloc_group */ extern void fsnotify_put_group(struct fsnotify_group *group); - +/* destroy group */ +extern void fsnotify_destroy_group(struct fsnotify_group *group); /* take a reference to an event */ extern void fsnotify_get_event(struct fsnotify_event *event); extern void fsnotify_put_event(struct fsnotify_event *event); -- cgit v0.10.2 From 986129520479d689962a42c31acdeaf854ac91f5 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Tue, 14 Jun 2011 17:29:46 +0200 Subject: fsnotify: introduce fsnotify_get_group() Introduce fsnotify_get_group() which increments the reference counter of a group. Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/group.c b/fs/notify/group.c index cfda328..1d57c35 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c @@ -63,6 +63,14 @@ void fsnotify_destroy_group(struct fsnotify_group *group) } /* + * Get reference to a group. + */ +void fsnotify_get_group(struct fsnotify_group *group) +{ + atomic_inc(&group->refcnt); +} + +/* * Drop a reference to a group. Free it if it's through. */ void fsnotify_put_group(struct fsnotify_group *group) diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index d2ad345..e76cef7 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -360,8 +360,10 @@ static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode /* called from fsnotify listeners, such as fanotify or dnotify */ -/* get a reference to an existing or create a new group */ +/* create a new group */ extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops); +/* get reference to a group */ +extern void fsnotify_get_group(struct fsnotify_group *group); /* drop reference on a group from fsnotify_alloc_group */ extern void fsnotify_put_group(struct fsnotify_group *group); /* destroy group */ -- cgit v0.10.2 From 23e964c284ca0a767b80a30482bd53b059d30391 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Tue, 14 Jun 2011 17:29:47 +0200 Subject: fsnotify: use reference counting for groups Get a group ref for each mark that is added to the groups list and release that ref when the mark is freed in fsnotify_put_mark(). We also use get a group reference for duplicated marks and for private event data. Now we dont free a group any more when the number of marks becomes 0 but when the groups ref count does. Since this will only happen when all marks are removed from a groups mark list, we dont have to set the groups number of marks to 1 at group creation. Beside clearing all marks in fsnotify_destroy_group() we do also flush the groups event queue. This is since events may hold references to groups (due to private event data) and we have to put those references first before we get a chance to put the final ref, which will result in a call to fsnotify_final_destroy_group(). Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/group.c b/fs/notify/group.c index 1d57c35..354044c 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c @@ -33,9 +33,6 @@ */ void fsnotify_final_destroy_group(struct fsnotify_group *group) { - /* clear the notification queue of all events */ - fsnotify_flush_notify(group); - if (group->ops->free_group_priv) group->ops->free_group_priv(group); @@ -43,12 +40,10 @@ void fsnotify_final_destroy_group(struct fsnotify_group *group) } /* - * Trying to get rid of a group. We need to first get rid of any outstanding - * allocations and then free the group. Remember that fsnotify_clear_marks_by_group - * could miss marks that are being freed by inode and those marks could still - * hold a reference to this group (via group->num_marks) If we get into that - * situtation, the fsnotify_final_destroy_group will get called when that final - * mark is freed. + * Trying to get rid of a group. Remove all marks, flush all events and release + * the group reference. + * Note that another thread calling fsnotify_clear_marks_by_group() may still + * hold a ref to the group. */ void fsnotify_destroy_group(struct fsnotify_group *group) { @@ -57,9 +52,10 @@ void fsnotify_destroy_group(struct fsnotify_group *group) synchronize_srcu(&fsnotify_mark_srcu); - /* past the point of no return, matches the initial value of 1 */ - if (atomic_dec_and_test(&group->num_marks)) - fsnotify_final_destroy_group(group); + /* clear the notification queue of all events */ + fsnotify_flush_notify(group); + + fsnotify_put_group(group); } /* @@ -76,7 +72,7 @@ void fsnotify_get_group(struct fsnotify_group *group) void fsnotify_put_group(struct fsnotify_group *group) { if (atomic_dec_and_test(&group->refcnt)) - fsnotify_destroy_group(group); + fsnotify_final_destroy_group(group); } /* @@ -92,11 +88,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) /* set to 0 when there a no external references to this group */ atomic_set(&group->refcnt, 1); - /* - * hits 0 when there are no external references AND no marks for - * this group - */ - atomic_set(&group->num_marks, 1); + atomic_set(&group->num_marks, 0); mutex_init(&group->notification_mutex); INIT_LIST_HEAD(&group->notification_list); diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index e3cbd74..74977fb 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c @@ -118,6 +118,7 @@ static int inotify_handle_event(struct fsnotify_group *group, fsn_event_priv = &event_priv->fsnotify_event_priv_data; + fsnotify_get_group(group); fsn_event_priv->group = group; event_priv->wd = wd; @@ -210,6 +211,7 @@ void inotify_free_event_priv(struct fsnotify_event_private_data *fsn_event_priv) event_priv = container_of(fsn_event_priv, struct inotify_event_private_data, fsnotify_event_priv_data); + fsnotify_put_group(fsn_event_priv->group); kmem_cache_free(event_priv_cachep, event_priv); } diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index dbafbfc..246250f 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -531,6 +531,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, fsn_event_priv = &event_priv->fsnotify_event_priv_data; + fsnotify_get_group(group); fsn_event_priv->group = group; event_priv->wd = i_mark->wd; diff --git a/fs/notify/mark.c b/fs/notify/mark.c index f104d56..3c7a169 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -109,8 +109,11 @@ void fsnotify_get_mark(struct fsnotify_mark *mark) void fsnotify_put_mark(struct fsnotify_mark *mark) { - if (atomic_dec_and_test(&mark->refcnt)) + if (atomic_dec_and_test(&mark->refcnt)) { + if (mark->group) + fsnotify_put_group(mark->group); mark->free_mark(mark); + } } /* @@ -125,12 +128,13 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) spin_lock(&mark->lock); + fsnotify_get_group(mark->group); group = mark->group; /* something else already called this function on this mark */ if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { spin_unlock(&mark->lock); - return; + goto put_group; } mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; @@ -177,19 +181,15 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) iput(inode); - /* * We don't necessarily have a ref on mark from caller so the above iput * may have already destroyed it. Don't touch from now on. */ - /* - * it's possible that this group tried to destroy itself, but this - * this mark was simultaneously being freed by inode. If that's the - * case, we finish freeing the group here. - */ - if (unlikely(atomic_dec_and_test(&group->num_marks))) - fsnotify_final_destroy_group(group); + atomic_dec(&group->num_marks); + +put_group: + fsnotify_put_group(group); } void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) @@ -234,6 +234,7 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; + fsnotify_get_group(group); mark->group = group; list_add(&mark->g_list, &group->marks_list); atomic_inc(&group->num_marks); @@ -265,6 +266,7 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, err: mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; list_del_init(&mark->g_list); + fsnotify_put_group(group); mark->group = NULL; atomic_dec(&group->num_marks); @@ -317,6 +319,8 @@ void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *ol assert_spin_locked(&old->lock); new->i.inode = old->i.inode; new->m.mnt = old->m.mnt; + if (old->group) + fsnotify_get_group(old->group); new->group = old->group; new->mask = old->mask; new->free_mark = old->free_mark; -- cgit v0.10.2 From 104d06f08ea59247cb0e7e548c5a5d22d21dcfd5 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Tue, 14 Jun 2011 17:29:48 +0200 Subject: fsnotify: take groups mark_lock before mark lock Race-free addition and removal of a mark to a groups mark list would be easier if we could lock the mark list of group before we lock the specific mark. This patch changes the order used to add/remove marks to/from mark lists from 1. mark->lock 2. group->mark_lock 3. inode->i_lock to 1. group->mark_lock 2. mark->lock 3. inode->i_lock Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 3c7a169..32447dc 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -127,20 +127,27 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) struct inode *inode = NULL; spin_lock(&mark->lock); - + /* dont get the group from a mark that is not alive yet */ + if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { + spin_unlock(&mark->lock); + return; + } fsnotify_get_group(mark->group); group = mark->group; + spin_unlock(&mark->lock); + + spin_lock(&group->mark_lock); + spin_lock(&mark->lock); /* something else already called this function on this mark */ if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { spin_unlock(&mark->lock); + spin_unlock(&group->mark_lock); goto put_group; } mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; - spin_lock(&group->mark_lock); - if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { inode = mark->i.inode; fsnotify_destroy_inode_mark(mark); @@ -151,8 +158,8 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) list_del_init(&mark->g_list); - spin_unlock(&group->mark_lock); spin_unlock(&mark->lock); + spin_unlock(&group->mark_lock); spin_lock(&destroy_lock); list_add(&mark->destroy_list, &destroy_list); @@ -225,13 +232,13 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, /* * LOCKING ORDER!!!! - * mark->lock * group->mark_lock + * mark->lock * inode->i_lock */ - spin_lock(&mark->lock); spin_lock(&group->mark_lock); + spin_lock(&mark->lock); mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; fsnotify_get_group(group); @@ -252,13 +259,12 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, BUG(); } - spin_unlock(&group->mark_lock); - /* this will pin the object if appropriate */ fsnotify_set_mark_mask_locked(mark, mark->mask); - spin_unlock(&mark->lock); + spin_unlock(&group->mark_lock); + if (inode) __fsnotify_update_child_dentry_flags(inode); @@ -270,8 +276,8 @@ err: mark->group = NULL; atomic_dec(&group->num_marks); - spin_unlock(&group->mark_lock); spin_unlock(&mark->lock); + spin_unlock(&group->mark_lock); spin_lock(&destroy_lock); list_add(&mark->destroy_list, &destroy_list); -- cgit v0.10.2 From 6dfbd149946c22c2e2886d6b560def78630c8387 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Tue, 14 Jun 2011 17:29:49 +0200 Subject: fanotify: add an extra flag to mark_remove_from_mask that indicates wheather a mark should be destroyed This patch adds an extra flag to mark_remove_from_mask() to inform the caller if the mark should be destroyed. With this we dont destroy the mark implicitly in the function itself any more but let the caller handle it. Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 82ae6d7..599a019 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -511,7 +511,8 @@ out: static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, __u32 mask, - unsigned int flags) + unsigned int flags, + int *destroy) { __u32 oldmask; @@ -525,8 +526,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, } spin_unlock(&fsn_mark->lock); - if (!(oldmask & ~mask)) - fsnotify_destroy_mark(fsn_mark); + *destroy = !(oldmask & ~mask); return mask & oldmask; } @@ -537,12 +537,17 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, { struct fsnotify_mark *fsn_mark = NULL; __u32 removed; + int destroy_mark; fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); if (!fsn_mark) return -ENOENT; - removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags); + removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, + &destroy_mark); + if (destroy_mark) + fsnotify_destroy_mark(fsn_mark); + fsnotify_put_mark(fsn_mark); if (removed & real_mount(mnt)->mnt_fsnotify_mask) fsnotify_recalc_vfsmount_mask(mnt); @@ -556,12 +561,16 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, { struct fsnotify_mark *fsn_mark = NULL; __u32 removed; + int destroy_mark; fsn_mark = fsnotify_find_inode_mark(group, inode); if (!fsn_mark) return -ENOENT; - removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags); + removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, + &destroy_mark); + if (destroy_mark) + fsnotify_destroy_mark(fsn_mark); /* matches the fsnotify_find_inode_mark() */ fsnotify_put_mark(fsn_mark); if (removed & inode->i_fsnotify_mask) -- cgit v0.10.2 From 986ab09807ca9454c3f54aae4db7e1bb00daeed3 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Tue, 14 Jun 2011 17:29:50 +0200 Subject: fsnotify: use a mutex instead of a spinlock to protect a groups mark list Replaces the groups mark_lock spinlock with a mutex. Using a mutex instead of a spinlock results in more flexibility (i.e it allows to sleep while the lock is held). Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/group.c b/fs/notify/group.c index 354044c..1f73057 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c @@ -95,7 +95,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) init_waitqueue_head(&group->notification_waitq); group->max_events = UINT_MAX; - spin_lock_init(&group->mark_lock); + mutex_init(&group->mark_mutex); INIT_LIST_HEAD(&group->marks_list); group->ops = ops; diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index b13c00a..4e9071e 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c @@ -63,8 +63,8 @@ void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) { struct inode *inode = mark->i.inode; + BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); assert_spin_locked(&mark->lock); - assert_spin_locked(&mark->group->mark_lock); spin_lock(&inode->i_lock); @@ -191,8 +191,8 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, mark->flags |= FSNOTIFY_MARK_FLAG_INODE; + BUG_ON(!mutex_is_locked(&group->mark_mutex)); assert_spin_locked(&mark->lock); - assert_spin_locked(&group->mark_lock); spin_lock(&inode->i_lock); diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 32447dc..ab25b81 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -136,13 +136,13 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) group = mark->group; spin_unlock(&mark->lock); - spin_lock(&group->mark_lock); + mutex_lock(&group->mark_mutex); spin_lock(&mark->lock); /* something else already called this function on this mark */ if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { spin_unlock(&mark->lock); - spin_unlock(&group->mark_lock); + mutex_unlock(&group->mark_mutex); goto put_group; } @@ -159,7 +159,7 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) list_del_init(&mark->g_list); spin_unlock(&mark->lock); - spin_unlock(&group->mark_lock); + mutex_unlock(&group->mark_mutex); spin_lock(&destroy_lock); list_add(&mark->destroy_list, &destroy_list); @@ -232,11 +232,11 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, /* * LOCKING ORDER!!!! - * group->mark_lock + * group->mark_mutex * mark->lock * inode->i_lock */ - spin_lock(&group->mark_lock); + mutex_lock(&group->mark_mutex); spin_lock(&mark->lock); mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; @@ -263,7 +263,7 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_set_mark_mask_locked(mark, mark->mask); spin_unlock(&mark->lock); - spin_unlock(&group->mark_lock); + mutex_unlock(&group->mark_mutex); if (inode) __fsnotify_update_child_dentry_flags(inode); @@ -277,7 +277,7 @@ err: atomic_dec(&group->num_marks); spin_unlock(&mark->lock); - spin_unlock(&group->mark_lock); + mutex_unlock(&group->mark_mutex); spin_lock(&destroy_lock); list_add(&mark->destroy_list, &destroy_list); @@ -296,7 +296,7 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, struct fsnotify_mark *lmark, *mark; LIST_HEAD(free_list); - spin_lock(&group->mark_lock); + mutex_lock(&group->mark_mutex); list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { if (mark->flags & flags) { list_add(&mark->free_g_list, &free_list); @@ -304,7 +304,7 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, fsnotify_get_mark(mark); } } - spin_unlock(&group->mark_lock); + mutex_unlock(&group->mark_mutex); list_for_each_entry_safe(mark, lmark, &free_list, free_g_list) { fsnotify_destroy_mark(mark); diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index b7b4b0e..f26a348 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c @@ -88,8 +88,8 @@ void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) { struct vfsmount *mnt = mark->m.mnt; + BUG_ON(!mutex_is_locked(&mark->group->mark_mutex)); assert_spin_locked(&mark->lock); - assert_spin_locked(&mark->group->mark_lock); spin_lock(&mnt->mnt_root->d_lock); @@ -151,8 +151,8 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; + BUG_ON(!mutex_is_locked(&group->mark_mutex)); assert_spin_locked(&mark->lock); - assert_spin_locked(&group->mark_lock); spin_lock(&mnt->mnt_root->d_lock); diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index e76cef7..c584834 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -141,7 +141,7 @@ struct fsnotify_group { unsigned int priority; /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ - spinlock_t mark_lock; /* protect marks_list */ + struct mutex mark_mutex; /* protect marks_list */ atomic_t num_marks; /* 1 for each mark and 1 for not being * past the point of no return when freeing * a group */ -- cgit v0.10.2 From 3fed40cc97f32bebfd34a55364de9b44dcbede59 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 13 Sep 2012 04:51:36 -0600 Subject: Btrfs: cleanup duplicated division functions div_factor{_fine} has been implemented for two times, cleanup it. And I move them into a independent file named math.h because they are common math functions. Signed-off-by: Miao Xie Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 3d3e2c1..7563db7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -33,6 +33,7 @@ #include "volumes.h" #include "locking.h" #include "free-space-cache.h" +#include "math.h" #undef SCRAMBLE_DELAYED_REFS @@ -649,24 +650,6 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info) rcu_read_unlock(); } -static u64 div_factor(u64 num, int factor) -{ - if (factor == 10) - return num; - num *= factor; - do_div(num, 10); - return num; -} - -static u64 div_factor_fine(u64 num, int factor) -{ - if (factor == 100) - return num; - num *= factor; - do_div(num, 100); - return num; -} - u64 btrfs_find_block_group(struct btrfs_root *root, u64 search_start, u64 search_hint, int owner) { diff --git a/fs/btrfs/math.h b/fs/btrfs/math.h new file mode 100644 index 0000000..b7816ce --- /dev/null +++ b/fs/btrfs/math.h @@ -0,0 +1,44 @@ + +/* + * Copyright (C) 2012 Fujitsu. All rights reserved. + * Written by Miao Xie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#ifndef __BTRFS_MATH_H +#define __BTRFS_MATH_H + +#include + +static inline u64 div_factor(u64 num, int factor) +{ + if (factor == 10) + return num; + num *= factor; + do_div(num, 10); + return num; +} + +static inline u64 div_factor_fine(u64 num, int factor) +{ + if (factor == 100) + return num; + num *= factor; + do_div(num, 100); + return num; +} + +#endif diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 0f5ebb7..a8adf26 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "compat.h" #include "ctree.h" #include "extent_map.h" @@ -36,6 +35,7 @@ #include "async-thread.h" #include "check-integrity.h" #include "rcu-string.h" +#include "math.h" static int init_first_rw_device(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -2338,18 +2338,6 @@ static int chunk_profiles_filter(u64 chunk_type, return 1; } -static u64 div_factor_fine(u64 num, int factor) -{ - if (factor <= 0) - return 0; - if (factor >= 100) - return num; - - num *= factor; - do_div(num, 100); - return num; -} - static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, struct btrfs_balance_args *bargs) { @@ -2514,15 +2502,6 @@ static int should_balance_chunk(struct btrfs_root *root, return 1; } -static u64 div_factor(u64 num, int factor) -{ - if (factor == 10) - return num; - num *= factor; - do_div(num, 10); - return num; -} - static int __btrfs_balance(struct btrfs_fs_info *fs_info) { struct btrfs_balance_control *bctl = fs_info->balance_ctl; -- cgit v0.10.2 From 561c294d4cfb30c4acfa0a243448fc55af730d87 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Tue, 16 Oct 2012 11:32:18 +0000 Subject: Btrfs: fix wrong comment in can_overcommit() The comment is not coincident with the code. Fix it. Signed-off-by: Miao Xie Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 7563db7..2cfcce2 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3668,9 +3668,9 @@ static int can_overcommit(struct btrfs_root *root, avail >>= 1; /* - * If we aren't flushing don't let us overcommit too much, say - * 1/8th of the space. If we can flush, let it overcommit up to - * 1/2 of the space. + * If we aren't flushing all things, let us overcommit up to + * 1/2th of the space. If we can flush, don't let us overcommit + * too much, let it overcommit up to 1/8 of the space. */ if (flush) avail >>= 3; -- cgit v0.10.2 From 08e007d2e57744472a9424735a368ffe6d625597 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Tue, 16 Oct 2012 11:33:38 +0000 Subject: Btrfs: improve the noflush reservation In some places(such as: evicting inode), we just can not flush the reserved space of delalloc, flushing the delayed directory index and delayed inode is OK, but we don't try to flush those things and just go back when there is no enough space to be reserved. This patch fixes this problem. We defined 3 types of the flush operations: NO_FLUSH, FLUSH_LIMIT and FLUSH_ALL. If we can in the transaction, we should not flush anything, or the deadlock would happen, so use NO_FLUSH. If we flushing the reserved space of delalloc would cause deadlock, use FLUSH_LIMIT. In the other cases, FLUSH_ALL is used, and we will flush all things. Signed-off-by: Miao Xie Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index c72ead8..8fd9fe4 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2900,6 +2900,18 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans, u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags); u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data); void btrfs_clear_space_info_full(struct btrfs_fs_info *info); + +enum btrfs_reserve_flush_enum { + /* If we are in the transaction, we can't flush anything.*/ + BTRFS_RESERVE_NO_FLUSH, + /* + * Flushing delalloc may cause deadlock somewhere, in this + * case, use FLUSH LIMIT + */ + BTRFS_RESERVE_FLUSH_LIMIT, + BTRFS_RESERVE_FLUSH_ALL, +}; + int btrfs_check_data_free_space(struct inode *inode, u64 bytes); void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes); void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, @@ -2919,19 +2931,13 @@ struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root, void btrfs_free_block_rsv(struct btrfs_root *root, struct btrfs_block_rsv *rsv); int btrfs_block_rsv_add(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 num_bytes); -int btrfs_block_rsv_add_noflush(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 num_bytes); + struct btrfs_block_rsv *block_rsv, u64 num_bytes, + enum btrfs_reserve_flush_enum flush); int btrfs_block_rsv_check(struct btrfs_root *root, struct btrfs_block_rsv *block_rsv, int min_factor); int btrfs_block_rsv_refill(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 min_reserved); -int btrfs_block_rsv_refill_noflush(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 min_reserved); + struct btrfs_block_rsv *block_rsv, u64 min_reserved, + enum btrfs_reserve_flush_enum flush); int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv, struct btrfs_block_rsv *dst_rsv, u64 num_bytes); diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 478f66b..0c6dca5 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -651,7 +651,8 @@ static int btrfs_delayed_inode_reserve_metadata( */ if (!src_rsv || (!trans->bytes_reserved && src_rsv->type != BTRFS_BLOCK_RSV_DELALLOC)) { - ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes); + ret = btrfs_block_rsv_add(root, dst_rsv, num_bytes, + BTRFS_RESERVE_NO_FLUSH); /* * Since we're under a transaction reserve_metadata_bytes could * try to commit the transaction which will make it return @@ -686,7 +687,8 @@ static int btrfs_delayed_inode_reserve_metadata( * reserve something strictly for us. If not be a pain and try * to steal from the delalloc block rsv. */ - ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes); + ret = btrfs_block_rsv_add(root, dst_rsv, num_bytes, + BTRFS_RESERVE_NO_FLUSH); if (!ret) goto out; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2cfcce2..2136add 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3644,7 +3644,7 @@ out: static int can_overcommit(struct btrfs_root *root, struct btrfs_space_info *space_info, u64 bytes, - int flush) + enum btrfs_reserve_flush_enum flush) { u64 profile = btrfs_get_alloc_profile(root, 0); u64 avail; @@ -3672,7 +3672,7 @@ static int can_overcommit(struct btrfs_root *root, * 1/2th of the space. If we can flush, don't let us overcommit * too much, let it overcommit up to 1/8 of the space. */ - if (flush) + if (flush == BTRFS_RESERVE_FLUSH_ALL) avail >>= 3; else avail >>= 1; @@ -3696,6 +3696,7 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig, long time_left; unsigned long nr_pages = (2 * 1024 * 1024) >> PAGE_CACHE_SHIFT; int loops = 0; + enum btrfs_reserve_flush_enum flush; trans = (struct btrfs_trans_handle *)current->journal_info; block_rsv = &root->fs_info->delalloc_block_rsv; @@ -3723,8 +3724,12 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig, wait_event(root->fs_info->async_submit_wait, !atomic_read(&root->fs_info->async_delalloc_pages)); + if (!trans) + flush = BTRFS_RESERVE_FLUSH_ALL; + else + flush = BTRFS_RESERVE_NO_FLUSH; spin_lock(&space_info->lock); - if (can_overcommit(root, space_info, orig, !trans)) { + if (can_overcommit(root, space_info, orig, flush)) { spin_unlock(&space_info->lock); break; } @@ -3882,7 +3887,8 @@ static int flush_space(struct btrfs_root *root, */ static int reserve_metadata_bytes(struct btrfs_root *root, struct btrfs_block_rsv *block_rsv, - u64 orig_bytes, int flush) + u64 orig_bytes, + enum btrfs_reserve_flush_enum flush) { struct btrfs_space_info *space_info = block_rsv->space_info; u64 used; @@ -3895,10 +3901,11 @@ again: ret = 0; spin_lock(&space_info->lock); /* - * We only want to wait if somebody other than us is flushing and we are - * actually alloed to flush. + * We only want to wait if somebody other than us is flushing and we + * are actually allowed to flush all things. */ - while (flush && !flushing && space_info->flush) { + while (flush == BTRFS_RESERVE_FLUSH_ALL && !flushing && + space_info->flush) { spin_unlock(&space_info->lock); /* * If we have a trans handle we can't wait because the flusher @@ -3964,23 +3971,40 @@ again: * Couldn't make our reservation, save our place so while we're trying * to reclaim space we can actually use it instead of somebody else * stealing it from us. + * + * We make the other tasks wait for the flush only when we can flush + * all things. */ - if (ret && flush) { + if (ret && flush == BTRFS_RESERVE_FLUSH_ALL) { flushing = true; space_info->flush = 1; } spin_unlock(&space_info->lock); - if (!ret || !flush) + if (!ret || flush == BTRFS_RESERVE_NO_FLUSH) goto out; ret = flush_space(root, space_info, num_bytes, orig_bytes, flush_state); flush_state++; + + /* + * If we are FLUSH_LIMIT, we can not flush delalloc, or the deadlock + * would happen. So skip delalloc flush. + */ + if (flush == BTRFS_RESERVE_FLUSH_LIMIT && + (flush_state == FLUSH_DELALLOC || + flush_state == FLUSH_DELALLOC_WAIT)) + flush_state = ALLOC_CHUNK; + if (!ret) goto again; - else if (flush_state <= COMMIT_TRANS) + else if (flush == BTRFS_RESERVE_FLUSH_LIMIT && + flush_state < COMMIT_TRANS) + goto again; + else if (flush == BTRFS_RESERVE_FLUSH_ALL && + flush_state <= COMMIT_TRANS) goto again; out: @@ -4131,9 +4155,9 @@ void btrfs_free_block_rsv(struct btrfs_root *root, kfree(rsv); } -static inline int __block_rsv_add(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 num_bytes, int flush) +int btrfs_block_rsv_add(struct btrfs_root *root, + struct btrfs_block_rsv *block_rsv, u64 num_bytes, + enum btrfs_reserve_flush_enum flush) { int ret; @@ -4149,20 +4173,6 @@ static inline int __block_rsv_add(struct btrfs_root *root, return ret; } -int btrfs_block_rsv_add(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 num_bytes) -{ - return __block_rsv_add(root, block_rsv, num_bytes, 1); -} - -int btrfs_block_rsv_add_noflush(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 num_bytes) -{ - return __block_rsv_add(root, block_rsv, num_bytes, 0); -} - int btrfs_block_rsv_check(struct btrfs_root *root, struct btrfs_block_rsv *block_rsv, int min_factor) { @@ -4181,9 +4191,9 @@ int btrfs_block_rsv_check(struct btrfs_root *root, return ret; } -static inline int __btrfs_block_rsv_refill(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 min_reserved, int flush) +int btrfs_block_rsv_refill(struct btrfs_root *root, + struct btrfs_block_rsv *block_rsv, u64 min_reserved, + enum btrfs_reserve_flush_enum flush) { u64 num_bytes = 0; int ret = -ENOSPC; @@ -4211,20 +4221,6 @@ static inline int __btrfs_block_rsv_refill(struct btrfs_root *root, return ret; } -int btrfs_block_rsv_refill(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 min_reserved) -{ - return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 1); -} - -int btrfs_block_rsv_refill_noflush(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 min_reserved) -{ - return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 0); -} - int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv, struct btrfs_block_rsv *dst_rsv, u64 num_bytes) @@ -4515,14 +4511,15 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) u64 csum_bytes; unsigned nr_extents = 0; int extra_reserve = 0; - int flush = 1; + enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL; int ret; /* Need to be holding the i_mutex here if we aren't free space cache */ if (btrfs_is_free_space_inode(inode)) - flush = 0; + flush = BTRFS_RESERVE_NO_FLUSH; - if (flush && btrfs_transaction_in_commit(root->fs_info)) + if (flush != BTRFS_RESERVE_NO_FLUSH && + btrfs_transaction_in_commit(root->fs_info)) schedule_timeout(1); mutex_lock(&BTRFS_I(inode)->delalloc_mutex); @@ -6252,7 +6249,8 @@ use_block_rsv(struct btrfs_trans_handle *trans, block_rsv = get_block_rsv(trans, root); if (block_rsv->size == 0) { - ret = reserve_metadata_bytes(root, block_rsv, blocksize, 0); + ret = reserve_metadata_bytes(root, block_rsv, blocksize, + BTRFS_RESERVE_NO_FLUSH); /* * If we couldn't reserve metadata bytes try and use some from * the global reserve. @@ -6279,7 +6277,8 @@ use_block_rsv(struct btrfs_trans_handle *trans, printk(KERN_DEBUG "btrfs: block rsv returned %d\n", ret); WARN_ON(1); } - ret = reserve_metadata_bytes(root, block_rsv, blocksize, 0); + ret = reserve_metadata_bytes(root, block_rsv, blocksize, + BTRFS_RESERVE_NO_FLUSH); if (!ret) { return block_rsv; } else if (ret && block_rsv != global_rsv) { diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index b1a1c92..d26f67a 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -434,8 +434,9 @@ int btrfs_save_ino_cache(struct btrfs_root *root, * 3 items for pre-allocation */ trans->bytes_reserved = btrfs_calc_trans_metadata_size(root, 8); - ret = btrfs_block_rsv_add_noflush(root, trans->block_rsv, - trans->bytes_reserved); + ret = btrfs_block_rsv_add(root, trans->block_rsv, + trans->bytes_reserved, + BTRFS_RESERVE_NO_FLUSH); if (ret) goto out; trace_btrfs_space_reservation(root->fs_info, "ino_cache", diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 95542a1..db3dd4e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3829,7 +3829,8 @@ void btrfs_evict_inode(struct inode *inode) * inode item when doing the truncate. */ while (1) { - ret = btrfs_block_rsv_refill_noflush(root, rsv, min_size); + ret = btrfs_block_rsv_refill(root, rsv, min_size, + BTRFS_RESERVE_FLUSH_LIMIT); /* * Try and steal from the global reserve since we will @@ -3847,7 +3848,7 @@ void btrfs_evict_inode(struct inode *inode) goto no_delete; } - trans = btrfs_start_transaction_noflush(root, 1); + trans = btrfs_start_transaction_lflush(root, 1); if (IS_ERR(trans)) { btrfs_orphan_del(NULL, inode); btrfs_free_block_rsv(root, rsv); diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 776f0aa..242d6de 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -2074,7 +2074,8 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, BUG_ON(IS_ERR(trans)); trans->block_rsv = rc->block_rsv; - ret = btrfs_block_rsv_refill(root, rc->block_rsv, min_reserved); + ret = btrfs_block_rsv_refill(root, rc->block_rsv, min_reserved, + BTRFS_RESERVE_FLUSH_ALL); if (ret) { BUG_ON(ret != -EAGAIN); ret = btrfs_commit_transaction(trans, root); @@ -2184,7 +2185,8 @@ int prepare_to_merge(struct reloc_control *rc, int err) again: if (!err) { num_bytes = rc->merging_rsv_size; - ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes); + ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes, + BTRFS_RESERVE_FLUSH_ALL); if (ret) err = ret; } @@ -2459,7 +2461,8 @@ static int reserve_metadata_space(struct btrfs_trans_handle *trans, num_bytes = calcu_metadata_size(rc, node, 1) * 2; trans->block_rsv = rc->block_rsv; - ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes); + ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes, + BTRFS_RESERVE_FLUSH_ALL); if (ret) { if (ret == -EAGAIN) rc->commit_transaction = 1; @@ -3685,7 +3688,8 @@ int prepare_to_relocate(struct reloc_control *rc) * is no reservation in transaction handle. */ ret = btrfs_block_rsv_add(rc->extent_root, rc->block_rsv, - rc->extent_root->nodesize * 256); + rc->extent_root->nodesize * 256, + BTRFS_RESERVE_FLUSH_ALL); if (ret) return ret; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 04bbfb1..4e1def4 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -295,9 +295,9 @@ static int may_wait_transaction(struct btrfs_root *root, int type) return 0; } -static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, - u64 num_items, int type, - int noflush) +static struct btrfs_trans_handle * +start_transaction(struct btrfs_root *root, u64 num_items, int type, + enum btrfs_reserve_flush_enum flush) { struct btrfs_trans_handle *h; struct btrfs_transaction *cur_trans; @@ -331,14 +331,9 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, } num_bytes = btrfs_calc_trans_metadata_size(root, num_items); - if (noflush) - ret = btrfs_block_rsv_add_noflush(root, - &root->fs_info->trans_block_rsv, - num_bytes); - else - ret = btrfs_block_rsv_add(root, - &root->fs_info->trans_block_rsv, - num_bytes); + ret = btrfs_block_rsv_add(root, + &root->fs_info->trans_block_rsv, + num_bytes, flush); if (ret) return ERR_PTR(ret); } @@ -422,13 +417,15 @@ got_it: struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, int num_items) { - return start_transaction(root, num_items, TRANS_START, 0); + return start_transaction(root, num_items, TRANS_START, + BTRFS_RESERVE_FLUSH_ALL); } -struct btrfs_trans_handle *btrfs_start_transaction_noflush( +struct btrfs_trans_handle *btrfs_start_transaction_lflush( struct btrfs_root *root, int num_items) { - return start_transaction(root, num_items, TRANS_START, 1); + return start_transaction(root, num_items, TRANS_START, + BTRFS_RESERVE_FLUSH_LIMIT); } struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root) @@ -1032,8 +1029,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, btrfs_reloc_pre_snapshot(trans, pending, &to_reserve); if (to_reserve > 0) { - ret = btrfs_block_rsv_add_noflush(root, &pending->block_rsv, - to_reserve); + ret = btrfs_block_rsv_add(root, &pending->block_rsv, + to_reserve, + BTRFS_RESERVE_NO_FLUSH); if (ret) { pending->error = ret; goto no_free_objectid; diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 8096194..0e8aa1e 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h @@ -105,7 +105,7 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans, struct btrfs_root *root); struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, int num_items); -struct btrfs_trans_handle *btrfs_start_transaction_noflush( +struct btrfs_trans_handle *btrfs_start_transaction_lflush( struct btrfs_root *root, int num_items); struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root); struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root); -- cgit v0.10.2 From de1ee92ac3bce4c9d760016c4d6198158e6e2f15 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 19 Oct 2012 16:50:56 -0400 Subject: Btrfs: recheck bio against block device when we map the bio Alex reported a problem where we were writing between chunks on a rbd device. The thing is we do bio_add_page using logical offsets, but the physical offset may be different. So when we map the bio now check to see if the bio is still ok with the physical offset, and if it is not split the bio up and redo the bio_add_page with the physical sector. This fixes the problem for Alex and doesn't affect performance in the normal case. Thanks, Reported-and-tested-by: Alex Elder Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index a8adf26..eaaf0bf 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4217,6 +4217,113 @@ static noinline void schedule_bio(struct btrfs_root *root, &device->work); } +static int bio_size_ok(struct block_device *bdev, struct bio *bio, + sector_t sector) +{ + struct bio_vec *prev; + struct request_queue *q = bdev_get_queue(bdev); + unsigned short max_sectors = queue_max_sectors(q); + struct bvec_merge_data bvm = { + .bi_bdev = bdev, + .bi_sector = sector, + .bi_rw = bio->bi_rw, + }; + + if (bio->bi_vcnt == 0) { + WARN_ON(1); + return 1; + } + + prev = &bio->bi_io_vec[bio->bi_vcnt - 1]; + if ((bio->bi_size >> 9) > max_sectors) + return 0; + + if (!q->merge_bvec_fn) + return 1; + + bvm.bi_size = bio->bi_size - prev->bv_len; + if (q->merge_bvec_fn(q, &bvm, prev) < prev->bv_len) + return 0; + return 1; +} + +static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio, + struct bio *bio, u64 physical, int dev_nr, + int rw, int async) +{ + struct btrfs_device *dev = bbio->stripes[dev_nr].dev; + + bio->bi_private = bbio; + bio->bi_private = merge_stripe_index_into_bio_private( + bio->bi_private, (unsigned int)dev_nr); + bio->bi_end_io = btrfs_end_bio; + bio->bi_sector = physical >> 9; +#ifdef DEBUG + { + struct rcu_string *name; + + rcu_read_lock(); + name = rcu_dereference(dev->name); + pr_debug("btrfs_map_bio: rw %d, secor=%llu, dev=%lu " + "(%s id %llu), size=%u\n", rw, + (u64)bio->bi_sector, (u_long)dev->bdev->bd_dev, + name->str, dev->devid, bio->bi_size); + rcu_read_unlock(); + } +#endif + bio->bi_bdev = dev->bdev; + if (async) + schedule_bio(root, dev, rw, bio); + else + btrfsic_submit_bio(rw, bio); +} + +static int breakup_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio, + struct bio *first_bio, struct btrfs_device *dev, + int dev_nr, int rw, int async) +{ + struct bio_vec *bvec = first_bio->bi_io_vec; + struct bio *bio; + int nr_vecs = bio_get_nr_vecs(dev->bdev); + u64 physical = bbio->stripes[dev_nr].physical; + +again: + bio = btrfs_bio_alloc(dev->bdev, physical >> 9, nr_vecs, GFP_NOFS); + if (!bio) + return -ENOMEM; + + while (bvec <= (first_bio->bi_io_vec + first_bio->bi_vcnt - 1)) { + if (bio_add_page(bio, bvec->bv_page, bvec->bv_len, + bvec->bv_offset) < bvec->bv_len) { + u64 len = bio->bi_size; + + atomic_inc(&bbio->stripes_pending); + submit_stripe_bio(root, bbio, bio, physical, dev_nr, + rw, async); + physical += len; + goto again; + } + bvec++; + } + + submit_stripe_bio(root, bbio, bio, physical, dev_nr, rw, async); + return 0; +} + +static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) +{ + atomic_inc(&bbio->error); + if (atomic_dec_and_test(&bbio->stripes_pending)) { + bio->bi_private = bbio->private; + bio->bi_end_io = bbio->end_io; + bio->bi_bdev = (struct block_device *) + (unsigned long)bbio->mirror_num; + bio->bi_sector = logical >> 9; + kfree(bbio); + bio_endio(bio, -EIO); + } +} + int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, int mirror_num, int async_submit) { @@ -4255,40 +4362,36 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, atomic_set(&bbio->stripes_pending, bbio->num_stripes); while (dev_nr < total_devs) { + dev = bbio->stripes[dev_nr].dev; + if (!dev || !dev->bdev || (rw & WRITE && !dev->writeable)) { + bbio_error(bbio, first_bio, logical); + dev_nr++; + continue; + } + + /* + * Check and see if we're ok with this bio based on it's size + * and offset with the given device. + */ + if (!bio_size_ok(dev->bdev, first_bio, + bbio->stripes[dev_nr].physical >> 9)) { + ret = breakup_stripe_bio(root, bbio, first_bio, dev, + dev_nr, rw, async_submit); + BUG_ON(ret); + dev_nr++; + continue; + } + if (dev_nr < total_devs - 1) { bio = bio_clone(first_bio, GFP_NOFS); BUG_ON(!bio); /* -ENOMEM */ } else { bio = first_bio; } - bio->bi_private = bbio; - bio->bi_private = merge_stripe_index_into_bio_private( - bio->bi_private, (unsigned int)dev_nr); - bio->bi_end_io = btrfs_end_bio; - bio->bi_sector = bbio->stripes[dev_nr].physical >> 9; - dev = bbio->stripes[dev_nr].dev; - if (dev && dev->bdev && (rw != WRITE || dev->writeable)) { -#ifdef DEBUG - struct rcu_string *name; - - rcu_read_lock(); - name = rcu_dereference(dev->name); - pr_debug("btrfs_map_bio: rw %d, secor=%llu, dev=%lu " - "(%s id %llu), size=%u\n", rw, - (u64)bio->bi_sector, (u_long)dev->bdev->bd_dev, - name->str, dev->devid, bio->bi_size); - rcu_read_unlock(); -#endif - bio->bi_bdev = dev->bdev; - if (async_submit) - schedule_bio(root, dev, rw, bio); - else - btrfsic_submit_bio(rw, bio); - } else { - bio->bi_bdev = root->fs_info->fs_devices->latest_bdev; - bio->bi_sector = logical >> 9; - bio_endio(bio, -EIO); - } + + submit_stripe_bio(root, bbio, bio, + bbio->stripes[dev_nr].physical, dev_nr, rw, + async_submit); dev_nr++; } return 0; -- cgit v0.10.2 From de6c4115a297d4bbf178aca9948c3539f89c9caa Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 18 Oct 2012 08:18:01 +0000 Subject: Btrfs: fix unnecessary while loop when search the free space, cache When we find a bitmap free space entry, we may check the previous extent entry covers the offset or not. But if we find this entry is also a bitmap entry, we will continue to check the previous entry of the current one by a while loop. It is unnecessary because it is impossible that the extent entry which is in front of a bitmap entry can cover the offset of the entry after that bitmap entry. Signed-off-by: Miao Xie Reviewed-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 1027b85..557502c 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -1250,18 +1250,13 @@ tree_search_offset(struct btrfs_free_space_ctl *ctl, * if previous extent entry covers the offset, * we should return it instead of the bitmap entry */ - n = &entry->offset_index; - while (1) { - n = rb_prev(n); - if (!n) - break; + n = rb_prev(&entry->offset_index); + if (n) { prev = rb_entry(n, struct btrfs_free_space, offset_index); - if (!prev->bitmap) { - if (prev->offset + prev->bytes > offset) - entry = prev; - break; - } + if (!prev->bitmap && + prev->offset + prev->bytes > offset) + entry = prev; } } return entry; @@ -1287,18 +1282,13 @@ tree_search_offset(struct btrfs_free_space_ctl *ctl, } if (entry->bitmap) { - n = &entry->offset_index; - while (1) { - n = rb_prev(n); - if (!n) - break; + n = rb_prev(&entry->offset_index); + if (n) { prev = rb_entry(n, struct btrfs_free_space, offset_index); - if (!prev->bitmap) { - if (prev->offset + prev->bytes > offset) - return prev; - break; - } + if (!prev->bitmap && + prev->offset + prev->bytes > offset) + return prev; } if (entry->offset + BITS_PER_BITMAP * ctl->unit > offset) return entry; -- cgit v0.10.2 From 95c80bb1f6b24b57058d971ed252b2c1c5121b51 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 19 Oct 2012 09:50:52 +0000 Subject: Btrfs: MOD_LOG_KEY_REMOVE_WHILE_MOVING never change node's nritems Key MOD_LOG_KEY_REMOVE_WHILE_MOVING means that we're doing memmove inside an extent buffer node, and the node's number of items remains unchanged (unless we are inserting a single pointer, but we have MOD_LOG_KEY_ADD for that). So we don't need to increase node's number of items during rewinding, otherwise we may get an node larger than leafsize and cause general protection errors later. Here is the details, - If we do memory move for inserting a single pointer, we need to add node's nritems by one, and we honor MOD_LOG_KEY_ADD for adding. - If we do memory move for deleting a single pointer, we need to decrease node's nritems by one, and we honor MOD_LOG_KEY_REMOVE for deleting. - If we do memory move for balance left/right, we need to decrease node's nritems, and we honor MOD_LOG_KEY_REMOVE for balaning. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index cdfb4c4..b12c039 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1140,13 +1140,13 @@ __tree_mod_log_rewind(struct extent_buffer *eb, u64 time_seq, switch (tm->op) { case MOD_LOG_KEY_REMOVE_WHILE_FREEING: BUG_ON(tm->slot < n); - case MOD_LOG_KEY_REMOVE_WHILE_MOVING: case MOD_LOG_KEY_REMOVE: + n++; + case MOD_LOG_KEY_REMOVE_WHILE_MOVING: btrfs_set_node_key(eb, &tm->key, tm->slot); btrfs_set_node_blockptr(eb, tm->slot, tm->blockptr); btrfs_set_node_ptr_generation(eb, tm->slot, tm->generation); - n++; break; case MOD_LOG_KEY_REPLACE: BUG_ON(tm->slot >= n); -- cgit v0.10.2 From 6a7a665d78c5dd8bc76a010648c4e7d84517ab5a Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 19 Oct 2012 09:50:53 +0000 Subject: Btrfs: reorder tree mod log operations in deleting a pointer Since we don't use MOD_LOG_KEY_REMOVE_WHILE_MOVING to add nritems during rewinding, we should insert a MOD_LOG_KEY_REMOVE operation first. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index b12c039..4d518bd 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -4609,6 +4609,12 @@ static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, u32 nritems; int ret; + if (tree_mod_log && level) { + ret = tree_mod_log_insert_key(root->fs_info, parent, slot, + MOD_LOG_KEY_REMOVE); + BUG_ON(ret < 0); + } + nritems = btrfs_header_nritems(parent); if (slot != nritems - 1) { if (tree_mod_log && level) @@ -4619,10 +4625,6 @@ static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, btrfs_node_key_ptr_offset(slot + 1), sizeof(struct btrfs_key_ptr) * (nritems - slot - 1)); - } else if (tree_mod_log && level) { - ret = tree_mod_log_insert_key(root->fs_info, parent, slot, - MOD_LOG_KEY_REMOVE); - BUG_ON(ret < 0); } nritems--; -- cgit v0.10.2 From 0e411ecec60138f22442728f036d38cfea007817 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 19 Oct 2012 09:50:54 +0000 Subject: Btrfs: kill unnecessary arguments in del_ptr The argument 'tree_mod_log' is not necessary since all of callers enable it. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 4d518bd..615b749 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -38,8 +38,7 @@ static int balance_node_right(struct btrfs_trans_handle *trans, struct extent_buffer *dst_buf, struct extent_buffer *src_buf); static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct btrfs_path *path, int level, int slot, - int tree_mod_log); + struct btrfs_path *path, int level, int slot); static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb); struct extent_buffer *read_old_tree_block(struct btrfs_root *root, u64 bytenr, @@ -1827,7 +1826,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, if (btrfs_header_nritems(right) == 0) { clean_tree_block(trans, root, right); btrfs_tree_unlock(right); - del_ptr(trans, root, path, level + 1, pslot + 1, 1); + del_ptr(trans, root, path, level + 1, pslot + 1); root_sub_used(root, right->len); btrfs_free_tree_block(trans, root, right, 0, 1); free_extent_buffer_stale(right); @@ -1871,7 +1870,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, if (btrfs_header_nritems(mid) == 0) { clean_tree_block(trans, root, mid); btrfs_tree_unlock(mid); - del_ptr(trans, root, path, level + 1, pslot, 1); + del_ptr(trans, root, path, level + 1, pslot); root_sub_used(root, mid->len); btrfs_free_tree_block(trans, root, mid, 0, 1); free_extent_buffer_stale(mid); @@ -4602,14 +4601,13 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root * empty a node. */ static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct btrfs_path *path, int level, int slot, - int tree_mod_log) + struct btrfs_path *path, int level, int slot) { struct extent_buffer *parent = path->nodes[level]; u32 nritems; int ret; - if (tree_mod_log && level) { + if (level) { ret = tree_mod_log_insert_key(root->fs_info, parent, slot, MOD_LOG_KEY_REMOVE); BUG_ON(ret < 0); @@ -4617,7 +4615,7 @@ static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, nritems = btrfs_header_nritems(parent); if (slot != nritems - 1) { - if (tree_mod_log && level) + if (level) tree_mod_log_eb_move(root->fs_info, parent, slot, slot + 1, nritems - slot - 1); memmove_extent_buffer(parent, @@ -4658,7 +4656,7 @@ static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans, struct extent_buffer *leaf) { WARN_ON(btrfs_header_generation(leaf) != trans->transid); - del_ptr(trans, root, path, 1, path->slots[1], 1); + del_ptr(trans, root, path, 1, path->slots[1]); /* * btrfs_free_extent is expensive, we want to make sure we -- cgit v0.10.2 From 32adf0901371c8b9d258dba7811f3067d1d2ea5c Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 19 Oct 2012 12:52:15 +0000 Subject: Btrfs: cleanup unused arguments 'disk_key' is not used at all. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 615b749..100c274 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -775,8 +775,7 @@ tree_mod_log_eb_move(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, static noinline void tree_mod_log_set_node_key(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb, - struct btrfs_disk_key *disk_key, int slot, int atomic) + struct extent_buffer *eb, int slot, int atomic) { int ret; @@ -1835,7 +1834,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, struct btrfs_disk_key right_key; btrfs_node_key(right, &right_key, 0); tree_mod_log_set_node_key(root->fs_info, parent, - &right_key, pslot + 1, 0); + pslot + 1, 0); btrfs_set_node_key(parent, &right_key, pslot + 1); btrfs_mark_buffer_dirty(parent); } @@ -1879,7 +1878,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, /* update the parent key to reflect our changes */ struct btrfs_disk_key mid_key; btrfs_node_key(mid, &mid_key, 0); - tree_mod_log_set_node_key(root->fs_info, parent, &mid_key, + tree_mod_log_set_node_key(root->fs_info, parent, pslot, 0); btrfs_set_node_key(parent, &mid_key, pslot); btrfs_mark_buffer_dirty(parent); @@ -1979,7 +1978,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, orig_slot += left_nr; btrfs_node_key(mid, &disk_key, 0); tree_mod_log_set_node_key(root->fs_info, parent, - &disk_key, pslot, 0); + pslot, 0); btrfs_set_node_key(parent, &disk_key, pslot); btrfs_mark_buffer_dirty(parent); if (btrfs_header_nritems(left) > orig_slot) { @@ -2032,7 +2031,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, btrfs_node_key(right, &disk_key, 0); tree_mod_log_set_node_key(root->fs_info, parent, - &disk_key, pslot + 1, 0); + pslot + 1, 0); btrfs_set_node_key(parent, &disk_key, pslot + 1); btrfs_mark_buffer_dirty(parent); @@ -2916,7 +2915,7 @@ static void fixup_low_keys(struct btrfs_trans_handle *trans, if (!path->nodes[i]) break; t = path->nodes[i]; - tree_mod_log_set_node_key(root->fs_info, t, key, tslot, 1); + tree_mod_log_set_node_key(root->fs_info, t, tslot, 1); btrfs_set_node_key(t, key, tslot); btrfs_mark_buffer_dirty(path->nodes[i]); if (tslot != 0) -- cgit v0.10.2 From 7b398f8e58c415738e397645c926253c428cf002 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Mon, 22 Oct 2012 15:52:28 -0400 Subject: Btrfs: fill the global reserve when unpinning space Dave gave me an image of a very full file system that would abort the transaction because it ran out of space while committing the transaction. This is because we would think there was plenty of room to create a snapshot even though the global reserve was not full. This happens because we calculate the global reserve size before we unpin any space, so after we unpin the space we allow reservations to occur even though we haven't reserved all of the space for our global reserve. Fix this by adding to the global reserve while unpinning in order to make sure we always have enough space to do our work. With this patch we no longer end up with an aborted transaction, we return ENOSPC properly to the person trying to create the snapshot. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2136add..b495cb4 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4949,9 +4949,13 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) { struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_block_group_cache *cache = NULL; + struct btrfs_space_info *space_info; + struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; u64 len; + bool readonly; while (start <= end) { + readonly = false; if (!cache || start >= cache->key.objectid + cache->key.offset) { if (cache) @@ -4969,15 +4973,30 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) } start += len; + space_info = cache->space_info; - spin_lock(&cache->space_info->lock); + spin_lock(&space_info->lock); spin_lock(&cache->lock); cache->pinned -= len; - cache->space_info->bytes_pinned -= len; - if (cache->ro) - cache->space_info->bytes_readonly += len; + space_info->bytes_pinned -= len; + if (cache->ro) { + space_info->bytes_readonly += len; + readonly = true; + } spin_unlock(&cache->lock); - spin_unlock(&cache->space_info->lock); + if (!readonly && global_rsv->space_info == space_info) { + spin_lock(&global_rsv->lock); + if (!global_rsv->full) { + len = min(len, global_rsv->size - + global_rsv->reserved); + global_rsv->reserved += len; + space_info->bytes_may_use += len; + if (global_rsv->reserved >= global_rsv->size) + global_rsv->full = 1; + } + spin_unlock(&global_rsv->lock); + } + spin_unlock(&space_info->lock); } if (cache) -- cgit v0.10.2 From 8ccf6f19b67f7e0921063cc309f4672a6afcb528 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 25 Oct 2012 09:28:04 +0000 Subject: Btrfs: make delalloc inodes be flushed by multi-task This patch introduce a new worker pool named "flush_workers", and if we want to force all the inode with pending delalloc to the disks, we can queue those inodes into the work queue of the worker pool, in this way, those inodes will be flushed by multi-task. Signed-off-by: Miao Xie Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 8fd9fe4..cad1656 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1333,6 +1333,7 @@ struct btrfs_fs_info { struct btrfs_workers generic_worker; struct btrfs_workers workers; struct btrfs_workers delalloc_workers; + struct btrfs_workers flush_workers; struct btrfs_workers endio_workers; struct btrfs_workers endio_meta_workers; struct btrfs_workers endio_meta_write_workers; @@ -3277,6 +3278,19 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans, int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, struct list_head *list, int search_commit); /* inode.c */ +struct btrfs_delalloc_work { + struct inode *inode; + int wait; + int delay_iput; + struct completion completion; + struct list_head list; + struct btrfs_work work; +}; + +struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode, + int wait, int delay_iput); +void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work); + struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page, size_t pg_offset, u64 start, u64 len, int create); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 7cda519..bd70c28 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2279,6 +2279,10 @@ int open_ctree(struct super_block *sb, fs_info->thread_pool_size, &fs_info->generic_worker); + btrfs_init_workers(&fs_info->flush_workers, "flush_delalloc", + fs_info->thread_pool_size, + &fs_info->generic_worker); + btrfs_init_workers(&fs_info->submit_workers, "submit", min_t(u64, fs_devices->num_devices, fs_info->thread_pool_size), @@ -2350,6 +2354,7 @@ int open_ctree(struct super_block *sb, ret |= btrfs_start_workers(&fs_info->delayed_workers); ret |= btrfs_start_workers(&fs_info->caching_workers); ret |= btrfs_start_workers(&fs_info->readahead_workers); + ret |= btrfs_start_workers(&fs_info->flush_workers); if (ret) { err = -ENOMEM; goto fail_sb_buffer; @@ -2667,6 +2672,7 @@ fail_sb_buffer: btrfs_stop_workers(&fs_info->submit_workers); btrfs_stop_workers(&fs_info->delayed_workers); btrfs_stop_workers(&fs_info->caching_workers); + btrfs_stop_workers(&fs_info->flush_workers); fail_alloc: fail_iput: btrfs_mapping_tree_free(&fs_info->mapping_tree); @@ -3339,6 +3345,7 @@ int close_ctree(struct btrfs_root *root) btrfs_stop_workers(&fs_info->delayed_workers); btrfs_stop_workers(&fs_info->caching_workers); btrfs_stop_workers(&fs_info->readahead_workers); + btrfs_stop_workers(&fs_info->flush_workers); #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY if (btrfs_test_opt(root, CHECK_INTEGRITY)) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index db3dd4e..dce9e21 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -71,6 +71,7 @@ static const struct file_operations btrfs_dir_file_operations; static struct extent_io_ops btrfs_extent_io_ops; static struct kmem_cache *btrfs_inode_cachep; +static struct kmem_cache *btrfs_delalloc_work_cachep; struct kmem_cache *btrfs_trans_handle_cachep; struct kmem_cache *btrfs_transaction_cachep; struct kmem_cache *btrfs_path_cachep; @@ -7204,6 +7205,8 @@ void btrfs_destroy_cachep(void) kmem_cache_destroy(btrfs_path_cachep); if (btrfs_free_space_cachep) kmem_cache_destroy(btrfs_free_space_cachep); + if (btrfs_delalloc_work_cachep) + kmem_cache_destroy(btrfs_delalloc_work_cachep); } int btrfs_init_cachep(void) @@ -7238,6 +7241,13 @@ int btrfs_init_cachep(void) if (!btrfs_free_space_cachep) goto fail; + btrfs_delalloc_work_cachep = kmem_cache_create("btrfs_delalloc_work", + sizeof(struct btrfs_delalloc_work), 0, + SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, + NULL); + if (!btrfs_delalloc_work_cachep) + goto fail; + return 0; fail: btrfs_destroy_cachep(); @@ -7448,6 +7458,49 @@ out_notrans: return ret; } +static void btrfs_run_delalloc_work(struct btrfs_work *work) +{ + struct btrfs_delalloc_work *delalloc_work; + + delalloc_work = container_of(work, struct btrfs_delalloc_work, + work); + if (delalloc_work->wait) + btrfs_wait_ordered_range(delalloc_work->inode, 0, (u64)-1); + else + filemap_flush(delalloc_work->inode->i_mapping); + + if (delalloc_work->delay_iput) + btrfs_add_delayed_iput(delalloc_work->inode); + else + iput(delalloc_work->inode); + complete(&delalloc_work->completion); +} + +struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode, + int wait, int delay_iput) +{ + struct btrfs_delalloc_work *work; + + work = kmem_cache_zalloc(btrfs_delalloc_work_cachep, GFP_NOFS); + if (!work) + return NULL; + + init_completion(&work->completion); + INIT_LIST_HEAD(&work->list); + work->inode = inode; + work->wait = wait; + work->delay_iput = delay_iput; + work->work.func = btrfs_run_delalloc_work; + + return work; +} + +void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work) +{ + wait_for_completion(&work->completion); + kmem_cache_free(btrfs_delalloc_work_cachep, work); +} + /* * some fairly slow code that needs optimization. This walks the list * of all the inodes with pending delalloc and forces them to disk. @@ -7457,10 +7510,15 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) struct list_head *head = &root->fs_info->delalloc_inodes; struct btrfs_inode *binode; struct inode *inode; + struct btrfs_delalloc_work *work, *next; + struct list_head works; + int ret = 0; if (root->fs_info->sb->s_flags & MS_RDONLY) return -EROFS; + INIT_LIST_HEAD(&works); + spin_lock(&root->fs_info->delalloc_lock); while (!list_empty(head)) { binode = list_entry(head->next, struct btrfs_inode, @@ -7470,11 +7528,14 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) list_del_init(&binode->delalloc_inodes); spin_unlock(&root->fs_info->delalloc_lock); if (inode) { - filemap_flush(inode->i_mapping); - if (delay_iput) - btrfs_add_delayed_iput(inode); - else - iput(inode); + work = btrfs_alloc_delalloc_work(inode, 0, delay_iput); + if (!work) { + ret = -ENOMEM; + goto out; + } + list_add_tail(&work->list, &works); + btrfs_queue_worker(&root->fs_info->flush_workers, + &work->work); } cond_resched(); spin_lock(&root->fs_info->delalloc_lock); @@ -7493,7 +7554,12 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) atomic_read(&root->fs_info->async_delalloc_pages) == 0)); } atomic_dec(&root->fs_info->async_submit_draining); - return 0; +out: + list_for_each_entry_safe(work, next, &works, list) { + list_del_init(&work->list); + btrfs_wait_and_free_delalloc_work(work); + } + return ret; } static int btrfs_symlink(struct inode *dir, struct dentry *dentry, diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 242d6de..270f24f 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -4061,7 +4061,11 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) (unsigned long long)rc->block_group->key.objectid, (unsigned long long)rc->block_group->flags); - btrfs_start_delalloc_inodes(fs_info->tree_root, 0); + ret = btrfs_start_delalloc_inodes(fs_info->tree_root, 0); + if (ret < 0) { + err = ret; + goto out; + } btrfs_wait_ordered_extents(fs_info->tree_root, 0); while (1) { diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 4e1def4..9c466f9 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1497,7 +1497,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, WARN_ON(cur_trans != trans->transaction); if (flush_on_commit || snap_pending) { - btrfs_start_delalloc_inodes(root, 1); + ret = btrfs_start_delalloc_inodes(root, 1); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + goto cleanup_transaction; + } btrfs_wait_ordered_extents(root, 1); } -- cgit v0.10.2 From 25287e0a16c0ad068aa89ab01aea6c699b31ec12 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 25 Oct 2012 09:31:03 +0000 Subject: Btrfs: make ordered operations be handled by multi-task The process of the ordered operations is similar to the delalloc inode flush, so we handle them by flush workers. Signed-off-by: Miao Xie Signed-off-by: Chris Mason diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 7772f02..ab2a3c0 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -519,13 +519,17 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput) * extra check to make sure the ordered operation list really is empty * before we return */ -void btrfs_run_ordered_operations(struct btrfs_root *root, int wait) +int btrfs_run_ordered_operations(struct btrfs_root *root, int wait) { struct btrfs_inode *btrfs_inode; struct inode *inode; struct list_head splice; + struct list_head works; + struct btrfs_delalloc_work *work, *next; + int ret = 0; INIT_LIST_HEAD(&splice); + INIT_LIST_HEAD(&works); mutex_lock(&root->fs_info->ordered_operations_mutex); spin_lock(&root->fs_info->ordered_extent_lock); @@ -533,6 +537,7 @@ again: list_splice_init(&root->fs_info->ordered_operations, &splice); while (!list_empty(&splice)) { + btrfs_inode = list_entry(splice.next, struct btrfs_inode, ordered_operations); @@ -549,15 +554,26 @@ again: list_add_tail(&BTRFS_I(inode)->ordered_operations, &root->fs_info->ordered_operations); } + + if (!inode) + continue; spin_unlock(&root->fs_info->ordered_extent_lock); - if (inode) { - if (wait) - btrfs_wait_ordered_range(inode, 0, (u64)-1); - else - filemap_flush(inode->i_mapping); - btrfs_add_delayed_iput(inode); + work = btrfs_alloc_delalloc_work(inode, wait, 1); + if (!work) { + if (list_empty(&BTRFS_I(inode)->ordered_operations)) + list_add_tail(&btrfs_inode->ordered_operations, + &splice); + spin_lock(&root->fs_info->ordered_extent_lock); + list_splice_tail(&splice, + &root->fs_info->ordered_operations); + spin_unlock(&root->fs_info->ordered_extent_lock); + ret = -ENOMEM; + goto out; } + list_add_tail(&work->list, &works); + btrfs_queue_worker(&root->fs_info->flush_workers, + &work->work); cond_resched(); spin_lock(&root->fs_info->ordered_extent_lock); @@ -566,7 +582,13 @@ again: goto again; spin_unlock(&root->fs_info->ordered_extent_lock); +out: + list_for_each_entry_safe(work, next, &works, list) { + list_del_init(&work->list); + btrfs_wait_and_free_delalloc_work(work); + } mutex_unlock(&root->fs_info->ordered_operations_mutex); + return ret; } /* @@ -934,15 +956,6 @@ void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans, if (last_mod < root->fs_info->last_trans_committed) return; - /* - * the transaction is already committing. Just start the IO and - * don't bother with all of this list nonsense - */ - if (trans && root->fs_info->running_transaction->blocked) { - btrfs_wait_ordered_range(inode, 0, (u64)-1); - return; - } - spin_lock(&root->fs_info->ordered_extent_lock); if (list_empty(&BTRFS_I(inode)->ordered_operations)) { list_add_tail(&BTRFS_I(inode)->ordered_operations, @@ -959,6 +972,7 @@ int __init ordered_data_init(void) NULL); if (!btrfs_ordered_extent_cache) return -ENOMEM; + return 0; } diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index dd27a0b..e8dcec6 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -186,7 +186,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode, int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, struct btrfs_ordered_extent *ordered); int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum); -void btrfs_run_ordered_operations(struct btrfs_root *root, int wait); +int btrfs_run_ordered_operations(struct btrfs_root *root, int wait); void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct inode *inode); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 9c466f9..259f74e 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1412,15 +1412,21 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_transaction *cur_trans = trans->transaction; struct btrfs_transaction *prev_trans = NULL; DEFINE_WAIT(wait); - int ret = -EIO; + int ret; int should_grow = 0; unsigned long now = get_seconds(); int flush_on_commit = btrfs_test_opt(root, FLUSHONCOMMIT); - btrfs_run_ordered_operations(root, 0); + ret = btrfs_run_ordered_operations(root, 0); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + goto cleanup_transaction; + } - if (cur_trans->aborted) + if (cur_trans->aborted) { + ret = cur_trans->aborted; goto cleanup_transaction; + } /* make a pass through all the delayed refs we have so far * any runnings procs may add more while we are here @@ -1523,7 +1529,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, * it here and no for sure that nothing new will be added * to the list */ - btrfs_run_ordered_operations(root, 1); + ret = btrfs_run_ordered_operations(root, 1); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + goto cleanup_transaction; + } prepare_to_wait(&cur_trans->writer_wait, &wait, TASK_UNINTERRUPTIBLE); -- cgit v0.10.2 From 9afab8820bb8b55af669b199597d6716e04d1ba8 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 25 Oct 2012 09:41:36 +0000 Subject: Btrfs: make ordered extent be flushed by multi-task Though the process of the ordered extents is a bit different with the delalloc inode flush, but we can see it as a subset of the delalloc inode flush, so we also handle them by flush workers. Signed-off-by: Miao Xie Signed-off-by: Chris Mason diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index ab2a3c0..eecc20f 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -211,6 +211,8 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, init_waitqueue_head(&entry->wait); INIT_LIST_HEAD(&entry->list); INIT_LIST_HEAD(&entry->root_extent_list); + INIT_LIST_HEAD(&entry->work_list); + init_completion(&entry->completion); trace_btrfs_ordered_extent_add(inode, entry); @@ -464,18 +466,28 @@ void btrfs_remove_ordered_extent(struct inode *inode, wake_up(&entry->wait); } +static void btrfs_run_ordered_extent_work(struct btrfs_work *work) +{ + struct btrfs_ordered_extent *ordered; + + ordered = container_of(work, struct btrfs_ordered_extent, flush_work); + btrfs_start_ordered_extent(ordered->inode, ordered, 1); + complete(&ordered->completion); +} + /* * wait for all the ordered extents in a root. This is done when balancing * space between drives. */ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput) { - struct list_head splice; + struct list_head splice, works; struct list_head *cur; - struct btrfs_ordered_extent *ordered; + struct btrfs_ordered_extent *ordered, *next; struct inode *inode; INIT_LIST_HEAD(&splice); + INIT_LIST_HEAD(&works); spin_lock(&root->fs_info->ordered_extent_lock); list_splice_init(&root->fs_info->ordered_extents, &splice); @@ -494,19 +506,32 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput) spin_unlock(&root->fs_info->ordered_extent_lock); if (inode) { - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - if (delay_iput) - btrfs_add_delayed_iput(inode); - else - iput(inode); + ordered->flush_work.func = btrfs_run_ordered_extent_work; + list_add_tail(&ordered->work_list, &works); + btrfs_queue_worker(&root->fs_info->flush_workers, + &ordered->flush_work); } else { btrfs_put_ordered_extent(ordered); } + cond_resched(); spin_lock(&root->fs_info->ordered_extent_lock); } spin_unlock(&root->fs_info->ordered_extent_lock); + + list_for_each_entry_safe(ordered, next, &works, work_list) { + list_del_init(&ordered->work_list); + wait_for_completion(&ordered->completion); + + inode = ordered->inode; + btrfs_put_ordered_extent(ordered); + if (delay_iput) + btrfs_add_delayed_iput(inode); + else + iput(inode); + + cond_resched(); + } } /* diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index e8dcec6..efc7c29 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -128,8 +128,11 @@ struct btrfs_ordered_extent { struct list_head root_extent_list; struct btrfs_work work; -}; + struct completion completion; + struct btrfs_work flush_work; + struct list_head work_list; +}; /* * calculates the total size you need to allocate for an ordered sum -- cgit v0.10.2 From e2a29943e9a2ee2aa737a77f550f46ba72269db4 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Tue, 14 Jun 2011 17:29:51 +0200 Subject: fsnotify: pass group to fsnotify_destroy_mark() In fsnotify_destroy_mark() dont get the group from the passed mark anymore, but pass the group itself as an additional parameter to the function. Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index 3344bdd..08b886f 100644 --- a/fs/notify/dnotify/dnotify.c +++ b/fs/notify/dnotify/dnotify.c @@ -201,7 +201,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id) /* nothing else could have found us thanks to the dnotify_mark_mutex */ if (dn_mark->dn == NULL) - fsnotify_destroy_mark(fsn_mark); + fsnotify_destroy_mark(fsn_mark, dnotify_group); mutex_unlock(&dnotify_mark_mutex); @@ -385,7 +385,7 @@ out: spin_unlock(&fsn_mark->lock); if (destroy) - fsnotify_destroy_mark(fsn_mark); + fsnotify_destroy_mark(fsn_mark, dnotify_group); mutex_unlock(&dnotify_mark_mutex); fsnotify_put_mark(fsn_mark); diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 599a019..1218d10 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -546,7 +546,7 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, &destroy_mark); if (destroy_mark) - fsnotify_destroy_mark(fsn_mark); + fsnotify_destroy_mark(fsn_mark, group); fsnotify_put_mark(fsn_mark); if (removed & real_mount(mnt)->mnt_fsnotify_mask) @@ -570,7 +570,7 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, &destroy_mark); if (destroy_mark) - fsnotify_destroy_mark(fsn_mark); + fsnotify_destroy_mark(fsn_mark, group); /* matches the fsnotify_find_inode_mark() */ fsnotify_put_mark(fsn_mark); if (removed & inode->i_fsnotify_mask) diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index 4e9071e..2123020 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c @@ -99,8 +99,16 @@ void fsnotify_clear_marks_by_inode(struct inode *inode) spin_unlock(&inode->i_lock); list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) { - fsnotify_destroy_mark(mark); + struct fsnotify_group *group; + + spin_lock(&mark->lock); + fsnotify_get_group(mark->group); + group = mark->group; + spin_unlock(&mark->lock); + + fsnotify_destroy_mark(mark, group); fsnotify_put_mark(mark); + fsnotify_put_group(group); } } diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 74977fb..871569c 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c @@ -132,7 +132,7 @@ static int inotify_handle_event(struct fsnotify_group *group, } if (inode_mark->mask & IN_ONESHOT) - fsnotify_destroy_mark(inode_mark); + fsnotify_destroy_mark(inode_mark, group); return ret; } diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 246250f..00ff82f 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -816,7 +816,7 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) ret = 0; - fsnotify_destroy_mark(&i_mark->fsn_mark); + fsnotify_destroy_mark(&i_mark->fsn_mark, group); /* match ref taken by inotify_idr_find */ fsnotify_put_mark(&i_mark->fsn_mark); diff --git a/fs/notify/mark.c b/fs/notify/mark.c index ab25b81..b77c833 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -121,21 +121,11 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) * The caller had better be holding a reference to this mark so we don't actually * do the final put under the mark->lock */ -void fsnotify_destroy_mark(struct fsnotify_mark *mark) +void fsnotify_destroy_mark(struct fsnotify_mark *mark, + struct fsnotify_group *group) { - struct fsnotify_group *group; struct inode *inode = NULL; - spin_lock(&mark->lock); - /* dont get the group from a mark that is not alive yet */ - if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { - spin_unlock(&mark->lock); - return; - } - fsnotify_get_group(mark->group); - group = mark->group; - spin_unlock(&mark->lock); - mutex_lock(&group->mark_mutex); spin_lock(&mark->lock); @@ -143,7 +133,7 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { spin_unlock(&mark->lock); mutex_unlock(&group->mark_mutex); - goto put_group; + return; } mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; @@ -194,9 +184,6 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) */ atomic_dec(&group->num_marks); - -put_group: - fsnotify_put_group(group); } void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) @@ -307,7 +294,7 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, mutex_unlock(&group->mark_mutex); list_for_each_entry_safe(mark, lmark, &free_list, free_g_list) { - fsnotify_destroy_mark(mark); + fsnotify_destroy_mark(mark, group); fsnotify_put_mark(mark); } } diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index f26a348..4df58b8 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c @@ -46,8 +46,16 @@ void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) spin_unlock(&mnt->mnt_root->d_lock); list_for_each_entry_safe(mark, lmark, &free_list, m.free_m_list) { - fsnotify_destroy_mark(mark); + struct fsnotify_group *group; + + spin_lock(&mark->lock); + fsnotify_get_group(mark->group); + group = mark->group; + spin_unlock(&mark->lock); + + fsnotify_destroy_mark(mark, group); fsnotify_put_mark(mark); + fsnotify_put_group(group); } } diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index c584834..140b4b8 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -408,8 +408,9 @@ extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask /* attach the mark to both the group and the inode */ extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, struct inode *inode, struct vfsmount *mnt, int allow_dups); -/* given a mark, flag it to be freed when all references are dropped */ -extern void fsnotify_destroy_mark(struct fsnotify_mark *mark); +/* given a group and a mark, flag mark to be freed when all references are dropped */ +extern void fsnotify_destroy_mark(struct fsnotify_mark *mark, + struct fsnotify_group *group); /* run all the marks in a group, and clear all of the vfsmount marks */ extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group); /* run all the marks in a group, and clear all of the inode marks */ diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index ed206fd..e81175e 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -249,7 +249,7 @@ static void untag_chunk(struct node *p) list_del_rcu(&chunk->hash); spin_unlock(&hash_lock); spin_unlock(&entry->lock); - fsnotify_destroy_mark(entry); + fsnotify_destroy_mark(entry, audit_tree_group); goto out; } @@ -291,7 +291,7 @@ static void untag_chunk(struct node *p) owner->root = new; spin_unlock(&hash_lock); spin_unlock(&entry->lock); - fsnotify_destroy_mark(entry); + fsnotify_destroy_mark(entry, audit_tree_group); fsnotify_put_mark(&new->mark); /* drop initial reference */ goto out; @@ -331,7 +331,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree) spin_unlock(&hash_lock); chunk->dead = 1; spin_unlock(&entry->lock); - fsnotify_destroy_mark(entry); + fsnotify_destroy_mark(entry, audit_tree_group); fsnotify_put_mark(entry); return 0; } @@ -412,7 +412,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) spin_unlock(&chunk_entry->lock); spin_unlock(&old_entry->lock); - fsnotify_destroy_mark(chunk_entry); + fsnotify_destroy_mark(chunk_entry, audit_tree_group); fsnotify_put_mark(chunk_entry); fsnotify_put_mark(old_entry); @@ -443,7 +443,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) spin_unlock(&hash_lock); spin_unlock(&chunk_entry->lock); spin_unlock(&old_entry->lock); - fsnotify_destroy_mark(old_entry); + fsnotify_destroy_mark(old_entry, audit_tree_group); fsnotify_put_mark(chunk_entry); /* drop initial reference */ fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */ return 0; diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 3823281..a66affc 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -349,7 +349,7 @@ static void audit_remove_parent_watches(struct audit_parent *parent) } mutex_unlock(&audit_filter_mutex); - fsnotify_destroy_mark(&parent->mark); + fsnotify_destroy_mark(&parent->mark, audit_watch_group); } /* Get path information necessary for adding watches. */ @@ -456,7 +456,7 @@ void audit_remove_watch_rule(struct audit_krule *krule) if (list_empty(&parent->watches)) { audit_get_parent(parent); - fsnotify_destroy_mark(&parent->mark); + fsnotify_destroy_mark(&parent->mark, audit_watch_group); audit_put_parent(parent); } } -- cgit v0.10.2 From d5a335b845792d2a69ed1e244c0b233117b7db3c Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Tue, 14 Jun 2011 17:29:52 +0200 Subject: fsnotify: introduce locked versions of fsnotify_add_mark() and fsnotify_remove_mark() This patch introduces fsnotify_add_mark_locked() and fsnotify_remove_mark_locked() which are essentially the same as fsnotify_add_mark() and fsnotify_remove_mark() but assume that the caller has already taken the groups mark mutex. Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/mark.c b/fs/notify/mark.c index b77c833..f9dda03 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -121,18 +121,18 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) * The caller had better be holding a reference to this mark so we don't actually * do the final put under the mark->lock */ -void fsnotify_destroy_mark(struct fsnotify_mark *mark, - struct fsnotify_group *group) +void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, + struct fsnotify_group *group) { struct inode *inode = NULL; - mutex_lock(&group->mark_mutex); + BUG_ON(!mutex_is_locked(&group->mark_mutex)); + spin_lock(&mark->lock); /* something else already called this function on this mark */ if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { spin_unlock(&mark->lock); - mutex_unlock(&group->mark_mutex); return; } @@ -149,6 +149,8 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark, list_del_init(&mark->g_list); spin_unlock(&mark->lock); + + /* release lock temporarily */ mutex_unlock(&group->mark_mutex); spin_lock(&destroy_lock); @@ -184,6 +186,16 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark, */ atomic_dec(&group->num_marks); + + mutex_lock(&group->mark_mutex); +} + +void fsnotify_destroy_mark(struct fsnotify_mark *mark, + struct fsnotify_group *group) +{ + mutex_lock(&group->mark_mutex); + fsnotify_destroy_mark_locked(mark, group); + mutex_unlock(&group->mark_mutex); } void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) @@ -208,14 +220,15 @@ void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mas * These marks may be used for the fsnotify backend to determine which * event types should be delivered to which group. */ -int fsnotify_add_mark(struct fsnotify_mark *mark, - struct fsnotify_group *group, struct inode *inode, - struct vfsmount *mnt, int allow_dups) +int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + struct fsnotify_group *group, struct inode *inode, + struct vfsmount *mnt, int allow_dups) { int ret = 0; BUG_ON(inode && mnt); BUG_ON(!inode && !mnt); + BUG_ON(!mutex_is_locked(&group->mark_mutex)); /* * LOCKING ORDER!!!! @@ -223,8 +236,6 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, * mark->lock * inode->i_lock */ - mutex_lock(&group->mark_mutex); - spin_lock(&mark->lock); mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; @@ -250,8 +261,6 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_set_mark_mask_locked(mark, mark->mask); spin_unlock(&mark->lock); - mutex_unlock(&group->mark_mutex); - if (inode) __fsnotify_update_child_dentry_flags(inode); @@ -264,7 +273,6 @@ err: atomic_dec(&group->num_marks); spin_unlock(&mark->lock); - mutex_unlock(&group->mark_mutex); spin_lock(&destroy_lock); list_add(&mark->destroy_list, &destroy_list); @@ -274,6 +282,16 @@ err: return ret; } +int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, + struct inode *inode, struct vfsmount *mnt, int allow_dups) +{ + int ret; + mutex_lock(&group->mark_mutex); + ret = fsnotify_add_mark_locked(mark, group, inode, mnt, allow_dups); + mutex_unlock(&group->mark_mutex); + return ret; +} + /* * clear any marks in a group in which mark->flags & flags is true */ diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 140b4b8..26c06af 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -408,9 +408,13 @@ extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask /* attach the mark to both the group and the inode */ extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, struct inode *inode, struct vfsmount *mnt, int allow_dups); +extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct fsnotify_group *group, + struct inode *inode, struct vfsmount *mnt, int allow_dups); /* given a group and a mark, flag mark to be freed when all references are dropped */ extern void fsnotify_destroy_mark(struct fsnotify_mark *mark, struct fsnotify_group *group); +extern void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, + struct fsnotify_group *group); /* run all the marks in a group, and clear all of the vfsmount marks */ extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group); /* run all the marks in a group, and clear all of the inode marks */ -- cgit v0.10.2 From 64c20d2a20fce295c260ea6cb3b468edfa2fb07b Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Tue, 14 Jun 2011 17:29:53 +0200 Subject: fsnotify: dont put marks on temporary list when clearing marks by group In clear_marks_by_group_flags() the mark list of a group is iterated and the marks are put on a temporary list. Since we introduced fsnotify_destroy_mark_locked() we dont need the temp list any more and are able to remove the marks while the mark list is iterated and the mark list mutex is held. Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/mark.c b/fs/notify/mark.c index f9dda03..0e93d90 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -299,22 +299,16 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags) { struct fsnotify_mark *lmark, *mark; - LIST_HEAD(free_list); mutex_lock(&group->mark_mutex); list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { if (mark->flags & flags) { - list_add(&mark->free_g_list, &free_list); - list_del_init(&mark->g_list); fsnotify_get_mark(mark); + fsnotify_destroy_mark_locked(mark, group); + fsnotify_put_mark(mark); } } mutex_unlock(&group->mark_mutex); - - list_for_each_entry_safe(mark, lmark, &free_list, free_g_list) { - fsnotify_destroy_mark(mark, group); - fsnotify_put_mark(mark); - } } /* diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 26c06af..5a88993 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -287,7 +287,6 @@ struct fsnotify_mark { struct fsnotify_inode_mark i; struct fsnotify_vfsmount_mark m; }; - struct list_head free_g_list; /* tmp list used when freeing this mark */ __u32 ignored_mask; /* events types to ignore */ #define FSNOTIFY_MARK_FLAG_INODE 0x01 #define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 -- cgit v0.10.2 From 6960b0d909cde5bdff49e4e5c1250edd10be7ebd Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Fri, 12 Aug 2011 01:13:31 +0200 Subject: fsnotify: change locking order On Mon, Aug 01, 2011 at 04:38:22PM -0400, Eric Paris wrote: > > I finally built and tested a v3.0 kernel with these patches (I know I'm > SOOOOOO far behind). Not what I hoped for: > > > [ 150.937798] VFS: Busy inodes after unmount of tmpfs. Self-destruct in 5 seconds. Have a nice day... > > [ 150.945290] BUG: unable to handle kernel NULL pointer dereference at 0000000000000070 > > [ 150.946012] IP: [] shmem_free_inode+0x18/0x50 > > [ 150.946012] PGD 2bf9e067 PUD 2bf9f067 PMD 0 > > [ 150.946012] Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC > > [ 150.946012] CPU 0 > > [ 150.946012] Modules linked in: nfs lockd fscache auth_rpcgss nfs_acl sunrpc ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_filter ip6_tables ext4 jbd2 crc16 joydev ata_piix i2c_piix4 pcspkr uinput ipv6 autofs4 usbhid [last unloaded: scsi_wait_scan] > > [ 150.946012] > > [ 150.946012] Pid: 2764, comm: syscall_thrash Not tainted 3.0.0+ #1 Red Hat KVM > > [ 150.946012] RIP: 0010:[] [] shmem_free_inode+0x18/0x50 > > [ 150.946012] RSP: 0018:ffff88002c2e5df8 EFLAGS: 00010282 > > [ 150.946012] RAX: 000000004e370d9f RBX: 0000000000000000 RCX: ffff88003a029438 > > [ 150.946012] RDX: 0000000033630a5f RSI: 0000000000000000 RDI: ffff88003491c240 > > [ 150.946012] RBP: ffff88002c2e5e08 R08: 0000000000000000 R09: 0000000000000000 > > [ 150.946012] R10: 0000000000000000 R11: 0000000000000000 R12: ffff88003a029428 > > [ 150.946012] R13: ffff88003a029428 R14: ffff88003a029428 R15: ffff88003499a610 > > [ 150.946012] FS: 00007f5a05420700(0000) GS:ffff88003f600000(0000) knlGS:0000000000000000 > > [ 150.946012] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b > > [ 150.946012] CR2: 0000000000000070 CR3: 000000002a662000 CR4: 00000000000006f0 > > [ 150.946012] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 > > [ 150.946012] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 > > [ 150.946012] Process syscall_thrash (pid: 2764, threadinfo ffff88002c2e4000, task ffff88002bfbc760) > > [ 150.946012] Stack: > > [ 150.946012] ffff88003a029438 ffff88003a029428 ffff88002c2e5e38 ffffffff81102f76 > > [ 150.946012] ffff88003a029438 ffff88003a029598 ffffffff8160f9c0 ffff88002c221250 > > [ 150.946012] ffff88002c2e5e68 ffffffff8115e9be ffff88002c2e5e68 ffff88003a029438 > > [ 150.946012] Call Trace: > > [ 150.946012] [] shmem_evict_inode+0x76/0x130 > > [ 150.946012] [] evict+0x7e/0x170 > > [ 150.946012] [] iput_final+0xd0/0x190 > > [ 150.946012] [] iput+0x33/0x40 > > [ 150.946012] [] fsnotify_destroy_mark_locked+0x145/0x160 > > [ 150.946012] [] fsnotify_destroy_mark+0x36/0x50 > > [ 150.946012] [] sys_inotify_rm_watch+0x77/0xd0 > > [ 150.946012] [] system_call_fastpath+0x16/0x1b > > [ 150.946012] Code: 67 4a 00 b8 e4 ff ff ff eb aa 66 0f 1f 84 00 00 00 00 00 55 48 89 e5 48 83 ec 10 48 89 1c 24 4c 89 64 24 08 48 8b 9f 40 05 00 00 > > [ 150.946012] 83 7b 70 00 74 1c 4c 8d a3 80 00 00 00 4c 89 e7 e8 d2 5d 4a > > [ 150.946012] RIP [] shmem_free_inode+0x18/0x50 > > [ 150.946012] RSP > > [ 150.946012] CR2: 0000000000000070 > > Looks at aweful lot like the problem from: > http://www.spinics.net/lists/linux-fsdevel/msg46101.html > I tried to reproduce this bug with your test program, but without success. However, if I understand correctly, this occurs since we dont hold any locks when we call iput() in mark_destroy(), right? With the patches you tested, iput() is also not called within any lock, since the groups mark_mutex is released temporarily before iput() is called. This is, since the original codes behaviour is similar. However since we now have a mutex as the biggest lock, we can do what you suggested (http://www.spinics.net/lists/linux-fsdevel/msg46107.html) and call iput() with the mutex held to avoid the race. The patch below implements this. It uses nested locking to avoid deadlock in case we do the final iput() on an inode which still holds marks and thus would take the mutex again when calling fsnotify_inode_delete() in destroy_inode(). Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 0e93d90..fc6b49b 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -150,6 +150,8 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, spin_unlock(&mark->lock); + if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) + iput(inode); /* release lock temporarily */ mutex_unlock(&group->mark_mutex); @@ -157,6 +159,11 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, list_add(&mark->destroy_list, &destroy_list); spin_unlock(&destroy_lock); wake_up(&destroy_waitq); + /* + * We don't necessarily have a ref on mark from caller so the above destroy + * may have actually freed it, unless this group provides a 'freeing_mark' + * function which must be holding a reference. + */ /* * Some groups like to know that marks are being freed. This is a @@ -178,22 +185,15 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, * is just a lazy update (and could be a perf win...) */ - if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) - iput(inode); - /* - * We don't necessarily have a ref on mark from caller so the above iput - * may have already destroyed it. Don't touch from now on. - */ - atomic_dec(&group->num_marks); - mutex_lock(&group->mark_mutex); + mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); } void fsnotify_destroy_mark(struct fsnotify_mark *mark, struct fsnotify_group *group) { - mutex_lock(&group->mark_mutex); + mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); fsnotify_destroy_mark_locked(mark, group); mutex_unlock(&group->mark_mutex); } @@ -300,7 +300,7 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, { struct fsnotify_mark *lmark, *mark; - mutex_lock(&group->mark_mutex); + mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { if (mark->flags & flags) { fsnotify_get_mark(mark); diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 5a88993..1af2f6a 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -88,9 +88,10 @@ struct fsnotify_event_private_data; * if the group is interested in this event. * handle_event - main call for a group to handle an fs event * free_group_priv - called when a group refcnt hits 0 to clean up the private union - * freeing-mark - this means that a mark has been flagged to die when everything - * finishes using it. The function is supplied with what must be a - * valid group and inode to use to clean up. + * freeing_mark - called when a mark is being destroyed for some reason. The group + * MUST be holding a reference on each mark and that reference must be + * dropped in this function. inotify uses this function to send + * userspace messages that marks have been removed. */ struct fsnotify_ops { bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, -- cgit v0.10.2 From 0a6b6bd5919a65030b557ec8fe81f6fb3e93744a Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 14 Oct 2011 17:43:39 -0400 Subject: fsnotify: make fasync generic for both inotify and fanotify inotify is supposed to support async signal notification when information is available on the inotify fd. This patch moves that support to generic fsnotify functions so it can be used by all notification mechanisms. Signed-off-by: Eric Paris diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 1218d10..f0e7a57 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -414,6 +414,10 @@ static int fanotify_release(struct inode *ignored, struct file *file) wake_up(&group->fanotify_data.access_waitq); #endif + + if (file->f_flags & FASYNC) + fsnotify_fasync(-1, file, 0); + /* matches the fanotify_init->fsnotify_alloc_group */ fsnotify_destroy_group(group); diff --git a/fs/notify/group.c b/fs/notify/group.c index 1f73057..bd2625b 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c @@ -102,3 +102,10 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) return group; } + +int fsnotify_fasync(int fd, struct file *file, int on) +{ + struct fsnotify_group *group = file->private_data; + + return fasync_helper(fd, file, on, &group->fsn_fa) >= 0 ? 0 : -EIO; +} diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 00ff82f..68f7bec 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -280,19 +280,15 @@ static ssize_t inotify_read(struct file *file, char __user *buf, return ret; } -static int inotify_fasync(int fd, struct file *file, int on) -{ - struct fsnotify_group *group = file->private_data; - - return fasync_helper(fd, file, on, &group->inotify_data.fa) >= 0 ? 0 : -EIO; -} - static int inotify_release(struct inode *ignored, struct file *file) { struct fsnotify_group *group = file->private_data; pr_debug("%s: group=%p\n", __func__, group); + if (file->f_flags & FASYNC) + fsnotify_fasync(-1, file, 0); + /* free this group, matching get was inotify_init->fsnotify_obtain_group */ fsnotify_destroy_group(group); @@ -335,7 +331,7 @@ static long inotify_ioctl(struct file *file, unsigned int cmd, static const struct file_operations inotify_fops = { .poll = inotify_poll, .read = inotify_read, - .fasync = inotify_fasync, + .fasync = fsnotify_fasync, .release = inotify_release, .unlocked_ioctl = inotify_ioctl, .compat_ioctl = inotify_ioctl, @@ -706,7 +702,6 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events) spin_lock_init(&group->inotify_data.idr_lock); idr_init(&group->inotify_data.idr); group->inotify_data.last_wd = 0; - group->inotify_data.fa = NULL; group->inotify_data.user = get_current_user(); if (atomic_inc_return(&group->inotify_data.user->inotify_devs) > diff --git a/fs/notify/notification.c b/fs/notify/notification.c index c887b13..b3963d8 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c @@ -225,6 +225,7 @@ alloc_holder: mutex_unlock(&group->notification_mutex); wake_up(&group->notification_waitq); + kill_fasync(&group->fsn_fa, SIGIO, POLL_IN); return return_event; } diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 1af2f6a..d5b0910 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -148,6 +148,8 @@ struct fsnotify_group { * a group */ struct list_head marks_list; /* all inode marks for this group */ + struct fasync_struct *fsn_fa; /* async notification */ + /* groups can define private fields here or use the void *private */ union { void *private; @@ -156,7 +158,6 @@ struct fsnotify_group { spinlock_t idr_lock; struct idr idr; u32 last_wd; - struct fasync_struct *fa; /* async notification */ struct user_struct *user; } inotify_data; #endif @@ -368,6 +369,8 @@ extern void fsnotify_get_group(struct fsnotify_group *group); extern void fsnotify_put_group(struct fsnotify_group *group); /* destroy group */ extern void fsnotify_destroy_group(struct fsnotify_group *group); +/* fasync handler function */ +extern int fsnotify_fasync(int fd, struct file *file, int on); /* take a reference to an event */ extern void fsnotify_get_event(struct fsnotify_event *event); extern void fsnotify_put_event(struct fsnotify_event *event); -- cgit v0.10.2 From 03a1cec1f17ac1a6041996b3e40f96b5a2f90e1b Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Fri, 23 Mar 2012 02:42:23 +0100 Subject: fanotify: dont merge permission events Boyd Yang reported a problem for the case that multiple threads of the same thread group are waiting for a reponse for a permission event. In this case it is possible that some of the threads are never woken up, even if the response for the event has been received (see http://marc.info/?l=linux-kernel&m=131822913806350&w=2). The reason is that we are currently merging permission events if they belong to the same thread group. But we are not prepared to wake up more than one waiter for each event. We do wait_event(group->fanotify_data.access_waitq, event->response || atomic_read(&group->fanotify_data.bypass_perm)); and after that event->response = 0; which is the reason that even if we woke up all waiters for the same event some of them may see event->response being already set 0 again, then go back to sleep and block forever. With this patch we avoid that more than one thread is waiting for a response by not merging permission events for the same thread group any more. Reported-by: Boyd Yang Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index f35794b..aeb5b5a 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -18,6 +18,12 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new) old->tgid == new->tgid) { switch (old->data_type) { case (FSNOTIFY_EVENT_PATH): +#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS + /* dont merge two permission events */ + if ((old->mask & FAN_ALL_PERM_EVENTS) && + (new->mask & FAN_ALL_PERM_EVENTS)) + return false; +#endif if ((old->path.mnt == new->path.mnt) && (old->path.dentry == new->path.dentry)) return true; -- cgit v0.10.2 From 8b99c3ccf735a2294c7842d236caa42e543e2c95 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Sat, 24 Mar 2012 23:44:19 +0100 Subject: inotify: dont skip removal of watch descriptor if creation of ignored event failed In inotify_ignored_and_remove_idr() the removal of a watch descriptor is skipped if the allocation of an ignored event failed and we are leaking memory (the watch descriptor and the mark linked to it). This patch ensures that the watch descriptor is removed regardless of whether event creation failed or not. Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 68f7bec..a6879d1 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -513,13 +513,13 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, struct fsnotify_event_private_data *fsn_event_priv; int ret; + i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); + ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, FSNOTIFY_EVENT_NONE, NULL, 0, GFP_NOFS); if (!ignored_event) - return; - - i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); + goto skip_send_ignore; event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS); if (unlikely(!event_priv)) @@ -541,9 +541,9 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, } skip_send_ignore: - /* matches the reference taken when the event was created */ - fsnotify_put_event(ignored_event); + if (ignored_event) + fsnotify_put_event(ignored_event); /* remove this mark from the idr */ inotify_remove_from_idr(group, i_mark); -- cgit v0.10.2 From 1ca39ab9d21ac93f94b9e3eb364ea9a5cf2aba06 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 26 Mar 2012 13:07:59 -0400 Subject: inotify: automatically restart syscalls We were mistakenly returning EINTR when we found an outstanding signal. Instead we should returen ERESTARTSYS and allow the kernel to handle things the right way. Patch-from: Oleg Nesterov Signed-off-by: Eric Paris diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index a6879d1..463e828 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -264,7 +264,7 @@ static ssize_t inotify_read(struct file *file, char __user *buf, ret = -EAGAIN; if (file->f_flags & O_NONBLOCK) break; - ret = -EINTR; + ret = -ERESTARTSYS; if (signal_pending(current)) break; -- cgit v0.10.2 From ad68652412276f68ad4fe3e1ecf5ee6880876783 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 11 Dec 2012 22:18:05 +0100 Subject: x86, 8042: Enable A20 using KBC to fix S3 resume on some MSI laptops Some MSI laptop BIOSes are broken - INT 15h code uses port 92h to enable A20 line but resume code assumes that KBC was used. The laptop will not resume from S3 otherwise but powers off after a while and then powers on again stuck with a blank screen. Fix it by enabling A20 using KBC in i8042_platform_init for x86. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=12878 Signed-off-by: Ondrej Zary Cc: Dmitry Torokhov Cc: Alan Cox Cc: Rafael J. Wysocki Cc: Link: http://lkml.kernel.org/r/201212112218.06551.linux@rainbow-software.org Signed-off-by: H. Peter Anvin diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index d6cc77a..5f306f7 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -921,6 +921,7 @@ static int __init i8042_platform_init(void) int retval; #ifdef CONFIG_X86 + u8 a20_on = 0xdf; /* Just return if pre-detection shows no i8042 controller exist */ if (!x86_platform.i8042_detect()) return -ENODEV; @@ -960,6 +961,14 @@ static int __init i8042_platform_init(void) if (dmi_check_system(i8042_dmi_dritek_table)) i8042_dritek = true; + + /* + * A20 was already enabled during early kernel init. But some buggy + * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to + * resume from S3. So we do it here and hope that nothing breaks. + */ + i8042_command(&a20_on, 0x10d1); + i8042_command(NULL, 0x00ff); /* Null command for SMM firmware */ #endif /* CONFIG_X86 */ return retval; -- cgit v0.10.2 From 210dce5faf89c9677ac1a6273bc53f130843539f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 10 Dec 2012 22:21:19 +0100 Subject: ARM: ep93xx: properly wait for UART FIFO to be empty This patch changes the busy-waiting loop around in the decompressor putc() function on the UART FIFO register. Without a proper wait, the output of the decompressor was corrupted like this: Uncompressing Linx. done, booting th enl To highlight the issue more evidently, looping 100 times instead of 1000 makes the issue appear much faster. This patch takes the approach of using an active while loop until the FIFO is empty (not FULL). This issue happened to me on Sim.One running at 200Mhz. Signed-off-by: Florian Fainelli Signed-off-by: Ryan Mallon diff --git a/arch/arm/mach-ep93xx/include/mach/uncompress.h b/arch/arm/mach-ep93xx/include/mach/uncompress.h index 16026c2..d64274f 100644 --- a/arch/arm/mach-ep93xx/include/mach/uncompress.h +++ b/arch/arm/mach-ep93xx/include/mach/uncompress.h @@ -47,13 +47,9 @@ static void __raw_writel(unsigned int value, unsigned int ptr) static inline void putc(int c) { - int i; - - for (i = 0; i < 1000; i++) { - /* Transmit fifo not full? */ - if (!(__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF)) - break; - } + /* Transmit fifo not full? */ + while (__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF) + ; __raw_writeb(c, PHYS_UART_DATA); } -- cgit v0.10.2 From 5a90d41b693bda1318807a49d38ef1444f61dfdd Mon Sep 17 00:00:00 2001 From: Mike Dunn Date: Fri, 7 Dec 2012 12:07:21 -0800 Subject: mtd: nand/docg4: add support for writing in reliable mode The controller on the docg4 has a "reliable" mode, where consecutive 2k pages are used in parallel. The initial program loader (IPL) on my Treo 680 expects the secondary program loader (SPL) to be written in this mode. This patch adds support for writing data in reliable mode, by way of a module parameter. Support for reading in this mode (as the IPL does) is not supported yet, but alternate (even-numbered) 2k pages written in reliable mode can be read normally (odd-numbered pages will contain junk and generate ecc errors). Signed-off-by: Mike Dunn Acked-by: Robert Jarzmik Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 799da5d..54b1e5e 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -46,6 +46,25 @@ #include /* + * In "reliable mode" consecutive 2k pages are used in parallel (in some + * fashion) to store the same data. The data can be read back from the + * even-numbered pages in the normal manner; odd-numbered pages will appear to + * contain junk. Systems that boot from the docg4 typically write the secondary + * program loader (SPL) code in this mode. The SPL is loaded by the initial + * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped + * to the reset vector address). This module parameter enables you to use this + * driver to write the SPL. When in this mode, no more than 2k of data can be + * written at a time, because the addresses do not increment in the normal + * manner, and the starting offset must be within an even-numbered 2k region; + * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800, + * 0x1a00, ... Reliable mode is a special case and should not be used unless + * you know what you're doing. + */ +static bool reliable_mode; +module_param(reliable_mode, bool, 0); +MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode"); + +/* * You'll want to ignore badblocks if you're reading a partition that contains * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since * it does not use mtd nand's method for marking bad blocks (using oob area). @@ -113,6 +132,7 @@ struct docg4_priv { #define DOCG4_SEQ_PAGEWRITE 0x16 #define DOCG4_SEQ_PAGEPROG 0x1e #define DOCG4_SEQ_BLOCKERASE 0x24 +#define DOCG4_SEQ_SETMODE 0x45 /* DOC_FLASHCOMMAND register commands */ #define DOCG4_CMD_PAGE_READ 0x00 @@ -122,6 +142,8 @@ struct docg4_priv { #define DOC_CMD_PROG_BLOCK_ADDR 0x60 #define DOCG4_CMD_PAGEWRITE 0x80 #define DOC_CMD_PROG_CYCLE2 0x10 +#define DOCG4_CMD_FAST_MODE 0xa3 /* functionality guessed */ +#define DOC_CMD_RELIABLE_MODE 0x22 #define DOC_CMD_RESET 0xff /* DOC_POWERMODE register bits */ @@ -611,6 +633,14 @@ static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr) dev_dbg(doc->dev, "docg4: %s: g4 addr: %x\n", __func__, docg4_addr); sequence_reset(mtd); + + if (unlikely(reliable_mode)) { + writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE); + writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND); + writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND); + write_nop(docptr); + } + writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE); writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND); write_nop(docptr); @@ -691,6 +721,15 @@ static void docg4_command(struct mtd_info *mtd, unsigned command, int column, break; case NAND_CMD_SEQIN: + if (unlikely(reliable_mode)) { + uint16_t g4_page = g4_addr >> 16; + + /* writes to odd-numbered 2k pages are invalid */ + if (g4_page & 0x01) + dev_warn(doc->dev, + "invalid reliable mode address\n"); + } + write_page_prologue(mtd, g4_addr); /* hack for deferred write of oob bytes */ -- cgit v0.10.2 From 440b1d73b1b49bc08e1709ee6f6ef7ba2fc1f8ba Mon Sep 17 00:00:00 2001 From: Mike Dunn Date: Fri, 7 Dec 2012 12:07:22 -0800 Subject: mtd: nand/docg4: reserve bb marker area in ecclayout Modify the nand_ecclayout to place the two bb marker bytes in the oob region off-limits to the user. Signed-off-by: Mike Dunn Acked-by: Robert Jarzmik Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 54b1e5e..04e5fa9 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -214,15 +214,17 @@ struct docg4_priv { #define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */ /* - * Oob bytes 0 - 6 are available to the user. - * Byte 7 is hamming ecc for first 7 bytes. Bytes 8 - 14 are hw-generated ecc. + * Bytes 0, 1 are used as badblock marker. + * Bytes 2 - 6 are available to the user. + * Byte 7 is hamming ecc for first 7 oob bytes only. + * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14. * Byte 15 (the last) is used by the driver as a "page written" flag. */ static struct nand_ecclayout docg4_oobinfo = { .eccbytes = 9, .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15}, - .oobavail = 7, - .oobfree = { {0, 7} } + .oobavail = 5, + .oobfree = { {.offset = 2, .length = 5} } }; /* -- cgit v0.10.2 From 3c9c6d657a94f9b9aae498cb5951659cc67fd6ad Mon Sep 17 00:00:00 2001 From: Mike Dunn Date: Fri, 7 Dec 2012 12:07:23 -0800 Subject: mtd: nand/docg4: fix and improve read of factory bbt This patch does two things related to reading the factory badblock table during initialization: (1) fix error where a non-zero return code from docg4_read_page() is assumed to be an error (it was later changed to be max_bitflips; thanks to Brian Norris for bringing this to my attention a while back), and (2) if there is an error reading the factory bbt, it tries reading another (redundant) factory bbt table. Signed-off-by: Mike Dunn Acked-by: Robert Jarzmik Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 04e5fa9..18fa448 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -212,6 +212,7 @@ struct docg4_priv { #define DOCG4_T 4 /* BCH alg corrects up to 4 bit errors */ #define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */ +#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */ /* * Bytes 0, 1 are used as badblock marker. @@ -1020,16 +1021,15 @@ static int __init read_factory_bbt(struct mtd_info *mtd) struct docg4_priv *doc = nand->priv; uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0); uint8_t *buf; - int i, block, status; + int i, block; + __u32 eccfailed_stats = mtd->ecc_stats.failed; buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL); if (buf == NULL) return -ENOMEM; read_page_prologue(mtd, g4_addr); - status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE); - if (status) - goto exit; + docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE); /* * If no memory-based bbt was created, exit. This will happen if module @@ -1041,6 +1041,20 @@ static int __init read_factory_bbt(struct mtd_info *mtd) if (nand->bbt == NULL) /* no memory-based bbt */ goto exit; + if (mtd->ecc_stats.failed > eccfailed_stats) { + /* + * Whoops, an ecc failure ocurred reading the factory bbt. + * It is stored redundantly, so we get another chance. + */ + eccfailed_stats = mtd->ecc_stats.failed; + docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE); + if (mtd->ecc_stats.failed > eccfailed_stats) { + dev_warn(doc->dev, + "The factory bbt could not be read!\n"); + goto exit; + } + } + /* * Parse factory bbt and update memory-based bbt. Factory bbt format is * simple: one bit per block, block numbers increase left to right (msb @@ -1060,7 +1074,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd) } exit: kfree(buf); - return status; + return 0; } static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) -- cgit v0.10.2 From 67fad106a219e083c91c79695bd1807dde1bf7b9 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 12 Dec 2012 11:38:44 -0500 Subject: nfs: don't zero out the rest of the page if we hit the EOF on a DIO READ Eryu provided a test program that would segfault when attempting to read past the EOF on file that was opened O_DIRECT. The buffer given to the read() call was on the stack, and when he attempted to read past it it would scribble over the rest of the stack page. If we hit the end of the file on a DIO READ request, then we don't want to zero out the rest of the buffer. These aren't pagecache pages after all, and there's no guarantee that the buffers that were passed in represent entire pages. Cc: # v3.5+ Cc: Fred Isaman Reported-by: Eryu Guan Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index cae26cb..594f4e7 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -266,14 +266,6 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) struct nfs_page *req = nfs_list_entry(hdr->pages.next); struct page *page = req->wb_page; - if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) { - if (bytes > hdr->good_bytes) - zero_user(page, 0, PAGE_SIZE); - else if (hdr->good_bytes - bytes < PAGE_SIZE) - zero_user_segment(page, - hdr->good_bytes & ~PAGE_MASK, - PAGE_SIZE); - } if (!PageCompound(page)) { if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { if (bytes < hdr->good_bytes) -- cgit v0.10.2 From be7e985804c610fcdcee8730cf42718b8a4e1c41 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 12 Dec 2012 12:36:31 -0500 Subject: nfs: fix page dirtying in NFS DIO read codepath The NFS DIO code will dirty pages that catch read responses in order to handle the case where someone is doing DIO reads into an mmapped buffer. The existing code doesn't really do the right thing though since it doesn't take into account the case where we might be attempting to read past the EOF. Fix the logic in that code to only dirty pages that ended up receiving data from the read. Note too that it really doesn't matter if NFS_IOHDR_ERROR is set or not. All that matters is if the page was altered by the read. Cc: Fred Isaman Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 594f4e7..0bd7a55 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -266,13 +266,8 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) struct nfs_page *req = nfs_list_entry(hdr->pages.next); struct page *page = req->wb_page; - if (!PageCompound(page)) { - if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) { - if (bytes < hdr->good_bytes) - set_page_dirty(page); - } else - set_page_dirty(page); - } + if (!PageCompound(page) && bytes < hdr->good_bytes) + set_page_dirty(page); bytes += req->wb_bytes; nfs_list_remove_request(req); nfs_direct_readpage_release(req); -- cgit v0.10.2 From 620038f6d2304475dce800dc5c75fc335a19613a Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Tue, 27 Nov 2012 10:34:20 -0500 Subject: SUNRPC set gss gc_expiry to full lifetime Only use the default GSSD_MIN_TIMEOUT if the gss downcall timeout is zero. Store the full lifetime in gc_expiry (not 3/4 of the lifetime) as subsequent patches will use the gc_expiry to determine buffered WRITE behavior in the face of expired or soon to be expired gss credentials. Signed-off-by: Andy Adamson Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 909dc0c..6e5c824 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -192,17 +192,23 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct const void *q; unsigned int seclen; unsigned int timeout; + unsigned long now = jiffies; u32 window_size; int ret; - /* First unsigned int gives the lifetime (in seconds) of the cred */ + /* First unsigned int gives the remaining lifetime in seconds of the + * credential - e.g. the remaining TGT lifetime for Kerberos or + * the -t value passed to GSSD. + */ p = simple_get_bytes(p, end, &timeout, sizeof(timeout)); if (IS_ERR(p)) goto err; if (timeout == 0) timeout = GSSD_MIN_TIMEOUT; - ctx->gc_expiry = jiffies + (unsigned long)timeout * HZ * 3 / 4; - /* Sequence number window. Determines the maximum number of simultaneous requests */ + ctx->gc_expiry = now + ((unsigned long)timeout * HZ); + /* Sequence number window. Determines the maximum number of + * simultaneous requests + */ p = simple_get_bytes(p, end, &window_size, sizeof(window_size)); if (IS_ERR(p)) goto err; @@ -237,9 +243,12 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct p = ERR_PTR(ret); goto err; } + dprintk("RPC: %s Success. gc_expiry %lu now %lu timeout %u\n", + __func__, ctx->gc_expiry, now, timeout); return q; err: - dprintk("RPC: %s returning %ld\n", __func__, -PTR_ERR(p)); + dprintk("RPC: %s returns %ld gc_expiry %lu now %lu timeout %u\n", + __func__, -PTR_ERR(p), ctx->gc_expiry, now, timeout); return p; } -- cgit v0.10.2 From eb96d5c97b0825d542e9c4ba5e0a22b519355166 Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Tue, 27 Nov 2012 10:34:19 -0500 Subject: SUNRPC handle EKEYEXPIRED in call_refreshresult Currently, when an RPCSEC_GSS context has expired or is non-existent and the users (Kerberos) credentials have also expired or are non-existent, the client receives the -EKEYEXPIRED error and tries to refresh the context forever. If an application is performing I/O, or other work against the share, the application hangs, and the user is not prompted to refresh/establish their credentials. This can result in a denial of service for other users. Users are expected to manage their Kerberos credential lifetimes to mitigate this issue. Move the -EKEYEXPIRED handling into the RPC layer. Try tk_cred_retry number of times to refresh the gss_context, and then return -EACCES to the application. Signed-off-by: Andy Adamson Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 6932209..70efb63 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -24,14 +24,14 @@ #define NFSDBG_FACILITY NFSDBG_PROC -/* A wrapper to handle the EJUKEBOX and EKEYEXPIRED error messages */ +/* A wrapper to handle the EJUKEBOX error messages */ static int nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) { int res; do { res = rpc_call_sync(clnt, msg, flags); - if (res != -EJUKEBOX && res != -EKEYEXPIRED) + if (res != -EJUKEBOX) break; freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); res = -ERESTARTSYS; @@ -44,7 +44,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) static int nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) { - if (task->tk_status != -EJUKEBOX && task->tk_status != -EKEYEXPIRED) + if (task->tk_status != -EJUKEBOX) return 0; if (task->tk_status == -EJUKEBOX) nfs_inc_stats(inode, NFSIOS_DELAY); diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 1e42413..194c484 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -179,7 +179,6 @@ static int filelayout_async_handle_error(struct rpc_task *task, break; case -NFS4ERR_DELAY: case -NFS4ERR_GRACE: - case -EKEYEXPIRED: rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX); break; case -NFS4ERR_RETRY_UNCACHED_REP: diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a4692e9..b0963ae 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -333,7 +333,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc } case -NFS4ERR_GRACE: case -NFS4ERR_DELAY: - case -EKEYEXPIRED: ret = nfs4_delay(server->client, &exception->timeout); if (ret != 0) break; @@ -1343,13 +1342,6 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state nfs_inode_find_state_and_recover(state->inode, stateid); nfs4_schedule_stateid_recovery(server, state); - case -EKEYEXPIRED: - /* - * User RPCSEC_GSS context has expired. - * We cannot recover this stateid now, so - * skip it and allow recovery thread to - * proceed. - */ case -ENOMEM: err = 0; goto out; @@ -3946,7 +3938,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, case -NFS4ERR_DELAY: nfs_inc_server_stats(server, NFSIOS_DELAY); case -NFS4ERR_GRACE: - case -EKEYEXPIRED: rpc_delay(task, NFS4_POLL_RETRY_MAX); task->tk_status = 0; return -EAGAIN; @@ -4946,15 +4937,6 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) nfs4_schedule_stateid_recovery(server, state); err = 0; goto out; - case -EKEYEXPIRED: - /* - * User RPCSEC_GSS context has expired. - * We cannot recover this stateid now, so - * skip it and allow recovery thread to - * proceed. - */ - err = 0; - goto out; case -ENOMEM: case -NFS4ERR_DENIED: /* kill_proc(fl->fl_pid, SIGLOST, 1); */ diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 78e90a8..8dcbd9a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1437,14 +1437,6 @@ restart: /* Mark the file as being 'closed' */ state->state = 0; break; - case -EKEYEXPIRED: - /* - * User RPCSEC_GSS context has expired. - * We cannot recover this stateid now, so - * skip it and allow recovery thread to - * proceed. - */ - break; case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_STALE_STATEID: case -NFS4ERR_BAD_STATEID: @@ -1597,14 +1589,6 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp) nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce); } -static void nfs4_warn_keyexpired(const char *s) -{ - printk_ratelimited(KERN_WARNING "Error: state manager" - " encountered RPCSEC_GSS session" - " expired against NFSv4 server %s.\n", - s); -} - static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) { switch (error) { @@ -1638,10 +1622,6 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state); break; - case -EKEYEXPIRED: - /* Nothing we can do */ - nfs4_warn_keyexpired(clp->cl_hostname); - break; default: dprintk("%s: failed to handle error %d for server %s\n", __func__, error, clp->cl_hostname); @@ -1758,8 +1738,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status) dprintk("%s: exit with error %d for server %s\n", __func__, -EPROTONOSUPPORT, clp->cl_hostname); return -EPROTONOSUPPORT; - case -EKEYEXPIRED: - nfs4_warn_keyexpired(clp->cl_hostname); case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery * in nfs4_exchange_id */ default: @@ -1912,7 +1890,6 @@ again: break; case -EKEYEXPIRED: - nfs4_warn_keyexpired(clp->cl_hostname); case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery * in nfs4_exchange_id */ status = -EKEYEXPIRED; diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 50a88c3..f084dac 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -47,39 +47,6 @@ #define NFSDBG_FACILITY NFSDBG_PROC /* - * wrapper to handle the -EKEYEXPIRED error message. This should generally - * only happen if using krb5 auth and a user's TGT expires. NFSv2 doesn't - * support the NFSERR_JUKEBOX error code, but we handle this situation in the - * same way that we handle that error with NFSv3. - */ -static int -nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) -{ - int res; - do { - res = rpc_call_sync(clnt, msg, flags); - if (res != -EKEYEXPIRED) - break; - freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); - res = -ERESTARTSYS; - } while (!fatal_signal_pending(current)); - return res; -} - -#define rpc_call_sync(clnt, msg, flags) nfs_rpc_wrapper(clnt, msg, flags) - -static int -nfs_async_handle_expired_key(struct rpc_task *task) -{ - if (task->tk_status != -EKEYEXPIRED) - return 0; - task->tk_status = 0; - rpc_restart_call(task); - rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); - return 1; -} - -/* * Bare-bones access to getattr: this is for nfs_read_super. */ static int @@ -364,8 +331,6 @@ static void nfs_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlink static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) { - if (nfs_async_handle_expired_key(task)) - return 0; nfs_mark_for_revalidate(dir); return 1; } @@ -385,8 +350,6 @@ static int nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir, struct inode *new_dir) { - if (nfs_async_handle_expired_key(task)) - return 0; nfs_mark_for_revalidate(old_dir); nfs_mark_for_revalidate(new_dir); return 1; @@ -642,9 +605,6 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) { struct inode *inode = data->header->inode; - if (nfs_async_handle_expired_key(task)) - return -EAGAIN; - nfs_invalidate_atime(inode); if (task->tk_status >= 0) { nfs_refresh_inode(inode, data->res.fattr); @@ -671,9 +631,6 @@ static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) { struct inode *inode = data->header->inode; - if (nfs_async_handle_expired_key(task)) - return -EAGAIN; - if (task->tk_status >= 0) nfs_post_op_update_inode_force_wcc(inode, data->res.fattr); return 0; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index c69e199..55e174f 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1381,6 +1381,7 @@ call_refreshresult(struct rpc_task *task) return; case -ETIMEDOUT: rpc_delay(task, 3*HZ); + case -EKEYEXPIRED: case -EAGAIN: status = -EACCES; if (!task->tk_cred_retry) -- cgit v0.10.2 From 0253f40ef9a709a1af39ce38b1d998af090f8127 Mon Sep 17 00:00:00 2001 From: "jeff.liu" Date: Sat, 27 Oct 2012 12:06:39 +0000 Subject: Btrfs: Remove the invalid shrink size check up from btrfs_shrink_dev() Remove an invalid size check up from btrfs_shrink_dev(). The new size should not larger than the device->total_bytes as it was already verified before coming to here(i.e. new_size < old_size). Remove invalid check up for btrfs_shrink_dev(). Signed-off-by: Jie Liu Signed-off-by: Chris Mason diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 8fcf9a5..14c0d2e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1409,7 +1409,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, btrfs_commit_transaction(trans, root); } else if (new_size < old_size) { ret = btrfs_shrink_device(device, new_size); - } + } /* equal, nothing need to do */ out_free: kfree(vol_args); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index eaaf0bf..32a8842 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3059,9 +3059,6 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) u64 old_size = device->total_bytes; u64 diff = device->total_bytes - new_size; - if (new_size >= device->total_bytes) - return -EINVAL; - path = btrfs_alloc_path(); if (!path) return -ENOMEM; -- cgit v0.10.2 From d1423248734df6d9aff769abffd675dc034e0601 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 31 Oct 2012 15:16:32 +0000 Subject: Btrfs: Fix typo in fs/btrfs Correct spelling typo in btrfs. Signed-off-by: Masanari Iida Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index cad1656..2d41cb2 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -413,7 +413,7 @@ struct btrfs_root_backup { __le64 bytes_used; __le64 num_devices; /* future */ - __le64 unsed_64[4]; + __le64 unused_64[4]; u8 tree_root_level; u8 chunk_root_level; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 32a8842..eeed97d 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4261,7 +4261,7 @@ static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio, rcu_read_lock(); name = rcu_dereference(dev->name); - pr_debug("btrfs_map_bio: rw %d, secor=%llu, dev=%lu " + pr_debug("btrfs_map_bio: rw %d, sector=%llu, dev=%lu " "(%s id %llu), size=%u\n", rw, (u64)bio->bi_sector, (u_long)dev->bdev->bd_dev, name->str, dev->devid, bio->bi_size); -- cgit v0.10.2 From 292fd7fc39aa06668f3a8db546714e727120cb3e Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Tue, 30 Oct 2012 17:16:16 +0000 Subject: Btrfs: don't allow degraded mount if too many devices are missing The current behavior is to allow mounting or remounting a filesystem writeable in degraded mode if at least one writeable device is present. The next failed write access to a missing device which is above the tolerance of the configured level of redundancy results in an read-only enforcement. Even without this, the next time barrier_all_devices() is called and more devices are missing than tolerable, the switch to read-only mode takes place. In order to behave predictably and to provide proper feedback to the user at mount time, this patch compares the number of missing devices with the number of devices that are tolerated to be missing according to the configured RAID level. If more devices are missing than tolerated, e.g. if two devices are missing in case of RAID1, only a read-only mount and remount is allowed. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index bd70c28..0643159 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2508,6 +2508,13 @@ retry_root_backup: } fs_info->num_tolerated_disk_barrier_failures = btrfs_calc_num_tolerated_disk_barrier_failures(fs_info); + if (fs_info->fs_devices->missing_devices > + fs_info->num_tolerated_disk_barrier_failures && + !(sb->s_flags & MS_RDONLY)) { + printk(KERN_WARNING + "Btrfs: too many missing devices, writeable mount is not allowed\n"); + goto fail_block_groups; + } fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, "btrfs-cleaner"); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 915ac14..acd2df8 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1226,6 +1226,15 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) goto restore; } + if (fs_info->fs_devices->missing_devices > + fs_info->num_tolerated_disk_barrier_failures && + !(*flags & MS_RDONLY)) { + printk(KERN_WARNING + "Btrfs: too many missing devices, writeable remount is not allowed\n"); + ret = -EACCES; + goto restore; + } + if (btrfs_super_log_root(fs_info->super_copy) != 0) { ret = -EINVAL; goto restore; -- cgit v0.10.2 From 183f37fa3503332740c76f1b493f4304ec889358 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 1 Nov 2012 06:38:47 +0000 Subject: Btrfs: do not log extents when we only log new names When we log new names, we need to log just enough to recreate the inode during log replay, and there is no need to log extents along with it. This actually fixes a bug revealed by xfstests 241, where it shows that we're logging some extents that have not updated metadata, so we don't get proper EXTENT_DATA items to be copied to log tree. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 81e407d..4ec41ec 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3435,7 +3435,8 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ret = btrfs_truncate_inode_items(trans, log, inode, 0, 0); } else { - fast_search = true; + if (inode_only == LOG_INODE_ALL) + fast_search = true; max_key.type = BTRFS_XATTR_ITEM_KEY; ret = drop_objectid_items(trans, log, path, ino, BTRFS_XATTR_ITEM_KEY); -- cgit v0.10.2 From 9f3959c53d57d010ae6f4205fbd0159cb7976a83 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 1 Nov 2012 06:38:48 +0000 Subject: Btrfs: get right arguments for btrfs_wait_ordered_range btrfs_wait_ordered_range expects for 'len' instead of 'end'. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 9ab1bed..d2df981 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1562,7 +1562,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) * range being left. */ atomic_inc(&root->log_batch); - btrfs_wait_ordered_range(inode, start, end); + btrfs_wait_ordered_range(inode, start, end - start + 1); atomic_inc(&root->log_batch); /* -- cgit v0.10.2 From 4fde183d8c755f8a8bdffcb03a8d947e62ccea6a Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 1 Nov 2012 06:38:49 +0000 Subject: Btrfs: cleanup for btrfs_wait_order_range Variable 'found' is no more used. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index eecc20f..f107312 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -653,7 +653,6 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) u64 end; u64 orig_end; struct btrfs_ordered_extent *ordered; - int found; if (start + len < start) { orig_end = INT_LIMIT(loff_t); @@ -689,7 +688,6 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) filemap_fdatawait_range(inode->i_mapping, start, orig_end); end = orig_end; - found = 0; while (1) { ordered = btrfs_lookup_first_ordered_extent(inode, end); if (!ordered) @@ -702,7 +700,6 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) btrfs_put_ordered_extent(ordered); break; } - found++; btrfs_start_ordered_extent(inode, ordered, 1); end = ordered->file_offset; btrfs_put_ordered_extent(ordered); -- cgit v0.10.2 From b7d5b0a819498a9c04e1d18201a42468f7edd92a Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 1 Nov 2012 07:32:18 +0000 Subject: Btrfs: fix joining the same transaction handler more than 2 times If we flush inodes with pending delalloc in a transaction, we may join the same transaction handler more than 2 times. The reason is: Task use_count of trans handle commit_transaction 1 |-> btrfs_start_delalloc_inodes 1 |-> run_delalloc_nocow 1 |-> join_transaction 2 |-> cow_file_range 2 |-> join_transaction 3 In fact, cow_file_range needn't join the transaction again because the caller have joined the transaction, so we fix this problem by this way. Reported-by: Liu Bo Signed-off-by: Miao Xie Signed-off-by: Chris Mason diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index dce9e21..96d2090 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -804,14 +804,14 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start, * required to start IO on it. It may be clean and already done with * IO when we return. */ -static noinline int cow_file_range(struct inode *inode, - struct page *locked_page, - u64 start, u64 end, int *page_started, - unsigned long *nr_written, - int unlock) +static noinline int __cow_file_range(struct btrfs_trans_handle *trans, + struct inode *inode, + struct btrfs_root *root, + struct page *locked_page, + u64 start, u64 end, int *page_started, + unsigned long *nr_written, + int unlock) { - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; u64 alloc_hint = 0; u64 num_bytes; unsigned long ram_size; @@ -824,25 +824,10 @@ static noinline int cow_file_range(struct inode *inode, int ret = 0; BUG_ON(btrfs_is_free_space_inode(inode)); - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - extent_clear_unlock_delalloc(inode, - &BTRFS_I(inode)->io_tree, - start, end, locked_page, - EXTENT_CLEAR_UNLOCK_PAGE | - EXTENT_CLEAR_UNLOCK | - EXTENT_CLEAR_DELALLOC | - EXTENT_CLEAR_DIRTY | - EXTENT_SET_WRITEBACK | - EXTENT_END_WRITEBACK); - return PTR_ERR(trans); - } - trans->block_rsv = &root->fs_info->delalloc_block_rsv; num_bytes = (end - start + blocksize) & ~(blocksize - 1); num_bytes = max(blocksize, num_bytes); disk_num_bytes = num_bytes; - ret = 0; /* if this is a small write inside eof, kick off defrag */ if (num_bytes < 64 * 1024 && @@ -953,11 +938,9 @@ static noinline int cow_file_range(struct inode *inode, alloc_hint = ins.objectid + ins.offset; start += cur_alloc_size; } - ret = 0; out: - btrfs_end_transaction(trans, root); - return ret; + out_unlock: extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree, @@ -972,6 +955,39 @@ out_unlock: goto out; } +static noinline int cow_file_range(struct inode *inode, + struct page *locked_page, + u64 start, u64 end, int *page_started, + unsigned long *nr_written, + int unlock) +{ + struct btrfs_trans_handle *trans; + struct btrfs_root *root = BTRFS_I(inode)->root; + int ret; + + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) { + extent_clear_unlock_delalloc(inode, + &BTRFS_I(inode)->io_tree, + start, end, locked_page, + EXTENT_CLEAR_UNLOCK_PAGE | + EXTENT_CLEAR_UNLOCK | + EXTENT_CLEAR_DELALLOC | + EXTENT_CLEAR_DIRTY | + EXTENT_SET_WRITEBACK | + EXTENT_END_WRITEBACK); + return PTR_ERR(trans); + } + trans->block_rsv = &root->fs_info->delalloc_block_rsv; + + ret = __cow_file_range(trans, inode, root, locked_page, start, end, + page_started, nr_written, unlock); + + btrfs_end_transaction(trans, root); + + return ret; +} + /* * work queue call back to started compression on a file and pages */ @@ -1282,9 +1298,9 @@ out_check: btrfs_release_path(path); if (cow_start != (u64)-1) { - ret = cow_file_range(inode, locked_page, cow_start, - found_key.offset - 1, page_started, - nr_written, 1); + ret = __cow_file_range(trans, inode, root, locked_page, + cow_start, found_key.offset - 1, + page_started, nr_written, 1); if (ret) { btrfs_abort_transaction(trans, root, ret); goto error; @@ -1353,8 +1369,9 @@ out_check: } if (cow_start != (u64)-1) { - ret = cow_file_range(inode, locked_page, cow_start, end, - page_started, nr_written, 1); + ret = __cow_file_range(trans, inode, root, locked_page, + cow_start, end, + page_started, nr_written, 1); if (ret) { btrfs_abort_transaction(trans, root, ret); goto error; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 259f74e..44a5d73 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -312,6 +312,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, int type, WARN_ON(type != TRANS_JOIN && type != TRANS_JOIN_NOLOCK); h = current->journal_info; h->use_count++; + WARN_ON(h->use_count > 2); h->orig_rsv = h->block_rsv; h->block_rsv = NULL; goto got_it; -- cgit v0.10.2 From ca46963718ef7368c84267c9f5e7394c3890442a Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 1 Nov 2012 07:33:14 +0000 Subject: Btrfs: fix missing flush when committing a transaction Consider the following case: Task1 Task2 start_transaction commit_transaction check pending snapshots list and the list is empty. add pending snapshot into list skip the delalloc flush end_transaction ... And then the problem that the snapshot is different with the source subvolume happen. This patch fixes the above problem by flush all pending stuffs when all the other tasks end the transaction. Signed-off-by: Miao Xie Signed-off-by: Chris Mason diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 44a5d73..bc1f523 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1399,6 +1399,48 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, kmem_cache_free(btrfs_trans_handle_cachep, trans); } +static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans, + struct btrfs_root *root) +{ + int flush_on_commit = btrfs_test_opt(root, FLUSHONCOMMIT); + int snap_pending = 0; + int ret; + + if (!flush_on_commit) { + spin_lock(&root->fs_info->trans_lock); + if (!list_empty(&trans->transaction->pending_snapshots)) + snap_pending = 1; + spin_unlock(&root->fs_info->trans_lock); + } + + if (flush_on_commit || snap_pending) { + btrfs_start_delalloc_inodes(root, 1); + btrfs_wait_ordered_extents(root, 1); + } + + ret = btrfs_run_delayed_items(trans, root); + if (ret) + return ret; + + /* + * running the delayed items may have added new refs. account + * them now so that they hinder processing of more delayed refs + * as little as possible. + */ + btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info); + + /* + * rename don't use btrfs_join_transaction, so, once we + * set the transaction to blocked above, we aren't going + * to get any new ordered operations. We can safely run + * it here and no for sure that nothing new will be added + * to the list + */ + btrfs_run_ordered_operations(root, 1); + + return 0; +} + /* * btrfs_transaction state sequence: * in_commit = 0, blocked = 0 (initial) @@ -1416,7 +1458,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, int ret; int should_grow = 0; unsigned long now = get_seconds(); - int flush_on_commit = btrfs_test_opt(root, FLUSHONCOMMIT); ret = btrfs_run_ordered_operations(root, 0); if (ret) { @@ -1495,47 +1536,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, should_grow = 1; do { - int snap_pending = 0; - joined = cur_trans->num_joined; - if (!list_empty(&trans->transaction->pending_snapshots)) - snap_pending = 1; WARN_ON(cur_trans != trans->transaction); - if (flush_on_commit || snap_pending) { - ret = btrfs_start_delalloc_inodes(root, 1); - if (ret) { - btrfs_abort_transaction(trans, root, ret); - goto cleanup_transaction; - } - btrfs_wait_ordered_extents(root, 1); - } - - ret = btrfs_run_delayed_items(trans, root); + ret = btrfs_flush_all_pending_stuffs(trans, root); if (ret) goto cleanup_transaction; - /* - * running the delayed items may have added new refs. account - * them now so that they hinder processing of more delayed refs - * as little as possible. - */ - btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info); - - /* - * rename don't use btrfs_join_transaction, so, once we - * set the transaction to blocked above, we aren't going - * to get any new ordered operations. We can safely run - * it here and no for sure that nothing new will be added - * to the list - */ - ret = btrfs_run_ordered_operations(root, 1); - if (ret) { - btrfs_abort_transaction(trans, root, ret); - goto cleanup_transaction; - } - prepare_to_wait(&cur_trans->writer_wait, &wait, TASK_UNINTERRUPTIBLE); @@ -1548,6 +1556,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, } while (atomic_read(&cur_trans->num_writers) > 1 || (should_grow && cur_trans->num_joined != joined)); + ret = btrfs_flush_all_pending_stuffs(trans, root); + if (ret) + goto cleanup_transaction; + /* * Ok now we need to make sure to block out any other joins while we * commit the transaction. We could have started a join before setting -- cgit v0.10.2 From 315a9850da2b89c83971b26fe54a60f22bdd91ad Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 1 Nov 2012 07:33:59 +0000 Subject: Btrfs: fix wrong file extent length There are two types of the file extent - inline extent and regular extent, When we log file extents, we didn't take inline extent into account, fix it. Signed-off-by: Miao Xie Reviewed-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 2d41cb2..f9a0786 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3263,6 +3263,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, u64 bytenr, int mod); +u64 btrfs_file_extent_length(struct btrfs_path *path); int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_ordered_sum *sums); diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 1ad08e4e4..bd38cef 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -133,7 +133,6 @@ fail: return ERR_PTR(ret); } - int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, @@ -151,6 +150,26 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, return ret; } +u64 btrfs_file_extent_length(struct btrfs_path *path) +{ + int extent_type; + struct btrfs_file_extent_item *fi; + u64 len; + + fi = btrfs_item_ptr(path->nodes[0], path->slots[0], + struct btrfs_file_extent_item); + extent_type = btrfs_file_extent_type(path->nodes[0], fi); + + if (extent_type == BTRFS_FILE_EXTENT_REG || + extent_type == BTRFS_FILE_EXTENT_PREALLOC) + len = btrfs_file_extent_num_bytes(path->nodes[0], fi); + else if (extent_type == BTRFS_FILE_EXTENT_INLINE) + len = btrfs_file_extent_inline_len(path->nodes[0], fi); + else + BUG(); + + return len; +} static int __btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, struct bio *bio, diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 4ec41ec..bcf0e48 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3143,7 +3143,6 @@ static int log_one_extent(struct btrfs_trans_handle *trans, struct btrfs_path *dst_path, struct log_args *args) { struct btrfs_root *log = root->log_root; - struct btrfs_file_extent_item *fi; struct btrfs_key key; u64 start = em->mod_start; u64 search_start = start; @@ -3199,10 +3198,7 @@ again: } } while (key.offset > start); - fi = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_file_extent_item); - num_bytes = btrfs_file_extent_num_bytes(path->nodes[0], - fi); + num_bytes = btrfs_file_extent_length(path); if (key.offset + num_bytes <= start) { btrfs_release_path(path); return -ENOENT; @@ -3211,8 +3207,7 @@ again: args->src = path->nodes[0]; next_slot: btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - fi = btrfs_item_ptr(args->src, path->slots[0], - struct btrfs_file_extent_item); + num_bytes = btrfs_file_extent_length(path); if (args->nr && args->start_slot + args->nr == path->slots[0]) { args->nr++; @@ -3230,7 +3225,6 @@ next_slot: } nritems = btrfs_header_nritems(path->nodes[0]); path->slots[0]++; - num_bytes = btrfs_file_extent_num_bytes(args->src, fi); if (len < num_bytes) { /* I _think_ this is ok, envision we write to a * preallocated space that is adjacent to a previously -- cgit v0.10.2 From bbe1426764e5dfaa57e7b12cc954acdb3fb7f94b Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 1 Nov 2012 07:34:54 +0000 Subject: Btrfs: fix unprotected extent map operation when logging file extents We forget to protect the modified_extents list, fix it. Signed-off-by: Miao Xie Reviewed-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index bcf0e48..d1947af 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3526,8 +3526,10 @@ next_slot: struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; struct extent_map *em, *n; + write_lock(&tree->lock); list_for_each_entry_safe(em, n, &tree->modified_extents, list) list_del_init(&em->list); + write_unlock(&tree->lock); } if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { -- cgit v0.10.2 From 5269b67e3d809dcaa4c6763a343423bb1b7b3fe6 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Thu, 1 Nov 2012 07:35:23 +0000 Subject: Btrfs: fix missing log when BTRFS_INODE_NEEDS_FULL_SYNC is set If we set BTRFS_INODE_NEEDS_FULL_SYNC, we should log all the extent, but now we forget to take it into account, and set a wrong max key, if so, we will skip the file extent metadata when doing logging. Fix it. Signed-off-by: Miao Xie Signed-off-by: Chris Mason diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index d1947af..40b9efd 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3394,7 +3394,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, /* today the code can only do partial logging of directories */ - if (inode_only == LOG_INODE_EXISTS || S_ISDIR(inode->i_mode)) + if (S_ISDIR(inode->i_mode) || + (!test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, + &BTRFS_I(inode)->runtime_flags) && + inode_only == LOG_INODE_EXISTS)) max_key.type = BTRFS_XATTR_ITEM_KEY; else max_key.type = (u8)-1; -- cgit v0.10.2 From 31b1a2bd758f439fc945b3ac5899d890cb7e2dc6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 3 Nov 2012 10:58:34 +0000 Subject: fs/btrfs: use WARN Use WARN rather than printk followed by WARN_ON(1), for conciseness. A simplified version of the semantic patch that makes this transformation is as follows: (http://coccinelle.lip6.fr/) // @@ expression list es; @@ -printk( +WARN(1, es); -WARN_ON(1); // Signed-off-by: Julia Lawall Reviewed-by: David Sterba Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 100c274..0e4adb0 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1359,19 +1359,16 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, u64 search_start; int ret; - if (trans->transaction != root->fs_info->running_transaction) { - printk(KERN_CRIT "trans %llu running %llu\n", + if (trans->transaction != root->fs_info->running_transaction) + WARN(1, KERN_CRIT "trans %llu running %llu\n", (unsigned long long)trans->transid, (unsigned long long) root->fs_info->running_transaction->transid); - WARN_ON(1); - } - if (trans->transid != root->fs_info->generation) { - printk(KERN_CRIT "trans %llu running %llu\n", + + if (trans->transid != root->fs_info->generation) + WARN(1, KERN_CRIT "trans %llu running %llu\n", (unsigned long long)trans->transid, (unsigned long long)root->fs_info->generation); - WARN_ON(1); - } if (!should_cow_block(trans, root, buf)) { *cow_ret = buf; @@ -3640,11 +3637,9 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans, btrfs_set_header_nritems(left, old_left_nritems + push_items); /* fixup right node */ - if (push_items > right_nritems) { - printk(KERN_CRIT "push items %d nr %u\n", push_items, + if (push_items > right_nritems) + WARN(1, KERN_CRIT "push items %d nr %u\n", push_items, right_nritems); - WARN_ON(1); - } if (push_items < right_nritems) { push_space = btrfs_item_offset_nr(right, push_items - 1) - diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 0643159..07a2162 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3397,14 +3397,12 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf) int was_dirty; btrfs_assert_tree_locked(buf); - if (transid != root->fs_info->generation) { - printk(KERN_CRIT "btrfs transid mismatch buffer %llu, " + if (transid != root->fs_info->generation) + WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, " "found %llu running %llu\n", (unsigned long long)buf->start, (unsigned long long)transid, (unsigned long long)root->fs_info->generation); - WARN_ON(1); - } was_dirty = set_extent_buffer_dirty(buf); if (!was_dirty) { spin_lock(&root->fs_info->delalloc_lock); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b495cb4..0bcb954 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -6292,10 +6292,9 @@ use_block_rsv(struct btrfs_trans_handle *trans, static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, /*DEFAULT_RATELIMIT_BURST*/ 2); - if (__ratelimit(&_rs)) { - printk(KERN_DEBUG "btrfs: block rsv returned %d\n", ret); - WARN_ON(1); - } + if (__ratelimit(&_rs)) + WARN(1, KERN_DEBUG "btrfs: block rsv returned %d\n", + ret); ret = reserve_metadata_bytes(root, block_rsv, blocksize, BTRFS_RESERVE_NO_FLUSH); if (!ret) { diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 472873a..3c062c8 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -341,12 +341,10 @@ static int insert_state(struct extent_io_tree *tree, { struct rb_node *node; - if (end < start) { - printk(KERN_ERR "btrfs end < start %llu %llu\n", + if (end < start) + WARN(1, KERN_ERR "btrfs end < start %llu %llu\n", (unsigned long long)end, (unsigned long long)start); - WARN_ON(1); - } state->start = start; state->end = end; @@ -4721,10 +4719,9 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, } if (start + min_len > eb->len) { - printk(KERN_ERR "btrfs bad mapping eb start %llu len %lu, " + WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, " "wanted %lu %lu\n", (unsigned long long)eb->start, eb->len, start, min_len); - WARN_ON(1); return -EINVAL; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 96d2090..6dca345 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5458,8 +5458,7 @@ again: extent_map_end(em) - 1, NULL, GFP_NOFS); goto insert; } else { - printk(KERN_ERR "btrfs unknown found_type %d\n", found_type); - WARN_ON(1); + WARN(1, KERN_ERR "btrfs unknown found_type %d\n", found_type); } not_found: em->start = start; diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index bc1f523..f21f39f 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -145,16 +145,12 @@ loop: * the log must never go across transaction boundaries. */ smp_mb(); - if (!list_empty(&fs_info->tree_mod_seq_list)) { - printk(KERN_ERR "btrfs: tree_mod_seq_list not empty when " + if (!list_empty(&fs_info->tree_mod_seq_list)) + WARN(1, KERN_ERR "btrfs: tree_mod_seq_list not empty when " "creating a fresh transaction\n"); - WARN_ON(1); - } - if (!RB_EMPTY_ROOT(&fs_info->tree_mod_log)) { - printk(KERN_ERR "btrfs: tree_mod_log rb tree not empty when " + if (!RB_EMPTY_ROOT(&fs_info->tree_mod_log)) + WARN(1, KERN_ERR "btrfs: tree_mod_log rb tree not empty when " "creating a fresh transaction\n"); - WARN_ON(1); - } atomic_set(&fs_info->tree_mod_seq, 0); spin_lock_init(&cur_trans->commit_lock); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index eeed97d..3f4bfee 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3323,9 +3323,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, cur = cur->next; if (!device->writeable) { - printk(KERN_ERR + WARN(1, KERN_ERR "btrfs: read-only device in alloc_list\n"); - WARN_ON(1); continue; } -- cgit v0.10.2 From 6c1500f22a7be3a24ad3dffcdbf04be3f676521b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 3 Nov 2012 20:30:18 +0000 Subject: fs/btrfs: drop if around WARN_ON Just use WARN_ON rather than an if containing only WARN_ON(1). A simplified version of the semantic patch that makes this transformation is as follows: (http://coccinelle.lip6.fr/) // @@ expression e; @@ - if (e) WARN_ON(1); + WARN_ON(e); // Signed-off-by: Julia Lawall Reviewed-by: David Sterba Signed-off-by: Chris Mason diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 208d8aa..a321952 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -890,8 +890,7 @@ again: while (!list_empty(&prefs)) { ref = list_first_entry(&prefs, struct __prelim_ref, list); list_del(&ref->list); - if (ref->count < 0) - WARN_ON(1); + WARN_ON(ref->count < 0); if (ref->count && ref->root_id && ref->parent == 0) { /* no parent == root of tree */ ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS); diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 0e4adb0..5c2cf99 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1464,10 +1464,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, if (cache_only && parent_level != 1) return 0; - if (trans->transaction != root->fs_info->running_transaction) - WARN_ON(1); - if (trans->transid != root->fs_info->generation) - WARN_ON(1); + WARN_ON(trans->transaction != root->fs_info->running_transaction); + WARN_ON(trans->transid != root->fs_info->generation); parent_nritems = btrfs_header_nritems(parent); blocksize = btrfs_level_size(root, parent_level - 1); @@ -3398,8 +3396,7 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans, if (push_items == 0) goto out_unlock; - if (!empty && push_items == left_nritems) - WARN_ON(1); + WARN_ON(!empty && push_items == left_nritems); /* push left to right */ right_nritems = btrfs_header_nritems(right); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6dca345..e8733fa 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1675,8 +1675,7 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans, int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, struct extent_state **cached_state) { - if ((end & (PAGE_CACHE_SIZE - 1)) == 0) - WARN_ON(1); + WARN_ON((end & (PAGE_CACHE_SIZE - 1)) == 0); return set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end, cached_state, GFP_NOFS); } -- cgit v0.10.2 From 37c4146d2208ba7e4463e8dd95a1bf9e3d865280 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Mon, 5 Nov 2012 12:42:08 +0000 Subject: Btrfs: fix a deadlock in aborting transaction due to ENOSPC When committing a transaction, we may bail out of running delayed refs due to ENOSPC, and then abort the current transaction to flip into readonly. But we'll hit a deadlock on ref head's lock since we forget to release its lock and other cleanup stuff. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0bcb954..f8a358a 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2297,6 +2297,9 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, kfree(extent_op); if (ret) { + list_del_init(&locked_ref->cluster); + mutex_unlock(&locked_ref->mutex); + printk(KERN_DEBUG "btrfs: run_delayed_extent_op returned %d\n", ret); spin_lock(&delayed_refs->lock); return ret; @@ -2339,6 +2342,10 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, count++; if (ret) { + if (locked_ref) { + list_del_init(&locked_ref->cluster); + mutex_unlock(&locked_ref->mutex); + } printk(KERN_DEBUG "btrfs: run_one_delayed_ref returned %d\n", ret); spin_lock(&delayed_refs->lock); return ret; -- cgit v0.10.2 From 109f2365f1928af241b2ccbd0f6ba0b93d911288 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Mon, 5 Nov 2012 12:42:09 +0000 Subject: Btrfs: fix a double free on pending snapshots in error handling When creating a snapshot, failing to commit a transaction can end up with aborting the transaction, following by doing a cleanup for it, where we'll free all snapshots pending to disk. So we check it and avoid double free on pending snapshots. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 14c0d2e..e262cd8 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -571,8 +571,12 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, ret = btrfs_commit_transaction(trans, root->fs_info->extent_root); } - if (ret) + if (ret) { + /* cleanup_transaction has freed this for us */ + if (trans->aborted) + pending_snapshot = NULL; goto fail; + } ret = pending_snapshot->error; if (ret) -- cgit v0.10.2 From d03f918ab9036cc71740c0aa796c8e02e6f6f6d3 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 13:10:49 +0000 Subject: Btrfs: Don't trust the superblock label and simply printk("%s") it Someone who is root or capable(CAP_SYS_ADMIN) could corrupt the superblock and make Btrfs printk("%s") crash while holding the uuid_mutex since nobody forces a limit on the string. Since the uuid_mutex is significant, the system would be unusable afterwards. Signed-off-by: Stefan Behrens Reviewed-by: David Sterba Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 3f4bfee..db79fb7 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -764,10 +764,13 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, devid = btrfs_stack_device_id(&disk_super->dev_item); transid = btrfs_super_generation(disk_super); total_devices = btrfs_super_num_devices(disk_super); - if (disk_super->label[0]) + if (disk_super->label[0]) { + if (disk_super->label[BTRFS_LABEL_SIZE - 1]) + disk_super->label[BTRFS_LABEL_SIZE - 1] = '\0'; printk(KERN_INFO "device label %s ", disk_super->label); - else + } else { printk(KERN_INFO "device fsid %pU ", disk_super->fsid); + } printk(KERN_CONT "devid %llu transid %llu %s\n", (unsigned long long)devid, (unsigned long long)transid, path); ret = device_list_add(path, disk_super, devid, fs_devices_ret); -- cgit v0.10.2 From e1f5790e0588bc5b11eb57f95bfde8702049dd0d Mon Sep 17 00:00:00 2001 From: Tsutomu Itoh Date: Thu, 8 Nov 2012 04:47:33 +0000 Subject: Btrfs: set hole punching time properly Even if the hole punching is executed, the modification time of the file is not updated. So, current time is set to inode. Signed-off-by: Tsutomu Itoh Signed-off-by: Chris Mason diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index d2df981..883cf82 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1964,6 +1964,9 @@ out_trans: if (!trans) goto out_free; + inode_inc_iversion(inode); + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + trans->block_rsv = &root->fs_info->trans_block_rsv; ret = btrfs_update_inode(trans, root, inode); nr = trans->blocks_used; -- cgit v0.10.2 From 3ef5969cd8a42a78ccdbc53f7abb2e6136b2ec65 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Thu, 8 Nov 2012 21:27:24 +0000 Subject: Btrfs: merge inode_list in __merge_refs When __merge_refs merges two refs, it is also needed to merge the inode_list of both refs. Otherwise we have missed backrefs and memory leaks. This happens for example if two inodes share an extent and both lie in the same leaf and thus also have the same parent. Signed-off-by: Alexander Block Reviewed-by: Jan Schmidt Signed-off-by: Chris Mason diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index a321952..04edf69 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -461,6 +461,7 @@ static int __merge_refs(struct list_head *head, int mode) pos2 = n2, n2 = pos2->next) { struct __prelim_ref *ref2; struct __prelim_ref *xchg; + struct extent_inode_elem *eie; ref2 = list_entry(pos2, struct __prelim_ref, list); @@ -472,12 +473,20 @@ static int __merge_refs(struct list_head *head, int mode) ref1 = ref2; ref2 = xchg; } - ref1->count += ref2->count; } else { if (ref1->parent != ref2->parent) continue; - ref1->count += ref2->count; } + + eie = ref1->inode_list; + while (eie && eie->next) + eie = eie->next; + if (eie) + eie->next = ref2->inode_list; + else + ref1->inode_list = ref2->inode_list; + ref1->count += ref2->count; + list_del(&ref2->list); kfree(ref2); } -- cgit v0.10.2 From b53d3f5db2b79637acadc06a330db6c2c60863f5 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 14 Nov 2012 14:34:34 +0000 Subject: Btrfs: cleanup for btrfs_btree_balance_dirty - 'nr' is no more used. - btrfs_btree_balance_dirty() and __btrfs_btree_balance_dirty() can share a bunch of code. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 0c6dca5..3483603 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1257,7 +1257,6 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work) struct btrfs_delayed_node *delayed_node = NULL; struct btrfs_root *root; struct btrfs_block_rsv *block_rsv; - unsigned long nr = 0; int need_requeue = 0; int ret; @@ -1318,11 +1317,9 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work) delayed_node); mutex_unlock(&delayed_node->mutex); - nr = trans->blocks_used; - trans->block_rsv = block_rsv; btrfs_end_transaction_dmeta(trans, root); - __btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty_nodelay(root); free_path: btrfs_free_path(path); out: diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 07a2162..ff5d259 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3411,7 +3411,8 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf) } } -void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) +static void __btrfs_btree_balance_dirty(struct btrfs_root *root, + int flush_delayed) { /* * looks as though older kernels can get into trouble with @@ -3423,7 +3424,8 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) if (current->flags & PF_MEMALLOC) return; - btrfs_balance_delayed_items(root); + if (flush_delayed) + btrfs_balance_delayed_items(root); num_dirty = root->fs_info->dirty_metadata_bytes; @@ -3434,25 +3436,14 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) return; } -void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) +void btrfs_btree_balance_dirty(struct btrfs_root *root) { - /* - * looks as though older kernels can get into trouble with - * this code, they end up stuck in balance_dirty_pages forever - */ - u64 num_dirty; - unsigned long thresh = 32 * 1024 * 1024; - - if (current->flags & PF_MEMALLOC) - return; - - num_dirty = root->fs_info->dirty_metadata_bytes; + __btrfs_btree_balance_dirty(root, 1); +} - if (num_dirty > thresh) { - balance_dirty_pages_ratelimited_nr( - root->fs_info->btree_inode->i_mapping, 1); - } - return; +void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root) +{ + __btrfs_btree_balance_dirty(root, 0); } int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid) diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 2025a91..305c33e 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -62,8 +62,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, struct btrfs_key *location); int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info); -void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); -void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr); +void btrfs_btree_balance_dirty(struct btrfs_root *root); +void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root); void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); void btrfs_mark_buffer_dirty(struct extent_buffer *buf); int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 883cf82..bd7f1b0 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1349,7 +1349,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, balance_dirty_pages_ratelimited_nr(inode->i_mapping, dirty_pages); if (dirty_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1) - btrfs_btree_balance_dirty(root, 1); + btrfs_btree_balance_dirty(root); pos += copied; num_written += copied; @@ -1803,7 +1803,6 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) u64 cur_offset = lockstart; u64 min_size = btrfs_calc_trunc_metadata_size(root, 1); u64 drop_end; - unsigned long nr; int ret = 0; int err = 0; bool same_page = (offset >> PAGE_CACHE_SHIFT) == @@ -1931,9 +1930,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) break; } - nr = trans->blocks_used; btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); trans = btrfs_start_transaction(root, 3); if (IS_ERR(trans)) { @@ -1969,9 +1967,8 @@ out_trans: trans->block_rsv = &root->fs_info->trans_block_rsv; ret = btrfs_update_inode(trans, root, inode); - nr = trans->blocks_used; btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); out_free: btrfs_free_path(path); btrfs_free_block_rsv(root, rsv); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e8733fa..aabf747 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3091,7 +3091,6 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) struct btrfs_trans_handle *trans; struct inode *inode = dentry->d_inode; int ret; - unsigned long nr = 0; trans = __unlink_start_trans(dir, dentry); if (IS_ERR(trans)) @@ -3111,9 +3110,8 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) } out: - nr = trans->blocks_used; __unlink_end_trans(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); return ret; } @@ -3203,7 +3201,6 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) int err = 0; struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_trans_handle *trans; - unsigned long nr = 0; if (inode->i_size > BTRFS_EMPTY_DIR_SIZE) return -ENOTEMPTY; @@ -3232,9 +3229,8 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) if (!err) btrfs_i_size_write(inode, 0); out: - nr = trans->blocks_used; __unlink_end_trans(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); return err; } @@ -3800,7 +3796,6 @@ void btrfs_evict_inode(struct inode *inode) struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_block_rsv *rsv, *global_rsv; u64 min_size = btrfs_calc_trunc_metadata_size(root, 1); - unsigned long nr; int ret; trace_btrfs_inode_evict(inode); @@ -3882,10 +3877,9 @@ void btrfs_evict_inode(struct inode *inode) ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); - nr = trans->blocks_used; btrfs_end_transaction(trans, root); trans = NULL; - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); } btrfs_free_block_rsv(root, rsv); @@ -3901,9 +3895,8 @@ void btrfs_evict_inode(struct inode *inode) root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID)) btrfs_return_ino(root, btrfs_ino(inode)); - nr = trans->blocks_used; btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); no_delete: clear_inode(inode); return; @@ -4915,7 +4908,6 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, int err; int drop_inode = 0; u64 objectid; - unsigned long nr = 0; u64 index = 0; if (!new_valid_dev(rdev)) @@ -4965,9 +4957,8 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, d_instantiate(dentry, inode); } out_unlock: - nr = trans->blocks_used; btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); if (drop_inode) { inode_dec_link_count(inode); iput(inode); @@ -4983,7 +4974,6 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; int drop_inode = 0; int err; - unsigned long nr = 0; u64 objectid; u64 index = 0; @@ -5033,13 +5023,12 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, d_instantiate(dentry, inode); } out_unlock: - nr = trans->blocks_used; btrfs_end_transaction(trans, root); if (drop_inode) { inode_dec_link_count(inode); iput(inode); } - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); return err; } @@ -5050,7 +5039,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, struct btrfs_root *root = BTRFS_I(dir)->root; struct inode *inode = old_dentry->d_inode; u64 index; - unsigned long nr = 0; int err; int drop_inode = 0; @@ -5094,14 +5082,13 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, btrfs_log_new_name(trans, inode, NULL, parent); } - nr = trans->blocks_used; btrfs_end_transaction(trans, root); fail: if (drop_inode) { inode_dec_link_count(inode); iput(inode); } - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); return err; } @@ -5114,7 +5101,6 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) int drop_on_err = 0; u64 objectid = 0; u64 index = 0; - unsigned long nr = 1; /* * 2 items for inode and ref @@ -5160,11 +5146,10 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) drop_on_err = 0; out_fail: - nr = trans->blocks_used; btrfs_end_transaction(trans, root); if (drop_on_err) iput(inode); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); return err; } @@ -6872,7 +6857,6 @@ static int btrfs_truncate(struct inode *inode) int ret; int err = 0; struct btrfs_trans_handle *trans; - unsigned long nr; u64 mask = root->sectorsize - 1; u64 min_size = btrfs_calc_trunc_metadata_size(root, 1); @@ -6995,9 +6979,8 @@ static int btrfs_truncate(struct inode *inode) break; } - nr = trans->blocks_used; btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); trans = btrfs_start_transaction(root, 2); if (IS_ERR(trans)) { @@ -7031,9 +7014,8 @@ static int btrfs_truncate(struct inode *inode) if (ret && !err) err = ret; - nr = trans->blocks_used; ret = btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); } out: @@ -7594,7 +7576,6 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, unsigned long ptr; struct btrfs_file_extent_item *ei; struct extent_buffer *leaf; - unsigned long nr = 0; name_len = strlen(symname) + 1; if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root)) @@ -7692,13 +7673,12 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, out_unlock: if (!err) d_instantiate(dentry, inode); - nr = trans->blocks_used; btrfs_end_transaction(trans, root); if (drop_inode) { inode_dec_link_count(inode); iput(inode); } - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); return err; } diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 270f24f..300e09a 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -2025,7 +2025,6 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, struct btrfs_root_item *root_item; struct btrfs_path *path; struct extent_buffer *leaf; - unsigned long nr; int level; int max_level; int replaced = 0; @@ -2126,10 +2125,9 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, path->slots[level]); root_item->drop_level = level; - nr = trans->blocks_used; btrfs_end_transaction_throttle(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); if (replaced && rc->stage == UPDATE_DATA_PTRS) invalidate_extent_cache(root, &key, &next_key); @@ -2156,10 +2154,9 @@ out: btrfs_update_reloc_root(trans, root); } - nr = trans->blocks_used; btrfs_end_transaction_throttle(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); if (replaced && rc->stage == UPDATE_DATA_PTRS) invalidate_extent_cache(root, &key, &next_key); @@ -3262,7 +3259,6 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info, struct btrfs_path *path; struct btrfs_root *root = fs_info->tree_root; struct btrfs_trans_handle *trans; - unsigned long nr; int ret = 0; if (inode) @@ -3296,9 +3292,8 @@ truncate: ret = btrfs_truncate_free_space_cache(root, trans, path, inode); btrfs_free_path(path); - nr = trans->blocks_used; btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); out: iput(inode); return ret; @@ -3715,7 +3710,6 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc) struct btrfs_trans_handle *trans = NULL; struct btrfs_path *path; struct btrfs_extent_item *ei; - unsigned long nr; u64 flags; u32 item_size; int ret; @@ -3832,9 +3826,8 @@ restart: ret = btrfs_commit_transaction(trans, rc->extent_root); BUG_ON(ret); } else { - nr = trans->blocks_used; btrfs_end_transaction_throttle(trans, rc->extent_root); - btrfs_btree_balance_dirty(rc->extent_root, nr); + btrfs_btree_balance_dirty(rc->extent_root); } trans = NULL; @@ -3864,9 +3857,8 @@ restart: GFP_NOFS); if (trans) { - nr = trans->blocks_used; btrfs_end_transaction_throttle(trans, rc->extent_root); - btrfs_btree_balance_dirty(rc->extent_root, nr); + btrfs_btree_balance_dirty(rc->extent_root); } if (!err) { @@ -3945,7 +3937,6 @@ struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info, struct btrfs_trans_handle *trans; struct btrfs_root *root; struct btrfs_key key; - unsigned long nr; u64 objectid = BTRFS_FIRST_FREE_OBJECTID; int err = 0; @@ -3973,9 +3964,8 @@ struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info, err = btrfs_orphan_add(trans, inode); out: - nr = trans->blocks_used; btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root, nr); + btrfs_btree_balance_dirty(root); if (err) { if (inode) iput(inode); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index f21f39f..7b29735 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -952,7 +952,6 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) struct btrfs_fs_info *info = root->fs_info; struct btrfs_trans_handle *trans; int ret; - unsigned long nr; if (xchg(&root->defrag_running, 1)) return 0; @@ -964,9 +963,8 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) ret = btrfs_defrag_leaves(trans, root, cacheonly); - nr = trans->blocks_used; btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(info->tree_root, nr); + btrfs_btree_balance_dirty(info->tree_root); cond_resched(); if (btrfs_fs_closing(root->fs_info) || ret != -EAGAIN) -- cgit v0.10.2 From d25628bdd66aedd6e07729d8dc6c8ee846d66d72 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 14 Nov 2012 14:35:30 +0000 Subject: Btrfs: protect devices list with its mutex Since we've kill the bigger one volume_mutex, we need to add devices list mutex back. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index db79fb7..92e586b 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1681,16 +1681,17 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) filemap_write_and_wait(bdev->bd_inode->i_mapping); devices = &root->fs_info->fs_devices->devices; - /* - * we have the volume lock, so we don't need the extra - * device list mutex while reading the list here. - */ + + mutex_lock(&root->fs_info->fs_devices->device_list_mutex); list_for_each_entry(device, devices, dev_list) { if (device->bdev == bdev) { ret = -EEXIST; + mutex_unlock( + &root->fs_info->fs_devices->device_list_mutex); goto error; } } + mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); device = kzalloc(sizeof(*device), GFP_NOFS); if (!device) { -- cgit v0.10.2 From d9d181c1ba7aa09a6d2698e8c7e75b515524d504 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Fri, 2 Nov 2012 09:58:09 +0100 Subject: Btrfs: rename the scrub context structure The device replace procedure makes use of the scrub code. The scrub code is the most efficient code to read the allocated data of a disk, i.e. it reads sequentially in order to avoid disk head movements, it skips unallocated blocks, it uses read ahead mechanisms, and it contains all the code to detect and repair defects. This commit is a first preparation step to adapt the scrub code to be shareable for the device replace procedure. The block device will be removed from the scrub context state structure in a later step. It used to be the source block device. The scrub code as it is used for the device replace procedure reads the source data from whereever it is optimal. The source device might even be gone (disconnected, for instance due to a hardware failure). Or the drive can be so faulty so that the device replace procedure tries to avoid access to the faulty source drive as much as possible, and only if all other mirrors are damaged, as a last resort, the source disk is accessed. The modified scrub code operates as if it would handle the source drive and thereby generates an exact copy of the source disk on the target disk, even if the source disk is not present at all. Therefore the block device pointer to the source disk is removed in a later patch, and therefore the context structure is renamed (this is the goal of the current patch) to reflect that no source block device scope is there anymore. Summary: This first preparation step consists of a textual substitution of the term "dev" to the term "ctx" whereever the scrub context is used. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 27892f6..29c8aac 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -42,10 +42,10 @@ */ struct scrub_block; -struct scrub_dev; +struct scrub_ctx; #define SCRUB_PAGES_PER_BIO 16 /* 64k per bio */ -#define SCRUB_BIOS_PER_DEV 16 /* 1 MB per device in flight */ +#define SCRUB_BIOS_PER_CTX 16 /* 1 MB per device in flight */ #define SCRUB_MAX_PAGES_PER_BLOCK 16 /* 64k per node/leaf/sector */ struct scrub_page { @@ -66,7 +66,7 @@ struct scrub_page { struct scrub_bio { int index; - struct scrub_dev *sdev; + struct scrub_ctx *sctx; struct bio *bio; int err; u64 logical; @@ -82,7 +82,7 @@ struct scrub_block { int page_count; atomic_t outstanding_pages; atomic_t ref_count; /* free mem on transition to zero */ - struct scrub_dev *sdev; + struct scrub_ctx *sctx; struct { unsigned int header_error:1; unsigned int checksum_error:1; @@ -91,8 +91,8 @@ struct scrub_block { }; }; -struct scrub_dev { - struct scrub_bio *bios[SCRUB_BIOS_PER_DEV]; +struct scrub_ctx { + struct scrub_bio *bios[SCRUB_BIOS_PER_CTX]; struct btrfs_device *dev; int first_free; int curr; @@ -116,7 +116,7 @@ struct scrub_dev { }; struct scrub_fixup_nodatasum { - struct scrub_dev *sdev; + struct scrub_ctx *sctx; u64 logical; struct btrfs_root *root; struct btrfs_work work; @@ -138,7 +138,7 @@ struct scrub_warning { static int scrub_handle_errored_block(struct scrub_block *sblock_to_check); -static int scrub_setup_recheck_block(struct scrub_dev *sdev, +static int scrub_setup_recheck_block(struct scrub_ctx *sctx, struct btrfs_mapping_tree *map_tree, u64 length, u64 logical, struct scrub_block *sblock); @@ -163,9 +163,9 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock); static int scrub_checksum_super(struct scrub_block *sblock); static void scrub_block_get(struct scrub_block *sblock); static void scrub_block_put(struct scrub_block *sblock); -static int scrub_add_page_to_bio(struct scrub_dev *sdev, +static int scrub_add_page_to_bio(struct scrub_ctx *sctx, struct scrub_page *spage); -static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len, +static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, u64 physical, u64 flags, u64 gen, int mirror_num, u8 *csum, int force); static void scrub_bio_end_io(struct bio *bio, int err); @@ -173,27 +173,27 @@ static void scrub_bio_end_io_worker(struct btrfs_work *work); static void scrub_block_complete(struct scrub_block *sblock); -static void scrub_free_csums(struct scrub_dev *sdev) +static void scrub_free_csums(struct scrub_ctx *sctx) { - while (!list_empty(&sdev->csum_list)) { + while (!list_empty(&sctx->csum_list)) { struct btrfs_ordered_sum *sum; - sum = list_first_entry(&sdev->csum_list, + sum = list_first_entry(&sctx->csum_list, struct btrfs_ordered_sum, list); list_del(&sum->list); kfree(sum); } } -static noinline_for_stack void scrub_free_dev(struct scrub_dev *sdev) +static noinline_for_stack void scrub_free_ctx(struct scrub_ctx *sctx) { int i; - if (!sdev) + if (!sctx) return; /* this can happen when scrub is cancelled */ - if (sdev->curr != -1) { - struct scrub_bio *sbio = sdev->bios[sdev->curr]; + if (sctx->curr != -1) { + struct scrub_bio *sbio = sctx->bios[sctx->curr]; for (i = 0; i < sbio->page_count; i++) { BUG_ON(!sbio->pagev[i]); @@ -203,69 +203,69 @@ static noinline_for_stack void scrub_free_dev(struct scrub_dev *sdev) bio_put(sbio->bio); } - for (i = 0; i < SCRUB_BIOS_PER_DEV; ++i) { - struct scrub_bio *sbio = sdev->bios[i]; + for (i = 0; i < SCRUB_BIOS_PER_CTX; ++i) { + struct scrub_bio *sbio = sctx->bios[i]; if (!sbio) break; kfree(sbio); } - scrub_free_csums(sdev); - kfree(sdev); + scrub_free_csums(sctx); + kfree(sctx); } static noinline_for_stack -struct scrub_dev *scrub_setup_dev(struct btrfs_device *dev) +struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev) { - struct scrub_dev *sdev; + struct scrub_ctx *sctx; int i; struct btrfs_fs_info *fs_info = dev->dev_root->fs_info; int pages_per_bio; pages_per_bio = min_t(int, SCRUB_PAGES_PER_BIO, bio_get_nr_vecs(dev->bdev)); - sdev = kzalloc(sizeof(*sdev), GFP_NOFS); - if (!sdev) + sctx = kzalloc(sizeof(*sctx), GFP_NOFS); + if (!sctx) goto nomem; - sdev->dev = dev; - sdev->pages_per_bio = pages_per_bio; - sdev->curr = -1; - for (i = 0; i < SCRUB_BIOS_PER_DEV; ++i) { + sctx->dev = dev; + sctx->pages_per_bio = pages_per_bio; + sctx->curr = -1; + for (i = 0; i < SCRUB_BIOS_PER_CTX; ++i) { struct scrub_bio *sbio; sbio = kzalloc(sizeof(*sbio), GFP_NOFS); if (!sbio) goto nomem; - sdev->bios[i] = sbio; + sctx->bios[i] = sbio; sbio->index = i; - sbio->sdev = sdev; + sbio->sctx = sctx; sbio->page_count = 0; sbio->work.func = scrub_bio_end_io_worker; - if (i != SCRUB_BIOS_PER_DEV-1) - sdev->bios[i]->next_free = i + 1; + if (i != SCRUB_BIOS_PER_CTX - 1) + sctx->bios[i]->next_free = i + 1; else - sdev->bios[i]->next_free = -1; - } - sdev->first_free = 0; - sdev->nodesize = dev->dev_root->nodesize; - sdev->leafsize = dev->dev_root->leafsize; - sdev->sectorsize = dev->dev_root->sectorsize; - atomic_set(&sdev->in_flight, 0); - atomic_set(&sdev->fixup_cnt, 0); - atomic_set(&sdev->cancel_req, 0); - sdev->csum_size = btrfs_super_csum_size(fs_info->super_copy); - INIT_LIST_HEAD(&sdev->csum_list); - - spin_lock_init(&sdev->list_lock); - spin_lock_init(&sdev->stat_lock); - init_waitqueue_head(&sdev->list_wait); - return sdev; + sctx->bios[i]->next_free = -1; + } + sctx->first_free = 0; + sctx->nodesize = dev->dev_root->nodesize; + sctx->leafsize = dev->dev_root->leafsize; + sctx->sectorsize = dev->dev_root->sectorsize; + atomic_set(&sctx->in_flight, 0); + atomic_set(&sctx->fixup_cnt, 0); + atomic_set(&sctx->cancel_req, 0); + sctx->csum_size = btrfs_super_csum_size(fs_info->super_copy); + INIT_LIST_HEAD(&sctx->csum_list); + + spin_lock_init(&sctx->list_lock); + spin_lock_init(&sctx->stat_lock); + init_waitqueue_head(&sctx->list_wait); + return sctx; nomem: - scrub_free_dev(sdev); + scrub_free_ctx(sctx); return ERR_PTR(-ENOMEM); } @@ -345,7 +345,7 @@ err: static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) { - struct btrfs_device *dev = sblock->sdev->dev; + struct btrfs_device *dev = sblock->sctx->dev; struct btrfs_fs_info *fs_info = dev->dev_root->fs_info; struct btrfs_path *path; struct btrfs_key found_key; @@ -530,21 +530,21 @@ static void scrub_fixup_nodatasum(struct btrfs_work *work) { int ret; struct scrub_fixup_nodatasum *fixup; - struct scrub_dev *sdev; + struct scrub_ctx *sctx; struct btrfs_trans_handle *trans = NULL; struct btrfs_fs_info *fs_info; struct btrfs_path *path; int uncorrectable = 0; fixup = container_of(work, struct scrub_fixup_nodatasum, work); - sdev = fixup->sdev; + sctx = fixup->sctx; fs_info = fixup->root->fs_info; path = btrfs_alloc_path(); if (!path) { - spin_lock(&sdev->stat_lock); - ++sdev->stat.malloc_errors; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + ++sctx->stat.malloc_errors; + spin_unlock(&sctx->stat_lock); uncorrectable = 1; goto out; } @@ -573,22 +573,22 @@ static void scrub_fixup_nodatasum(struct btrfs_work *work) } WARN_ON(ret != 1); - spin_lock(&sdev->stat_lock); - ++sdev->stat.corrected_errors; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + ++sctx->stat.corrected_errors; + spin_unlock(&sctx->stat_lock); out: if (trans && !IS_ERR(trans)) btrfs_end_transaction(trans, fixup->root); if (uncorrectable) { - spin_lock(&sdev->stat_lock); - ++sdev->stat.uncorrectable_errors; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + ++sctx->stat.uncorrectable_errors; + spin_unlock(&sctx->stat_lock); printk_ratelimited_in_rcu(KERN_ERR "btrfs: unable to fixup (nodatasum) error at logical %llu on dev %s\n", (unsigned long long)fixup->logical, - rcu_str_deref(sdev->dev->name)); + rcu_str_deref(sctx->dev->name)); } btrfs_free_path(path); @@ -599,9 +599,9 @@ out: atomic_dec(&fs_info->scrubs_running); atomic_dec(&fs_info->scrubs_paused); mutex_unlock(&fs_info->scrub_lock); - atomic_dec(&sdev->fixup_cnt); + atomic_dec(&sctx->fixup_cnt); wake_up(&fs_info->scrub_pause_wait); - wake_up(&sdev->list_wait); + wake_up(&sctx->list_wait); } /* @@ -614,7 +614,7 @@ out: */ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) { - struct scrub_dev *sdev = sblock_to_check->sdev; + struct scrub_ctx *sctx = sblock_to_check->sctx; struct btrfs_fs_info *fs_info; u64 length; u64 logical; @@ -633,7 +633,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) DEFAULT_RATELIMIT_BURST); BUG_ON(sblock_to_check->page_count < 1); - fs_info = sdev->dev->dev_root->fs_info; + fs_info = sctx->dev->dev_root->fs_info; length = sblock_to_check->page_count * PAGE_SIZE; logical = sblock_to_check->pagev[0].logical; generation = sblock_to_check->pagev[0].generation; @@ -677,25 +677,25 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) sizeof(*sblocks_for_recheck), GFP_NOFS); if (!sblocks_for_recheck) { - spin_lock(&sdev->stat_lock); - sdev->stat.malloc_errors++; - sdev->stat.read_errors++; - sdev->stat.uncorrectable_errors++; - spin_unlock(&sdev->stat_lock); - btrfs_dev_stat_inc_and_print(sdev->dev, + spin_lock(&sctx->stat_lock); + sctx->stat.malloc_errors++; + sctx->stat.read_errors++; + sctx->stat.uncorrectable_errors++; + spin_unlock(&sctx->stat_lock); + btrfs_dev_stat_inc_and_print(sctx->dev, BTRFS_DEV_STAT_READ_ERRS); goto out; } /* setup the context, map the logical blocks and alloc the pages */ - ret = scrub_setup_recheck_block(sdev, &fs_info->mapping_tree, length, + ret = scrub_setup_recheck_block(sctx, &fs_info->mapping_tree, length, logical, sblocks_for_recheck); if (ret) { - spin_lock(&sdev->stat_lock); - sdev->stat.read_errors++; - sdev->stat.uncorrectable_errors++; - spin_unlock(&sdev->stat_lock); - btrfs_dev_stat_inc_and_print(sdev->dev, + spin_lock(&sctx->stat_lock); + sctx->stat.read_errors++; + sctx->stat.uncorrectable_errors++; + spin_unlock(&sctx->stat_lock); + btrfs_dev_stat_inc_and_print(sctx->dev, BTRFS_DEV_STAT_READ_ERRS); goto out; } @@ -704,13 +704,13 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) /* build and submit the bios for the failed mirror, check checksums */ ret = scrub_recheck_block(fs_info, sblock_bad, is_metadata, have_csum, - csum, generation, sdev->csum_size); + csum, generation, sctx->csum_size); if (ret) { - spin_lock(&sdev->stat_lock); - sdev->stat.read_errors++; - sdev->stat.uncorrectable_errors++; - spin_unlock(&sdev->stat_lock); - btrfs_dev_stat_inc_and_print(sdev->dev, + spin_lock(&sctx->stat_lock); + sctx->stat.read_errors++; + sctx->stat.uncorrectable_errors++; + spin_unlock(&sctx->stat_lock); + btrfs_dev_stat_inc_and_print(sctx->dev, BTRFS_DEV_STAT_READ_ERRS); goto out; } @@ -725,45 +725,45 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) * different bio (usually one of the two latter cases is * the cause) */ - spin_lock(&sdev->stat_lock); - sdev->stat.unverified_errors++; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + sctx->stat.unverified_errors++; + spin_unlock(&sctx->stat_lock); goto out; } if (!sblock_bad->no_io_error_seen) { - spin_lock(&sdev->stat_lock); - sdev->stat.read_errors++; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + sctx->stat.read_errors++; + spin_unlock(&sctx->stat_lock); if (__ratelimit(&_rs)) scrub_print_warning("i/o error", sblock_to_check); - btrfs_dev_stat_inc_and_print(sdev->dev, + btrfs_dev_stat_inc_and_print(sctx->dev, BTRFS_DEV_STAT_READ_ERRS); } else if (sblock_bad->checksum_error) { - spin_lock(&sdev->stat_lock); - sdev->stat.csum_errors++; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + sctx->stat.csum_errors++; + spin_unlock(&sctx->stat_lock); if (__ratelimit(&_rs)) scrub_print_warning("checksum error", sblock_to_check); - btrfs_dev_stat_inc_and_print(sdev->dev, + btrfs_dev_stat_inc_and_print(sctx->dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); } else if (sblock_bad->header_error) { - spin_lock(&sdev->stat_lock); - sdev->stat.verify_errors++; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + sctx->stat.verify_errors++; + spin_unlock(&sctx->stat_lock); if (__ratelimit(&_rs)) scrub_print_warning("checksum/header error", sblock_to_check); if (sblock_bad->generation_error) - btrfs_dev_stat_inc_and_print(sdev->dev, + btrfs_dev_stat_inc_and_print(sctx->dev, BTRFS_DEV_STAT_GENERATION_ERRS); else - btrfs_dev_stat_inc_and_print(sdev->dev, + btrfs_dev_stat_inc_and_print(sctx->dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); } - if (sdev->readonly) + if (sctx->readonly) goto did_not_correct_error; if (!is_metadata && !have_csum) { @@ -779,7 +779,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) fixup_nodatasum = kzalloc(sizeof(*fixup_nodatasum), GFP_NOFS); if (!fixup_nodatasum) goto did_not_correct_error; - fixup_nodatasum->sdev = sdev; + fixup_nodatasum->sctx = sctx; fixup_nodatasum->logical = logical; fixup_nodatasum->root = fs_info->extent_root; fixup_nodatasum->mirror_num = failed_mirror_index + 1; @@ -796,7 +796,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) atomic_inc(&fs_info->scrubs_running); atomic_inc(&fs_info->scrubs_paused); mutex_unlock(&fs_info->scrub_lock); - atomic_inc(&sdev->fixup_cnt); + atomic_inc(&sctx->fixup_cnt); fixup_nodatasum->work.func = scrub_fixup_nodatasum; btrfs_queue_worker(&fs_info->scrub_workers, &fixup_nodatasum->work); @@ -818,7 +818,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) ret = scrub_recheck_block(fs_info, sblocks_for_recheck + mirror_index, is_metadata, have_csum, csum, - generation, sdev->csum_size); + generation, sctx->csum_size); if (ret) goto did_not_correct_error; } @@ -930,7 +930,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) */ ret = scrub_recheck_block(fs_info, sblock_bad, is_metadata, have_csum, csum, - generation, sdev->csum_size); + generation, sctx->csum_size); if (!ret && !sblock_bad->header_error && !sblock_bad->checksum_error && sblock_bad->no_io_error_seen) @@ -939,23 +939,23 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) goto did_not_correct_error; } else { corrected_error: - spin_lock(&sdev->stat_lock); - sdev->stat.corrected_errors++; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + sctx->stat.corrected_errors++; + spin_unlock(&sctx->stat_lock); printk_ratelimited_in_rcu(KERN_ERR "btrfs: fixed up error at logical %llu on dev %s\n", (unsigned long long)logical, - rcu_str_deref(sdev->dev->name)); + rcu_str_deref(sctx->dev->name)); } } else { did_not_correct_error: - spin_lock(&sdev->stat_lock); - sdev->stat.uncorrectable_errors++; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + sctx->stat.uncorrectable_errors++; + spin_unlock(&sctx->stat_lock); printk_ratelimited_in_rcu(KERN_ERR "btrfs: unable to fixup (regular) error at logical %llu on dev %s\n", (unsigned long long)logical, - rcu_str_deref(sdev->dev->name)); + rcu_str_deref(sctx->dev->name)); } out: @@ -978,7 +978,7 @@ out: return 0; } -static int scrub_setup_recheck_block(struct scrub_dev *sdev, +static int scrub_setup_recheck_block(struct scrub_ctx *sctx, struct btrfs_mapping_tree *map_tree, u64 length, u64 logical, struct scrub_block *sblocks_for_recheck) @@ -988,7 +988,7 @@ static int scrub_setup_recheck_block(struct scrub_dev *sdev, int ret; /* - * note: the three members sdev, ref_count and outstanding_pages + * note: the three members sctx, ref_count and outstanding_pages * are not used (and not set) in the blocks that are used for * the recheck procedure */ @@ -1028,9 +1028,9 @@ static int scrub_setup_recheck_block(struct scrub_dev *sdev, page->mirror_num = mirror_index + 1; page->page = alloc_page(GFP_NOFS); if (!page->page) { - spin_lock(&sdev->stat_lock); - sdev->stat.malloc_errors++; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + sctx->stat.malloc_errors++; + spin_unlock(&sctx->stat_lock); kfree(bbio); return -ENOMEM; } @@ -1259,14 +1259,14 @@ static void scrub_checksum(struct scrub_block *sblock) static int scrub_checksum_data(struct scrub_block *sblock) { - struct scrub_dev *sdev = sblock->sdev; + struct scrub_ctx *sctx = sblock->sctx; u8 csum[BTRFS_CSUM_SIZE]; u8 *on_disk_csum; struct page *page; void *buffer; u32 crc = ~(u32)0; int fail = 0; - struct btrfs_root *root = sdev->dev->dev_root; + struct btrfs_root *root = sctx->dev->dev_root; u64 len; int index; @@ -1278,7 +1278,7 @@ static int scrub_checksum_data(struct scrub_block *sblock) page = sblock->pagev[0].page; buffer = kmap_atomic(page); - len = sdev->sectorsize; + len = sctx->sectorsize; index = 0; for (;;) { u64 l = min_t(u64, len, PAGE_SIZE); @@ -1296,7 +1296,7 @@ static int scrub_checksum_data(struct scrub_block *sblock) } btrfs_csum_final(crc, csum); - if (memcmp(csum, on_disk_csum, sdev->csum_size)) + if (memcmp(csum, on_disk_csum, sctx->csum_size)) fail = 1; return fail; @@ -1304,9 +1304,9 @@ static int scrub_checksum_data(struct scrub_block *sblock) static int scrub_checksum_tree_block(struct scrub_block *sblock) { - struct scrub_dev *sdev = sblock->sdev; + struct scrub_ctx *sctx = sblock->sctx; struct btrfs_header *h; - struct btrfs_root *root = sdev->dev->dev_root; + struct btrfs_root *root = sctx->dev->dev_root; struct btrfs_fs_info *fs_info = root->fs_info; u8 calculated_csum[BTRFS_CSUM_SIZE]; u8 on_disk_csum[BTRFS_CSUM_SIZE]; @@ -1324,7 +1324,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) page = sblock->pagev[0].page; mapped_buffer = kmap_atomic(page); h = (struct btrfs_header *)mapped_buffer; - memcpy(on_disk_csum, h->csum, sdev->csum_size); + memcpy(on_disk_csum, h->csum, sctx->csum_size); /* * we don't use the getter functions here, as we @@ -1345,8 +1345,8 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) BTRFS_UUID_SIZE)) ++fail; - BUG_ON(sdev->nodesize != sdev->leafsize); - len = sdev->nodesize - BTRFS_CSUM_SIZE; + BUG_ON(sctx->nodesize != sctx->leafsize); + len = sctx->nodesize - BTRFS_CSUM_SIZE; mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE; p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE; index = 0; @@ -1368,7 +1368,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) } btrfs_csum_final(crc, calculated_csum); - if (memcmp(calculated_csum, on_disk_csum, sdev->csum_size)) + if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size)) ++crc_fail; return fail || crc_fail; @@ -1377,8 +1377,8 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) static int scrub_checksum_super(struct scrub_block *sblock) { struct btrfs_super_block *s; - struct scrub_dev *sdev = sblock->sdev; - struct btrfs_root *root = sdev->dev->dev_root; + struct scrub_ctx *sctx = sblock->sctx; + struct btrfs_root *root = sctx->dev->dev_root; struct btrfs_fs_info *fs_info = root->fs_info; u8 calculated_csum[BTRFS_CSUM_SIZE]; u8 on_disk_csum[BTRFS_CSUM_SIZE]; @@ -1396,7 +1396,7 @@ static int scrub_checksum_super(struct scrub_block *sblock) page = sblock->pagev[0].page; mapped_buffer = kmap_atomic(page); s = (struct btrfs_super_block *)mapped_buffer; - memcpy(on_disk_csum, s->csum, sdev->csum_size); + memcpy(on_disk_csum, s->csum, sctx->csum_size); if (sblock->pagev[0].logical != le64_to_cpu(s->bytenr)) ++fail_cor; @@ -1429,7 +1429,7 @@ static int scrub_checksum_super(struct scrub_block *sblock) } btrfs_csum_final(crc, calculated_csum); - if (memcmp(calculated_csum, on_disk_csum, sdev->csum_size)) + if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size)) ++fail_cor; if (fail_cor + fail_gen) { @@ -1438,14 +1438,14 @@ static int scrub_checksum_super(struct scrub_block *sblock) * They will get written with the next transaction commit * anyway */ - spin_lock(&sdev->stat_lock); - ++sdev->stat.super_errors; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + ++sctx->stat.super_errors; + spin_unlock(&sctx->stat_lock); if (fail_cor) - btrfs_dev_stat_inc_and_print(sdev->dev, + btrfs_dev_stat_inc_and_print(sctx->dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); else - btrfs_dev_stat_inc_and_print(sdev->dev, + btrfs_dev_stat_inc_and_print(sctx->dev, BTRFS_DEV_STAT_GENERATION_ERRS); } @@ -1469,21 +1469,21 @@ static void scrub_block_put(struct scrub_block *sblock) } } -static void scrub_submit(struct scrub_dev *sdev) +static void scrub_submit(struct scrub_ctx *sctx) { struct scrub_bio *sbio; - if (sdev->curr == -1) + if (sctx->curr == -1) return; - sbio = sdev->bios[sdev->curr]; - sdev->curr = -1; - atomic_inc(&sdev->in_flight); + sbio = sctx->bios[sctx->curr]; + sctx->curr = -1; + atomic_inc(&sctx->in_flight); btrfsic_submit_bio(READ, sbio->bio); } -static int scrub_add_page_to_bio(struct scrub_dev *sdev, +static int scrub_add_page_to_bio(struct scrub_ctx *sctx, struct scrub_page *spage) { struct scrub_block *sblock = spage->sblock; @@ -1494,20 +1494,20 @@ again: /* * grab a fresh bio or wait for one to become available */ - while (sdev->curr == -1) { - spin_lock(&sdev->list_lock); - sdev->curr = sdev->first_free; - if (sdev->curr != -1) { - sdev->first_free = sdev->bios[sdev->curr]->next_free; - sdev->bios[sdev->curr]->next_free = -1; - sdev->bios[sdev->curr]->page_count = 0; - spin_unlock(&sdev->list_lock); + while (sctx->curr == -1) { + spin_lock(&sctx->list_lock); + sctx->curr = sctx->first_free; + if (sctx->curr != -1) { + sctx->first_free = sctx->bios[sctx->curr]->next_free; + sctx->bios[sctx->curr]->next_free = -1; + sctx->bios[sctx->curr]->page_count = 0; + spin_unlock(&sctx->list_lock); } else { - spin_unlock(&sdev->list_lock); - wait_event(sdev->list_wait, sdev->first_free != -1); + spin_unlock(&sctx->list_lock); + wait_event(sctx->list_wait, sctx->first_free != -1); } } - sbio = sdev->bios[sdev->curr]; + sbio = sctx->bios[sctx->curr]; if (sbio->page_count == 0) { struct bio *bio; @@ -1515,7 +1515,7 @@ again: sbio->logical = spage->logical; bio = sbio->bio; if (!bio) { - bio = bio_alloc(GFP_NOFS, sdev->pages_per_bio); + bio = bio_alloc(GFP_NOFS, sctx->pages_per_bio); if (!bio) return -ENOMEM; sbio->bio = bio; @@ -1523,14 +1523,14 @@ again: bio->bi_private = sbio; bio->bi_end_io = scrub_bio_end_io; - bio->bi_bdev = sdev->dev->bdev; + bio->bi_bdev = sctx->dev->bdev; bio->bi_sector = spage->physical >> 9; sbio->err = 0; } else if (sbio->physical + sbio->page_count * PAGE_SIZE != spage->physical || sbio->logical + sbio->page_count * PAGE_SIZE != spage->logical) { - scrub_submit(sdev); + scrub_submit(sctx); goto again; } @@ -1542,20 +1542,20 @@ again: sbio->bio = NULL; return -EIO; } - scrub_submit(sdev); + scrub_submit(sctx); goto again; } scrub_block_get(sblock); /* one for the added page */ atomic_inc(&sblock->outstanding_pages); sbio->page_count++; - if (sbio->page_count == sdev->pages_per_bio) - scrub_submit(sdev); + if (sbio->page_count == sctx->pages_per_bio) + scrub_submit(sctx); return 0; } -static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len, +static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, u64 physical, u64 flags, u64 gen, int mirror_num, u8 *csum, int force) { @@ -1564,15 +1564,15 @@ static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len, sblock = kzalloc(sizeof(*sblock), GFP_NOFS); if (!sblock) { - spin_lock(&sdev->stat_lock); - sdev->stat.malloc_errors++; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + sctx->stat.malloc_errors++; + spin_unlock(&sctx->stat_lock); return -ENOMEM; } /* one ref inside this function, plus one for each page later on */ atomic_set(&sblock->ref_count, 1); - sblock->sdev = sdev; + sblock->sctx = sctx; sblock->no_io_error_seen = 1; for (index = 0; len > 0; index++) { @@ -1582,9 +1582,9 @@ static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len, BUG_ON(index >= SCRUB_MAX_PAGES_PER_BLOCK); spage->page = alloc_page(GFP_NOFS); if (!spage->page) { - spin_lock(&sdev->stat_lock); - sdev->stat.malloc_errors++; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + sctx->stat.malloc_errors++; + spin_unlock(&sctx->stat_lock); while (index > 0) { index--; __free_page(sblock->pagev[index].page); @@ -1593,7 +1593,7 @@ static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len, return -ENOMEM; } spage->sblock = sblock; - spage->dev = sdev->dev; + spage->dev = sctx->dev; spage->flags = flags; spage->generation = gen; spage->logical = logical; @@ -1601,7 +1601,7 @@ static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len, spage->mirror_num = mirror_num; if (csum) { spage->have_csum = 1; - memcpy(spage->csum, csum, sdev->csum_size); + memcpy(spage->csum, csum, sctx->csum_size); } else { spage->have_csum = 0; } @@ -1616,7 +1616,7 @@ static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len, struct scrub_page *spage = sblock->pagev + index; int ret; - ret = scrub_add_page_to_bio(sdev, spage); + ret = scrub_add_page_to_bio(sctx, spage); if (ret) { scrub_block_put(sblock); return ret; @@ -1624,7 +1624,7 @@ static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len, } if (force) - scrub_submit(sdev); + scrub_submit(sctx); /* last one frees, either here or in bio completion for last page */ scrub_block_put(sblock); @@ -1634,8 +1634,8 @@ static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len, static void scrub_bio_end_io(struct bio *bio, int err) { struct scrub_bio *sbio = bio->bi_private; - struct scrub_dev *sdev = sbio->sdev; - struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info; + struct scrub_ctx *sctx = sbio->sctx; + struct btrfs_fs_info *fs_info = sctx->dev->dev_root->fs_info; sbio->err = err; sbio->bio = bio; @@ -1646,7 +1646,7 @@ static void scrub_bio_end_io(struct bio *bio, int err) static void scrub_bio_end_io_worker(struct btrfs_work *work) { struct scrub_bio *sbio = container_of(work, struct scrub_bio, work); - struct scrub_dev *sdev = sbio->sdev; + struct scrub_ctx *sctx = sbio->sctx; int i; BUG_ON(sbio->page_count > SCRUB_PAGES_PER_BIO); @@ -1671,12 +1671,12 @@ static void scrub_bio_end_io_worker(struct btrfs_work *work) bio_put(sbio->bio); sbio->bio = NULL; - spin_lock(&sdev->list_lock); - sbio->next_free = sdev->first_free; - sdev->first_free = sbio->index; - spin_unlock(&sdev->list_lock); - atomic_dec(&sdev->in_flight); - wake_up(&sdev->list_wait); + spin_lock(&sctx->list_lock); + sbio->next_free = sctx->first_free; + sctx->first_free = sbio->index; + spin_unlock(&sctx->list_lock); + atomic_dec(&sctx->in_flight); + wake_up(&sctx->list_wait); } static void scrub_block_complete(struct scrub_block *sblock) @@ -1687,7 +1687,7 @@ static void scrub_block_complete(struct scrub_block *sblock) scrub_checksum(sblock); } -static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len, +static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u64 len, u8 *csum) { struct btrfs_ordered_sum *sum = NULL; @@ -1695,15 +1695,15 @@ static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len, unsigned long i; unsigned long num_sectors; - while (!list_empty(&sdev->csum_list)) { - sum = list_first_entry(&sdev->csum_list, + while (!list_empty(&sctx->csum_list)) { + sum = list_first_entry(&sctx->csum_list, struct btrfs_ordered_sum, list); if (sum->bytenr > logical) return 0; if (sum->bytenr + sum->len > logical) break; - ++sdev->stat.csum_discards; + ++sctx->stat.csum_discards; list_del(&sum->list); kfree(sum); sum = NULL; @@ -1711,10 +1711,10 @@ static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len, if (!sum) return 0; - num_sectors = sum->len / sdev->sectorsize; + num_sectors = sum->len / sctx->sectorsize; for (i = 0; i < num_sectors; ++i) { if (sum->sums[i].bytenr == logical) { - memcpy(csum, &sum->sums[i].sum, sdev->csum_size); + memcpy(csum, &sum->sums[i].sum, sctx->csum_size); ret = 1; break; } @@ -1727,7 +1727,7 @@ static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len, } /* scrub extent tries to collect up to 64 kB for each bio */ -static int scrub_extent(struct scrub_dev *sdev, u64 logical, u64 len, +static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, u64 physical, u64 flags, u64 gen, int mirror_num) { int ret; @@ -1735,20 +1735,20 @@ static int scrub_extent(struct scrub_dev *sdev, u64 logical, u64 len, u32 blocksize; if (flags & BTRFS_EXTENT_FLAG_DATA) { - blocksize = sdev->sectorsize; - spin_lock(&sdev->stat_lock); - sdev->stat.data_extents_scrubbed++; - sdev->stat.data_bytes_scrubbed += len; - spin_unlock(&sdev->stat_lock); + blocksize = sctx->sectorsize; + spin_lock(&sctx->stat_lock); + sctx->stat.data_extents_scrubbed++; + sctx->stat.data_bytes_scrubbed += len; + spin_unlock(&sctx->stat_lock); } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { - BUG_ON(sdev->nodesize != sdev->leafsize); - blocksize = sdev->nodesize; - spin_lock(&sdev->stat_lock); - sdev->stat.tree_extents_scrubbed++; - sdev->stat.tree_bytes_scrubbed += len; - spin_unlock(&sdev->stat_lock); + BUG_ON(sctx->nodesize != sctx->leafsize); + blocksize = sctx->nodesize; + spin_lock(&sctx->stat_lock); + sctx->stat.tree_extents_scrubbed++; + sctx->stat.tree_bytes_scrubbed += len; + spin_unlock(&sctx->stat_lock); } else { - blocksize = sdev->sectorsize; + blocksize = sctx->sectorsize; BUG_ON(1); } @@ -1758,11 +1758,11 @@ static int scrub_extent(struct scrub_dev *sdev, u64 logical, u64 len, if (flags & BTRFS_EXTENT_FLAG_DATA) { /* push csums to sbio */ - have_csum = scrub_find_csum(sdev, logical, l, csum); + have_csum = scrub_find_csum(sctx, logical, l, csum); if (have_csum == 0) - ++sdev->stat.no_csum; + ++sctx->stat.no_csum; } - ret = scrub_pages(sdev, logical, l, physical, flags, gen, + ret = scrub_pages(sctx, logical, l, physical, flags, gen, mirror_num, have_csum ? csum : NULL, 0); if (ret) return ret; @@ -1773,11 +1773,11 @@ static int scrub_extent(struct scrub_dev *sdev, u64 logical, u64 len, return 0; } -static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, +static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, struct map_lookup *map, int num, u64 base, u64 length) { struct btrfs_path *path; - struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info; + struct btrfs_fs_info *fs_info = sctx->dev->dev_root->fs_info; struct btrfs_root *root = fs_info->extent_root; struct btrfs_root *csum_root = fs_info->csum_root; struct btrfs_extent_item *extent; @@ -1843,8 +1843,8 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, */ logical = base + offset; - wait_event(sdev->list_wait, - atomic_read(&sdev->in_flight) == 0); + wait_event(sctx->list_wait, + atomic_read(&sctx->in_flight) == 0); atomic_inc(&fs_info->scrubs_paused); wake_up(&fs_info->scrub_pause_wait); @@ -1898,7 +1898,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, * canceled? */ if (atomic_read(&fs_info->scrub_cancel_req) || - atomic_read(&sdev->cancel_req)) { + atomic_read(&sctx->cancel_req)) { ret = -ECANCELED; goto out; } @@ -1907,9 +1907,9 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, */ if (atomic_read(&fs_info->scrub_pause_req)) { /* push queued extents */ - scrub_submit(sdev); - wait_event(sdev->list_wait, - atomic_read(&sdev->in_flight) == 0); + scrub_submit(sctx); + wait_event(sctx->list_wait, + atomic_read(&sctx->in_flight) == 0); atomic_inc(&fs_info->scrubs_paused); wake_up(&fs_info->scrub_pause_wait); mutex_lock(&fs_info->scrub_lock); @@ -1926,7 +1926,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, ret = btrfs_lookup_csums_range(csum_root, logical, logical + map->stripe_len - 1, - &sdev->csum_list, 1); + &sctx->csum_list, 1); if (ret) goto out; @@ -2004,7 +2004,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev, key.objectid; } - ret = scrub_extent(sdev, key.objectid, key.offset, + ret = scrub_extent(sctx, key.objectid, key.offset, key.objectid - logical + physical, flags, generation, mirror_num); if (ret) @@ -2016,12 +2016,12 @@ next: btrfs_release_path(path); logical += increment; physical += map->stripe_len; - spin_lock(&sdev->stat_lock); - sdev->stat.last_physical = physical; - spin_unlock(&sdev->stat_lock); + spin_lock(&sctx->stat_lock); + sctx->stat.last_physical = physical; + spin_unlock(&sctx->stat_lock); } /* push queued extents */ - scrub_submit(sdev); + scrub_submit(sctx); out: blk_finish_plug(&plug); @@ -2029,12 +2029,12 @@ out: return ret < 0 ? ret : 0; } -static noinline_for_stack int scrub_chunk(struct scrub_dev *sdev, +static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 length, u64 dev_offset) { struct btrfs_mapping_tree *map_tree = - &sdev->dev->dev_root->fs_info->mapping_tree; + &sctx->dev->dev_root->fs_info->mapping_tree; struct map_lookup *map; struct extent_map *em; int i; @@ -2055,9 +2055,9 @@ static noinline_for_stack int scrub_chunk(struct scrub_dev *sdev, goto out; for (i = 0; i < map->num_stripes; ++i) { - if (map->stripes[i].dev == sdev->dev && + if (map->stripes[i].dev == sctx->dev && map->stripes[i].physical == dev_offset) { - ret = scrub_stripe(sdev, map, i, chunk_offset, length); + ret = scrub_stripe(sctx, map, i, chunk_offset, length); if (ret) goto out; } @@ -2069,11 +2069,11 @@ out: } static noinline_for_stack -int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end) +int scrub_enumerate_chunks(struct scrub_ctx *sctx, u64 start, u64 end) { struct btrfs_dev_extent *dev_extent = NULL; struct btrfs_path *path; - struct btrfs_root *root = sdev->dev->dev_root; + struct btrfs_root *root = sctx->dev->dev_root; struct btrfs_fs_info *fs_info = root->fs_info; u64 length; u64 chunk_tree; @@ -2094,7 +2094,7 @@ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end) path->search_commit_root = 1; path->skip_locking = 1; - key.objectid = sdev->dev->devid; + key.objectid = sctx->dev->devid; key.offset = 0ull; key.type = BTRFS_DEV_EXTENT_KEY; @@ -2117,7 +2117,7 @@ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end) btrfs_item_key_to_cpu(l, &found_key, slot); - if (found_key.objectid != sdev->dev->devid) + if (found_key.objectid != sctx->dev->devid) break; if (btrfs_key_type(&found_key) != BTRFS_DEV_EXTENT_KEY) @@ -2151,7 +2151,7 @@ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end) ret = -ENOENT; break; } - ret = scrub_chunk(sdev, chunk_tree, chunk_objectid, + ret = scrub_chunk(sctx, chunk_tree, chunk_objectid, chunk_offset, length, found_key.offset); btrfs_put_block_group(cache); if (ret) @@ -2170,13 +2170,13 @@ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end) return ret < 0 ? ret : 0; } -static noinline_for_stack int scrub_supers(struct scrub_dev *sdev) +static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx) { int i; u64 bytenr; u64 gen; int ret; - struct btrfs_device *device = sdev->dev; + struct btrfs_device *device = sctx->dev; struct btrfs_root *root = device->dev_root; if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) @@ -2189,12 +2189,12 @@ static noinline_for_stack int scrub_supers(struct scrub_dev *sdev) if (bytenr + BTRFS_SUPER_INFO_SIZE > device->total_bytes) break; - ret = scrub_pages(sdev, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr, + ret = scrub_pages(sctx, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr, BTRFS_EXTENT_FLAG_SUPER, gen, i, NULL, 1); if (ret) return ret; } - wait_event(sdev->list_wait, atomic_read(&sdev->in_flight) == 0); + wait_event(sctx->list_wait, atomic_read(&sctx->in_flight) == 0); return 0; } @@ -2238,7 +2238,7 @@ static noinline_for_stack void scrub_workers_put(struct btrfs_root *root) int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, struct btrfs_scrub_progress *progress, int readonly) { - struct scrub_dev *sdev; + struct scrub_ctx *sctx; struct btrfs_fs_info *fs_info = root->fs_info; int ret; struct btrfs_device *dev; @@ -2302,41 +2302,41 @@ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, scrub_workers_put(root); return -EINPROGRESS; } - sdev = scrub_setup_dev(dev); - if (IS_ERR(sdev)) { + sctx = scrub_setup_ctx(dev); + if (IS_ERR(sctx)) { mutex_unlock(&fs_info->scrub_lock); mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); scrub_workers_put(root); - return PTR_ERR(sdev); + return PTR_ERR(sctx); } - sdev->readonly = readonly; - dev->scrub_device = sdev; + sctx->readonly = readonly; + dev->scrub_device = sctx; atomic_inc(&fs_info->scrubs_running); mutex_unlock(&fs_info->scrub_lock); mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); down_read(&fs_info->scrub_super_lock); - ret = scrub_supers(sdev); + ret = scrub_supers(sctx); up_read(&fs_info->scrub_super_lock); if (!ret) - ret = scrub_enumerate_chunks(sdev, start, end); + ret = scrub_enumerate_chunks(sctx, start, end); - wait_event(sdev->list_wait, atomic_read(&sdev->in_flight) == 0); + wait_event(sctx->list_wait, atomic_read(&sctx->in_flight) == 0); atomic_dec(&fs_info->scrubs_running); wake_up(&fs_info->scrub_pause_wait); - wait_event(sdev->list_wait, atomic_read(&sdev->fixup_cnt) == 0); + wait_event(sctx->list_wait, atomic_read(&sctx->fixup_cnt) == 0); if (progress) - memcpy(progress, &sdev->stat, sizeof(*progress)); + memcpy(progress, &sctx->stat, sizeof(*progress)); mutex_lock(&fs_info->scrub_lock); dev->scrub_device = NULL; mutex_unlock(&fs_info->scrub_lock); - scrub_free_dev(sdev); + scrub_free_ctx(sctx); scrub_workers_put(root); return ret; @@ -2407,15 +2407,15 @@ int btrfs_scrub_cancel(struct btrfs_root *root) int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev) { struct btrfs_fs_info *fs_info = root->fs_info; - struct scrub_dev *sdev; + struct scrub_ctx *sctx; mutex_lock(&fs_info->scrub_lock); - sdev = dev->scrub_device; - if (!sdev) { + sctx = dev->scrub_device; + if (!sctx) { mutex_unlock(&fs_info->scrub_lock); return -ENOTCONN; } - atomic_inc(&sdev->cancel_req); + atomic_inc(&sctx->cancel_req); while (dev->scrub_device) { mutex_unlock(&fs_info->scrub_lock); wait_event(fs_info->scrub_pause_wait, @@ -2453,15 +2453,15 @@ int btrfs_scrub_progress(struct btrfs_root *root, u64 devid, struct btrfs_scrub_progress *progress) { struct btrfs_device *dev; - struct scrub_dev *sdev = NULL; + struct scrub_ctx *sctx = NULL; mutex_lock(&root->fs_info->fs_devices->device_list_mutex); dev = btrfs_find_device(root, devid, NULL, NULL); if (dev) - sdev = dev->scrub_device; - if (sdev) - memcpy(progress, &sdev->stat, sizeof(*progress)); + sctx = dev->scrub_device; + if (sctx) + memcpy(progress, &sctx->stat, sizeof(*progress)); mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - return dev ? (sdev ? 0 : -ENOTCONN) : -ENODEV; + return dev ? (sctx ? 0 : -ENOTCONN) : -ENODEV; } diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 53c06af..1789cda 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -88,7 +88,7 @@ struct btrfs_device { u8 uuid[BTRFS_UUID_SIZE]; /* per-device scrub information */ - struct scrub_dev *scrub_device; + struct scrub_ctx *scrub_device; struct btrfs_work work; struct rcu_head rcu; -- cgit v0.10.2 From a36cf8b8933e4a7a7f2f2cbc3c70b097e97f7fd1 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Fri, 2 Nov 2012 13:26:57 +0100 Subject: Btrfs: remove the block device pointer from the scrub context struct The block device is removed from the scrub context state structure. The scrub code as it is used for the device replace procedure reads the source data from whereever it is optimal. The source device might even be gone (disconnected, for instance due to a hardware failure). Or the drive can be so faulty so that the device replace procedure tries to avoid access to the faulty source drive as much as possible, and only if all other mirrors are damaged, as a last resort, the source disk is accessed. The modified scrub code operates as if it would handle the source drive and thereby generates an exact copy of the source disk on the target disk, even if the source disk is not present at all. Therefore the block device pointer to the source disk is removed in the scrub context struct and moved into the lower level scope of scrub_bio, fixup and page structures where the block device context is known. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 29c8aac..822c08a 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -67,6 +67,7 @@ struct scrub_page { struct scrub_bio { int index; struct scrub_ctx *sctx; + struct btrfs_device *dev; struct bio *bio; int err; u64 logical; @@ -93,7 +94,7 @@ struct scrub_block { struct scrub_ctx { struct scrub_bio *bios[SCRUB_BIOS_PER_CTX]; - struct btrfs_device *dev; + struct btrfs_root *dev_root; int first_free; int curr; atomic_t in_flight; @@ -117,6 +118,7 @@ struct scrub_ctx { struct scrub_fixup_nodatasum { struct scrub_ctx *sctx; + struct btrfs_device *dev; u64 logical; struct btrfs_root *root; struct btrfs_work work; @@ -166,8 +168,8 @@ static void scrub_block_put(struct scrub_block *sblock); static int scrub_add_page_to_bio(struct scrub_ctx *sctx, struct scrub_page *spage); static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, - u64 physical, u64 flags, u64 gen, int mirror_num, - u8 *csum, int force); + u64 physical, struct btrfs_device *dev, u64 flags, + u64 gen, int mirror_num, u8 *csum, int force); static void scrub_bio_end_io(struct bio *bio, int err); static void scrub_bio_end_io_worker(struct btrfs_work *work); static void scrub_block_complete(struct scrub_block *sblock); @@ -228,9 +230,9 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev) sctx = kzalloc(sizeof(*sctx), GFP_NOFS); if (!sctx) goto nomem; - sctx->dev = dev; sctx->pages_per_bio = pages_per_bio; sctx->curr = -1; + sctx->dev_root = dev->dev_root; for (i = 0; i < SCRUB_BIOS_PER_CTX; ++i) { struct scrub_bio *sbio; @@ -345,8 +347,8 @@ err: static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) { - struct btrfs_device *dev = sblock->sctx->dev; - struct btrfs_fs_info *fs_info = dev->dev_root->fs_info; + struct btrfs_device *dev; + struct btrfs_fs_info *fs_info; struct btrfs_path *path; struct btrfs_key found_key; struct extent_buffer *eb; @@ -361,15 +363,18 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) const int bufsize = 4096; int ret; + WARN_ON(sblock->page_count < 1); + dev = sblock->pagev[0].dev; + fs_info = sblock->sctx->dev_root->fs_info; + path = btrfs_alloc_path(); swarn.scratch_buf = kmalloc(bufsize, GFP_NOFS); swarn.msg_buf = kmalloc(bufsize, GFP_NOFS); - BUG_ON(sblock->page_count < 1); swarn.sector = (sblock->pagev[0].physical) >> 9; swarn.logical = sblock->pagev[0].logical; swarn.errstr = errstr; - swarn.dev = dev; + swarn.dev = NULL; swarn.msg_bufsize = bufsize; swarn.scratch_bufsize = bufsize; @@ -405,6 +410,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) } while (ret != 1); } else { swarn.path = path; + swarn.dev = dev; iterate_extent_inodes(fs_info, found_key.objectid, extent_item_pos, 1, scrub_print_warning_inode, &swarn); @@ -588,7 +594,7 @@ out: printk_ratelimited_in_rcu(KERN_ERR "btrfs: unable to fixup (nodatasum) error at logical %llu on dev %s\n", (unsigned long long)fixup->logical, - rcu_str_deref(sctx->dev->name)); + rcu_str_deref(fixup->dev->name)); } btrfs_free_path(path); @@ -615,6 +621,7 @@ out: static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) { struct scrub_ctx *sctx = sblock_to_check->sctx; + struct btrfs_device *dev; struct btrfs_fs_info *fs_info; u64 length; u64 logical; @@ -633,7 +640,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) DEFAULT_RATELIMIT_BURST); BUG_ON(sblock_to_check->page_count < 1); - fs_info = sctx->dev->dev_root->fs_info; + fs_info = sctx->dev_root->fs_info; length = sblock_to_check->page_count * PAGE_SIZE; logical = sblock_to_check->pagev[0].logical; generation = sblock_to_check->pagev[0].generation; @@ -643,6 +650,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) BTRFS_EXTENT_FLAG_DATA); have_csum = sblock_to_check->pagev[0].have_csum; csum = sblock_to_check->pagev[0].csum; + dev = sblock_to_check->pagev[0].dev; /* * read all mirrors one after the other. This includes to @@ -682,8 +690,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) sctx->stat.read_errors++; sctx->stat.uncorrectable_errors++; spin_unlock(&sctx->stat_lock); - btrfs_dev_stat_inc_and_print(sctx->dev, - BTRFS_DEV_STAT_READ_ERRS); + btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS); goto out; } @@ -695,8 +702,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) sctx->stat.read_errors++; sctx->stat.uncorrectable_errors++; spin_unlock(&sctx->stat_lock); - btrfs_dev_stat_inc_and_print(sctx->dev, - BTRFS_DEV_STAT_READ_ERRS); + btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS); goto out; } BUG_ON(failed_mirror_index >= BTRFS_MAX_MIRRORS); @@ -710,8 +716,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) sctx->stat.read_errors++; sctx->stat.uncorrectable_errors++; spin_unlock(&sctx->stat_lock); - btrfs_dev_stat_inc_and_print(sctx->dev, - BTRFS_DEV_STAT_READ_ERRS); + btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS); goto out; } @@ -738,15 +743,14 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) spin_unlock(&sctx->stat_lock); if (__ratelimit(&_rs)) scrub_print_warning("i/o error", sblock_to_check); - btrfs_dev_stat_inc_and_print(sctx->dev, - BTRFS_DEV_STAT_READ_ERRS); + btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS); } else if (sblock_bad->checksum_error) { spin_lock(&sctx->stat_lock); sctx->stat.csum_errors++; spin_unlock(&sctx->stat_lock); if (__ratelimit(&_rs)) scrub_print_warning("checksum error", sblock_to_check); - btrfs_dev_stat_inc_and_print(sctx->dev, + btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); } else if (sblock_bad->header_error) { spin_lock(&sctx->stat_lock); @@ -756,10 +760,10 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) scrub_print_warning("checksum/header error", sblock_to_check); if (sblock_bad->generation_error) - btrfs_dev_stat_inc_and_print(sctx->dev, + btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_GENERATION_ERRS); else - btrfs_dev_stat_inc_and_print(sctx->dev, + btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); } @@ -780,6 +784,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) if (!fixup_nodatasum) goto did_not_correct_error; fixup_nodatasum->sctx = sctx; + fixup_nodatasum->dev = dev; fixup_nodatasum->logical = logical; fixup_nodatasum->root = fs_info->extent_root; fixup_nodatasum->mirror_num = failed_mirror_index + 1; @@ -945,7 +950,7 @@ corrected_error: printk_ratelimited_in_rcu(KERN_ERR "btrfs: fixed up error at logical %llu on dev %s\n", (unsigned long long)logical, - rcu_str_deref(sctx->dev->name)); + rcu_str_deref(dev->name)); } } else { did_not_correct_error: @@ -955,7 +960,7 @@ did_not_correct_error: printk_ratelimited_in_rcu(KERN_ERR "btrfs: unable to fixup (regular) error at logical %llu on dev %s\n", (unsigned long long)logical, - rcu_str_deref(sctx->dev->name)); + rcu_str_deref(dev->name)); } out: @@ -1266,7 +1271,7 @@ static int scrub_checksum_data(struct scrub_block *sblock) void *buffer; u32 crc = ~(u32)0; int fail = 0; - struct btrfs_root *root = sctx->dev->dev_root; + struct btrfs_root *root = sctx->dev_root; u64 len; int index; @@ -1306,7 +1311,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) { struct scrub_ctx *sctx = sblock->sctx; struct btrfs_header *h; - struct btrfs_root *root = sctx->dev->dev_root; + struct btrfs_root *root = sctx->dev_root; struct btrfs_fs_info *fs_info = root->fs_info; u8 calculated_csum[BTRFS_CSUM_SIZE]; u8 on_disk_csum[BTRFS_CSUM_SIZE]; @@ -1378,7 +1383,7 @@ static int scrub_checksum_super(struct scrub_block *sblock) { struct btrfs_super_block *s; struct scrub_ctx *sctx = sblock->sctx; - struct btrfs_root *root = sctx->dev->dev_root; + struct btrfs_root *root = sctx->dev_root; struct btrfs_fs_info *fs_info = root->fs_info; u8 calculated_csum[BTRFS_CSUM_SIZE]; u8 on_disk_csum[BTRFS_CSUM_SIZE]; @@ -1442,10 +1447,10 @@ static int scrub_checksum_super(struct scrub_block *sblock) ++sctx->stat.super_errors; spin_unlock(&sctx->stat_lock); if (fail_cor) - btrfs_dev_stat_inc_and_print(sctx->dev, + btrfs_dev_stat_inc_and_print(sblock->pagev[0].dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); else - btrfs_dev_stat_inc_and_print(sctx->dev, + btrfs_dev_stat_inc_and_print(sblock->pagev[0].dev, BTRFS_DEV_STAT_GENERATION_ERRS); } @@ -1513,6 +1518,7 @@ again: sbio->physical = spage->physical; sbio->logical = spage->logical; + sbio->dev = spage->dev; bio = sbio->bio; if (!bio) { bio = bio_alloc(GFP_NOFS, sctx->pages_per_bio); @@ -1523,13 +1529,14 @@ again: bio->bi_private = sbio; bio->bi_end_io = scrub_bio_end_io; - bio->bi_bdev = sctx->dev->bdev; - bio->bi_sector = spage->physical >> 9; + bio->bi_bdev = sbio->dev->bdev; + bio->bi_sector = sbio->physical >> 9; sbio->err = 0; } else if (sbio->physical + sbio->page_count * PAGE_SIZE != spage->physical || sbio->logical + sbio->page_count * PAGE_SIZE != - spage->logical) { + spage->logical || + sbio->dev != spage->dev) { scrub_submit(sctx); goto again; } @@ -1556,8 +1563,8 @@ again: } static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, - u64 physical, u64 flags, u64 gen, int mirror_num, - u8 *csum, int force) + u64 physical, struct btrfs_device *dev, u64 flags, + u64 gen, int mirror_num, u8 *csum, int force) { struct scrub_block *sblock; int index; @@ -1593,7 +1600,7 @@ static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, return -ENOMEM; } spage->sblock = sblock; - spage->dev = sctx->dev; + spage->dev = dev; spage->flags = flags; spage->generation = gen; spage->logical = logical; @@ -1634,8 +1641,7 @@ static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, static void scrub_bio_end_io(struct bio *bio, int err) { struct scrub_bio *sbio = bio->bi_private; - struct scrub_ctx *sctx = sbio->sctx; - struct btrfs_fs_info *fs_info = sctx->dev->dev_root->fs_info; + struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info; sbio->err = err; sbio->bio = bio; @@ -1728,7 +1734,8 @@ static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u64 len, /* scrub extent tries to collect up to 64 kB for each bio */ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, - u64 physical, u64 flags, u64 gen, int mirror_num) + u64 physical, struct btrfs_device *dev, u64 flags, + u64 gen, int mirror_num) { int ret; u8 csum[BTRFS_CSUM_SIZE]; @@ -1762,7 +1769,7 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, if (have_csum == 0) ++sctx->stat.no_csum; } - ret = scrub_pages(sctx, logical, l, physical, flags, gen, + ret = scrub_pages(sctx, logical, l, physical, dev, flags, gen, mirror_num, have_csum ? csum : NULL, 0); if (ret) return ret; @@ -1774,10 +1781,12 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, } static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, - struct map_lookup *map, int num, u64 base, u64 length) + struct map_lookup *map, + struct btrfs_device *scrub_dev, + int num, u64 base, u64 length) { struct btrfs_path *path; - struct btrfs_fs_info *fs_info = sctx->dev->dev_root->fs_info; + struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; struct btrfs_root *root = fs_info->extent_root; struct btrfs_root *csum_root = fs_info->csum_root; struct btrfs_extent_item *extent; @@ -1797,7 +1806,6 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, struct reada_control *reada2; struct btrfs_key key_start; struct btrfs_key key_end; - u64 increment = map->stripe_len; u64 offset; @@ -2006,7 +2014,8 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, ret = scrub_extent(sctx, key.objectid, key.offset, key.objectid - logical + physical, - flags, generation, mirror_num); + scrub_dev, flags, generation, + mirror_num); if (ret) goto out; @@ -2030,11 +2039,13 @@ out: } static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, - u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 length, - u64 dev_offset) + struct btrfs_device *scrub_dev, + u64 chunk_tree, u64 chunk_objectid, + u64 chunk_offset, u64 length, + u64 dev_offset) { struct btrfs_mapping_tree *map_tree = - &sctx->dev->dev_root->fs_info->mapping_tree; + &sctx->dev_root->fs_info->mapping_tree; struct map_lookup *map; struct extent_map *em; int i; @@ -2055,9 +2066,10 @@ static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, goto out; for (i = 0; i < map->num_stripes; ++i) { - if (map->stripes[i].dev == sctx->dev && + if (map->stripes[i].dev->bdev == scrub_dev->bdev && map->stripes[i].physical == dev_offset) { - ret = scrub_stripe(sctx, map, i, chunk_offset, length); + ret = scrub_stripe(sctx, map, scrub_dev, i, + chunk_offset, length); if (ret) goto out; } @@ -2069,11 +2081,12 @@ out: } static noinline_for_stack -int scrub_enumerate_chunks(struct scrub_ctx *sctx, u64 start, u64 end) +int scrub_enumerate_chunks(struct scrub_ctx *sctx, + struct btrfs_device *scrub_dev, u64 start, u64 end) { struct btrfs_dev_extent *dev_extent = NULL; struct btrfs_path *path; - struct btrfs_root *root = sctx->dev->dev_root; + struct btrfs_root *root = sctx->dev_root; struct btrfs_fs_info *fs_info = root->fs_info; u64 length; u64 chunk_tree; @@ -2094,11 +2107,10 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, u64 start, u64 end) path->search_commit_root = 1; path->skip_locking = 1; - key.objectid = sctx->dev->devid; + key.objectid = scrub_dev->devid; key.offset = 0ull; key.type = BTRFS_DEV_EXTENT_KEY; - while (1) { ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) @@ -2117,7 +2129,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, u64 start, u64 end) btrfs_item_key_to_cpu(l, &found_key, slot); - if (found_key.objectid != sctx->dev->devid) + if (found_key.objectid != scrub_dev->devid) break; if (btrfs_key_type(&found_key) != BTRFS_DEV_EXTENT_KEY) @@ -2151,7 +2163,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, u64 start, u64 end) ret = -ENOENT; break; } - ret = scrub_chunk(sctx, chunk_tree, chunk_objectid, + ret = scrub_chunk(sctx, scrub_dev, chunk_tree, chunk_objectid, chunk_offset, length, found_key.offset); btrfs_put_block_group(cache); if (ret) @@ -2170,14 +2182,14 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, u64 start, u64 end) return ret < 0 ? ret : 0; } -static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx) +static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx, + struct btrfs_device *scrub_dev) { int i; u64 bytenr; u64 gen; int ret; - struct btrfs_device *device = sctx->dev; - struct btrfs_root *root = device->dev_root; + struct btrfs_root *root = sctx->dev_root; if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) return -EIO; @@ -2186,11 +2198,12 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx) for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); - if (bytenr + BTRFS_SUPER_INFO_SIZE > device->total_bytes) + if (bytenr + BTRFS_SUPER_INFO_SIZE > scrub_dev->total_bytes) break; ret = scrub_pages(sctx, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr, - BTRFS_EXTENT_FLAG_SUPER, gen, i, NULL, 1); + scrub_dev, BTRFS_EXTENT_FLAG_SUPER, gen, i, + NULL, 1); if (ret) return ret; } @@ -2317,11 +2330,11 @@ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); down_read(&fs_info->scrub_super_lock); - ret = scrub_supers(sctx); + ret = scrub_supers(sctx, dev); up_read(&fs_info->scrub_super_lock); if (!ret) - ret = scrub_enumerate_chunks(sctx, start, end); + ret = scrub_enumerate_chunks(sctx, dev, start, end); wait_event(sctx->list_wait, atomic_read(&sctx->in_flight) == 0); atomic_dec(&fs_info->scrubs_running); -- cgit v0.10.2 From 7a9e9987681198c56ac7f165725ca322d7a196e1 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Fri, 2 Nov 2012 14:58:04 +0100 Subject: Btrfs: make the scrub page array dynamically allocated With the modified design (in order to support the devive replace procedure) it is necessary to alloc the page array dynamically. The reason is that pages are reused. At first a page is used for the bio to read the data from the filesystem, then the same page is reused for the bio that writes the data to the target disk. Since the read process and the write process are completely decoupled, this requires a new concept of refcounts and get/put functions for pages, and it requires to use newly created pages for each read bio which are freed after the write operation is finished. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 822c08a..15ac82a 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -46,6 +46,12 @@ struct scrub_ctx; #define SCRUB_PAGES_PER_BIO 16 /* 64k per bio */ #define SCRUB_BIOS_PER_CTX 16 /* 1 MB per device in flight */ + +/* + * the following value times PAGE_SIZE needs to be large enough to match the + * largest node/leaf/sector size that shall be supported. + * Values larger than BTRFS_STRIPE_LEN are not supported. + */ #define SCRUB_MAX_PAGES_PER_BLOCK 16 /* 64k per node/leaf/sector */ struct scrub_page { @@ -56,6 +62,7 @@ struct scrub_page { u64 generation; u64 logical; u64 physical; + atomic_t ref_count; struct { unsigned int mirror_num:8; unsigned int have_csum:1; @@ -79,7 +86,7 @@ struct scrub_bio { }; struct scrub_block { - struct scrub_page pagev[SCRUB_MAX_PAGES_PER_BLOCK]; + struct scrub_page *pagev[SCRUB_MAX_PAGES_PER_BLOCK]; int page_count; atomic_t outstanding_pages; atomic_t ref_count; /* free mem on transition to zero */ @@ -165,6 +172,8 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock); static int scrub_checksum_super(struct scrub_block *sblock); static void scrub_block_get(struct scrub_block *sblock); static void scrub_block_put(struct scrub_block *sblock); +static void scrub_page_get(struct scrub_page *spage); +static void scrub_page_put(struct scrub_page *spage); static int scrub_add_page_to_bio(struct scrub_ctx *sctx, struct scrub_page *spage); static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, @@ -364,15 +373,15 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) int ret; WARN_ON(sblock->page_count < 1); - dev = sblock->pagev[0].dev; + dev = sblock->pagev[0]->dev; fs_info = sblock->sctx->dev_root->fs_info; path = btrfs_alloc_path(); swarn.scratch_buf = kmalloc(bufsize, GFP_NOFS); swarn.msg_buf = kmalloc(bufsize, GFP_NOFS); - swarn.sector = (sblock->pagev[0].physical) >> 9; - swarn.logical = sblock->pagev[0].logical; + swarn.sector = (sblock->pagev[0]->physical) >> 9; + swarn.logical = sblock->pagev[0]->logical; swarn.errstr = errstr; swarn.dev = NULL; swarn.msg_bufsize = bufsize; @@ -642,15 +651,15 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) BUG_ON(sblock_to_check->page_count < 1); fs_info = sctx->dev_root->fs_info; length = sblock_to_check->page_count * PAGE_SIZE; - logical = sblock_to_check->pagev[0].logical; - generation = sblock_to_check->pagev[0].generation; - BUG_ON(sblock_to_check->pagev[0].mirror_num < 1); - failed_mirror_index = sblock_to_check->pagev[0].mirror_num - 1; - is_metadata = !(sblock_to_check->pagev[0].flags & + logical = sblock_to_check->pagev[0]->logical; + generation = sblock_to_check->pagev[0]->generation; + BUG_ON(sblock_to_check->pagev[0]->mirror_num < 1); + failed_mirror_index = sblock_to_check->pagev[0]->mirror_num - 1; + is_metadata = !(sblock_to_check->pagev[0]->flags & BTRFS_EXTENT_FLAG_DATA); - have_csum = sblock_to_check->pagev[0].have_csum; - csum = sblock_to_check->pagev[0].csum; - dev = sblock_to_check->pagev[0].dev; + have_csum = sblock_to_check->pagev[0]->have_csum; + csum = sblock_to_check->pagev[0]->csum; + dev = sblock_to_check->pagev[0]->dev; /* * read all mirrors one after the other. This includes to @@ -892,7 +901,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) success = 1; for (page_num = 0; page_num < sblock_bad->page_count; page_num++) { - struct scrub_page *page_bad = sblock_bad->pagev + page_num; + struct scrub_page *page_bad = sblock_bad->pagev[page_num]; if (!page_bad->io_error) continue; @@ -903,8 +912,8 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) mirror_index++) { struct scrub_block *sblock_other = sblocks_for_recheck + mirror_index; - struct scrub_page *page_other = sblock_other->pagev + - page_num; + struct scrub_page *page_other = sblock_other->pagev[ + page_num]; if (!page_other->io_error) { ret = scrub_repair_page_from_good_copy( @@ -971,11 +980,11 @@ out: mirror_index; int page_index; - for (page_index = 0; page_index < SCRUB_PAGES_PER_BIO; - page_index++) - if (sblock->pagev[page_index].page) - __free_page( - sblock->pagev[page_index].page); + for (page_index = 0; page_index < sblock->page_count; + page_index++) { + sblock->pagev[page_index]->sblock = NULL; + scrub_page_put(sblock->pagev[page_index]); + } } kfree(sblocks_for_recheck); } @@ -993,7 +1002,7 @@ static int scrub_setup_recheck_block(struct scrub_ctx *sctx, int ret; /* - * note: the three members sctx, ref_count and outstanding_pages + * note: the two members ref_count and outstanding_pages * are not used (and not set) in the blocks that are used for * the recheck procedure */ @@ -1025,21 +1034,27 @@ static int scrub_setup_recheck_block(struct scrub_ctx *sctx, continue; sblock = sblocks_for_recheck + mirror_index; - page = sblock->pagev + page_index; - page->logical = logical; - page->physical = bbio->stripes[mirror_index].physical; - /* for missing devices, dev->bdev is NULL */ - page->dev = bbio->stripes[mirror_index].dev; - page->mirror_num = mirror_index + 1; - page->page = alloc_page(GFP_NOFS); - if (!page->page) { + sblock->sctx = sctx; + page = kzalloc(sizeof(*page), GFP_NOFS); + if (!page) { +leave_nomem: spin_lock(&sctx->stat_lock); sctx->stat.malloc_errors++; spin_unlock(&sctx->stat_lock); kfree(bbio); return -ENOMEM; } + scrub_page_get(page); + sblock->pagev[page_index] = page; + page->logical = logical; + page->physical = bbio->stripes[mirror_index].physical; + /* for missing devices, dev->bdev is NULL */ + page->dev = bbio->stripes[mirror_index].dev; + page->mirror_num = mirror_index + 1; sblock->page_count++; + page->page = alloc_page(GFP_NOFS); + if (!page->page) + goto leave_nomem; } kfree(bbio); length -= sublen; @@ -1071,7 +1086,7 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info, for (page_num = 0; page_num < sblock->page_count; page_num++) { struct bio *bio; int ret; - struct scrub_page *page = sblock->pagev + page_num; + struct scrub_page *page = sblock->pagev[page_num]; DECLARE_COMPLETION_ONSTACK(complete); if (page->dev->bdev == NULL) { @@ -1080,7 +1095,7 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info, continue; } - BUG_ON(!page->page); + WARN_ON(!page->page); bio = bio_alloc(GFP_NOFS, 1); if (!bio) return -EIO; @@ -1125,14 +1140,14 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info, struct btrfs_root *root = fs_info->extent_root; void *mapped_buffer; - BUG_ON(!sblock->pagev[0].page); + WARN_ON(!sblock->pagev[0]->page); if (is_metadata) { struct btrfs_header *h; - mapped_buffer = kmap_atomic(sblock->pagev[0].page); + mapped_buffer = kmap_atomic(sblock->pagev[0]->page); h = (struct btrfs_header *)mapped_buffer; - if (sblock->pagev[0].logical != le64_to_cpu(h->bytenr) || + if (sblock->pagev[0]->logical != le64_to_cpu(h->bytenr) || memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE) || memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid, BTRFS_UUID_SIZE)) { @@ -1146,7 +1161,7 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info, if (!have_csum) return; - mapped_buffer = kmap_atomic(sblock->pagev[0].page); + mapped_buffer = kmap_atomic(sblock->pagev[0]->page); } for (page_num = 0;;) { @@ -1162,9 +1177,9 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info, page_num++; if (page_num >= sblock->page_count) break; - BUG_ON(!sblock->pagev[page_num].page); + WARN_ON(!sblock->pagev[page_num]->page); - mapped_buffer = kmap_atomic(sblock->pagev[page_num].page); + mapped_buffer = kmap_atomic(sblock->pagev[page_num]->page); } btrfs_csum_final(crc, calculated_csum); @@ -1202,11 +1217,11 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, struct scrub_block *sblock_good, int page_num, int force_write) { - struct scrub_page *page_bad = sblock_bad->pagev + page_num; - struct scrub_page *page_good = sblock_good->pagev + page_num; + struct scrub_page *page_bad = sblock_bad->pagev[page_num]; + struct scrub_page *page_good = sblock_good->pagev[page_num]; - BUG_ON(sblock_bad->pagev[page_num].page == NULL); - BUG_ON(sblock_good->pagev[page_num].page == NULL); + BUG_ON(page_bad->page == NULL); + BUG_ON(page_good->page == NULL); if (force_write || sblock_bad->header_error || sblock_bad->checksum_error || page_bad->io_error) { struct bio *bio; @@ -1247,8 +1262,8 @@ static void scrub_checksum(struct scrub_block *sblock) u64 flags; int ret; - BUG_ON(sblock->page_count < 1); - flags = sblock->pagev[0].flags; + WARN_ON(sblock->page_count < 1); + flags = sblock->pagev[0]->flags; ret = 0; if (flags & BTRFS_EXTENT_FLAG_DATA) ret = scrub_checksum_data(sblock); @@ -1276,11 +1291,11 @@ static int scrub_checksum_data(struct scrub_block *sblock) int index; BUG_ON(sblock->page_count < 1); - if (!sblock->pagev[0].have_csum) + if (!sblock->pagev[0]->have_csum) return 0; - on_disk_csum = sblock->pagev[0].csum; - page = sblock->pagev[0].page; + on_disk_csum = sblock->pagev[0]->csum; + page = sblock->pagev[0]->page; buffer = kmap_atomic(page); len = sctx->sectorsize; @@ -1295,8 +1310,8 @@ static int scrub_checksum_data(struct scrub_block *sblock) break; index++; BUG_ON(index >= sblock->page_count); - BUG_ON(!sblock->pagev[index].page); - page = sblock->pagev[index].page; + BUG_ON(!sblock->pagev[index]->page); + page = sblock->pagev[index]->page; buffer = kmap_atomic(page); } @@ -1326,7 +1341,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) int index; BUG_ON(sblock->page_count < 1); - page = sblock->pagev[0].page; + page = sblock->pagev[0]->page; mapped_buffer = kmap_atomic(page); h = (struct btrfs_header *)mapped_buffer; memcpy(on_disk_csum, h->csum, sctx->csum_size); @@ -1337,10 +1352,10 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) * b) the page is already kmapped */ - if (sblock->pagev[0].logical != le64_to_cpu(h->bytenr)) + if (sblock->pagev[0]->logical != le64_to_cpu(h->bytenr)) ++fail; - if (sblock->pagev[0].generation != le64_to_cpu(h->generation)) + if (sblock->pagev[0]->generation != le64_to_cpu(h->generation)) ++fail; if (memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE)) @@ -1365,8 +1380,8 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) break; index++; BUG_ON(index >= sblock->page_count); - BUG_ON(!sblock->pagev[index].page); - page = sblock->pagev[index].page; + BUG_ON(!sblock->pagev[index]->page); + page = sblock->pagev[index]->page; mapped_buffer = kmap_atomic(page); mapped_size = PAGE_SIZE; p = mapped_buffer; @@ -1398,15 +1413,15 @@ static int scrub_checksum_super(struct scrub_block *sblock) int index; BUG_ON(sblock->page_count < 1); - page = sblock->pagev[0].page; + page = sblock->pagev[0]->page; mapped_buffer = kmap_atomic(page); s = (struct btrfs_super_block *)mapped_buffer; memcpy(on_disk_csum, s->csum, sctx->csum_size); - if (sblock->pagev[0].logical != le64_to_cpu(s->bytenr)) + if (sblock->pagev[0]->logical != le64_to_cpu(s->bytenr)) ++fail_cor; - if (sblock->pagev[0].generation != le64_to_cpu(s->generation)) + if (sblock->pagev[0]->generation != le64_to_cpu(s->generation)) ++fail_gen; if (memcmp(s->fsid, fs_info->fsid, BTRFS_UUID_SIZE)) @@ -1426,8 +1441,8 @@ static int scrub_checksum_super(struct scrub_block *sblock) break; index++; BUG_ON(index >= sblock->page_count); - BUG_ON(!sblock->pagev[index].page); - page = sblock->pagev[index].page; + BUG_ON(!sblock->pagev[index]->page); + page = sblock->pagev[index]->page; mapped_buffer = kmap_atomic(page); mapped_size = PAGE_SIZE; p = mapped_buffer; @@ -1447,10 +1462,10 @@ static int scrub_checksum_super(struct scrub_block *sblock) ++sctx->stat.super_errors; spin_unlock(&sctx->stat_lock); if (fail_cor) - btrfs_dev_stat_inc_and_print(sblock->pagev[0].dev, + btrfs_dev_stat_inc_and_print(sblock->pagev[0]->dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); else - btrfs_dev_stat_inc_and_print(sblock->pagev[0].dev, + btrfs_dev_stat_inc_and_print(sblock->pagev[0]->dev, BTRFS_DEV_STAT_GENERATION_ERRS); } @@ -1468,12 +1483,25 @@ static void scrub_block_put(struct scrub_block *sblock) int i; for (i = 0; i < sblock->page_count; i++) - if (sblock->pagev[i].page) - __free_page(sblock->pagev[i].page); + scrub_page_put(sblock->pagev[i]); kfree(sblock); } } +static void scrub_page_get(struct scrub_page *spage) +{ + atomic_inc(&spage->ref_count); +} + +static void scrub_page_put(struct scrub_page *spage) +{ + if (atomic_dec_and_test(&spage->ref_count)) { + if (spage->page) + __free_page(spage->page); + kfree(spage); + } +} + static void scrub_submit(struct scrub_ctx *sctx) { struct scrub_bio *sbio; @@ -1577,28 +1605,28 @@ static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, return -ENOMEM; } - /* one ref inside this function, plus one for each page later on */ + /* one ref inside this function, plus one for each page added to + * a bio later on */ atomic_set(&sblock->ref_count, 1); sblock->sctx = sctx; sblock->no_io_error_seen = 1; for (index = 0; len > 0; index++) { - struct scrub_page *spage = sblock->pagev + index; + struct scrub_page *spage; u64 l = min_t(u64, len, PAGE_SIZE); - BUG_ON(index >= SCRUB_MAX_PAGES_PER_BLOCK); - spage->page = alloc_page(GFP_NOFS); - if (!spage->page) { + spage = kzalloc(sizeof(*spage), GFP_NOFS); + if (!spage) { +leave_nomem: spin_lock(&sctx->stat_lock); sctx->stat.malloc_errors++; spin_unlock(&sctx->stat_lock); - while (index > 0) { - index--; - __free_page(sblock->pagev[index].page); - } - kfree(sblock); + scrub_block_put(sblock); return -ENOMEM; } + BUG_ON(index >= SCRUB_MAX_PAGES_PER_BLOCK); + scrub_page_get(spage); + sblock->pagev[index] = spage; spage->sblock = sblock; spage->dev = dev; spage->flags = flags; @@ -1613,14 +1641,17 @@ static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, spage->have_csum = 0; } sblock->page_count++; + spage->page = alloc_page(GFP_NOFS); + if (!spage->page) + goto leave_nomem; len -= l; logical += l; physical += l; } - BUG_ON(sblock->page_count == 0); + WARN_ON(sblock->page_count == 0); for (index = 0; index < sblock->page_count; index++) { - struct scrub_page *spage = sblock->pagev + index; + struct scrub_page *spage = sblock->pagev[index]; int ret; ret = scrub_add_page_to_bio(sctx, spage); @@ -2289,6 +2320,22 @@ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, return -EINVAL; } + if (fs_info->chunk_root->nodesize > + PAGE_SIZE * SCRUB_MAX_PAGES_PER_BLOCK || + fs_info->chunk_root->sectorsize > + PAGE_SIZE * SCRUB_MAX_PAGES_PER_BLOCK) { + /* + * would exhaust the array bounds of pagev member in + * struct scrub_block + */ + pr_err("btrfs_scrub: size assumption nodesize and sectorsize <= SCRUB_MAX_PAGES_PER_BLOCK (%d <= %d && %d <= %d) fails\n", + fs_info->chunk_root->nodesize, + SCRUB_MAX_PAGES_PER_BLOCK, + fs_info->chunk_root->sectorsize, + SCRUB_MAX_PAGES_PER_BLOCK); + return -EINVAL; + } + ret = scrub_workers_get(root); if (ret) return ret; -- cgit v0.10.2 From cb2ced73d8c7a38b5f699e267deadf2a2cfe911c Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Fri, 2 Nov 2012 16:14:21 +0100 Subject: Btrfs: in scrub repair code, optimize the reading of mirrors In case that disk blocks need to be repaired (rewritten), the current code at first (for simplicity reasons) reads all alternate mirrors in the first step, afterwards selects the best one in a second step. This is now changed to read one alternate mirror after the other and to leave the loop early when a perfect mirror is found. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 15ac82a..7d38f40 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -819,26 +819,8 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) /* * now build and submit the bios for the other mirrors, check - * checksums - */ - for (mirror_index = 0; - mirror_index < BTRFS_MAX_MIRRORS && - sblocks_for_recheck[mirror_index].page_count > 0; - mirror_index++) { - if (mirror_index == failed_mirror_index) - continue; - - /* build and submit the bios, check checksums */ - ret = scrub_recheck_block(fs_info, - sblocks_for_recheck + mirror_index, - is_metadata, have_csum, csum, - generation, sctx->csum_size); - if (ret) - goto did_not_correct_error; - } - - /* - * first try to pick the mirror which is completely without I/O + * checksums. + * First try to pick the mirror which is completely without I/O * errors and also does not have a checksum error. * If one is found, and if a checksum is present, the full block * that is known to contain an error is rewritten. Afterwards @@ -854,10 +836,17 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) mirror_index < BTRFS_MAX_MIRRORS && sblocks_for_recheck[mirror_index].page_count > 0; mirror_index++) { - struct scrub_block *sblock_other = sblocks_for_recheck + - mirror_index; + struct scrub_block *sblock_other; - if (!sblock_other->header_error && + if (mirror_index == failed_mirror_index) + continue; + sblock_other = sblocks_for_recheck + mirror_index; + + /* build and submit the bios, check checksums */ + ret = scrub_recheck_block(fs_info, sblock_other, is_metadata, + have_csum, csum, generation, + sctx->csum_size); + if (!ret && !sblock_other->header_error && !sblock_other->checksum_error && sblock_other->no_io_error_seen) { int force_write = is_metadata || have_csum; -- cgit v0.10.2 From 34f5c8e90b3f002672cd6b4e6e7c5b959fd981ae Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Fri, 2 Nov 2012 16:16:26 +0100 Subject: Btrfs: in scrub repair code, simplify alloc error handling In the scrub repair code, the code is changed to handle memory allocation errors a little bit smarter. The change is to handle it just like a read error. This simplifies the code and removes a couple of lines of code, since the code to handle read errors is there anyway. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 7d38f40..fcd5bcc 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -151,10 +151,10 @@ static int scrub_setup_recheck_block(struct scrub_ctx *sctx, struct btrfs_mapping_tree *map_tree, u64 length, u64 logical, struct scrub_block *sblock); -static int scrub_recheck_block(struct btrfs_fs_info *fs_info, - struct scrub_block *sblock, int is_metadata, - int have_csum, u8 *csum, u64 generation, - u16 csum_size); +static void scrub_recheck_block(struct btrfs_fs_info *fs_info, + struct scrub_block *sblock, int is_metadata, + int have_csum, u8 *csum, u64 generation, + u16 csum_size); static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info, struct scrub_block *sblock, int is_metadata, int have_csum, @@ -718,16 +718,8 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) sblock_bad = sblocks_for_recheck + failed_mirror_index; /* build and submit the bios for the failed mirror, check checksums */ - ret = scrub_recheck_block(fs_info, sblock_bad, is_metadata, have_csum, - csum, generation, sctx->csum_size); - if (ret) { - spin_lock(&sctx->stat_lock); - sctx->stat.read_errors++; - sctx->stat.uncorrectable_errors++; - spin_unlock(&sctx->stat_lock); - btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS); - goto out; - } + scrub_recheck_block(fs_info, sblock_bad, is_metadata, have_csum, + csum, generation, sctx->csum_size); if (!sblock_bad->header_error && !sblock_bad->checksum_error && sblock_bad->no_io_error_seen) { @@ -843,10 +835,11 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) sblock_other = sblocks_for_recheck + mirror_index; /* build and submit the bios, check checksums */ - ret = scrub_recheck_block(fs_info, sblock_other, is_metadata, - have_csum, csum, generation, - sctx->csum_size); - if (!ret && !sblock_other->header_error && + scrub_recheck_block(fs_info, sblock_other, is_metadata, + have_csum, csum, generation, + sctx->csum_size); + + if (!sblock_other->header_error && !sblock_other->checksum_error && sblock_other->no_io_error_seen) { int force_write = is_metadata || have_csum; @@ -931,10 +924,10 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) * is verified, but most likely the data comes out * of the page cache. */ - ret = scrub_recheck_block(fs_info, sblock_bad, - is_metadata, have_csum, csum, - generation, sctx->csum_size); - if (!ret && !sblock_bad->header_error && + scrub_recheck_block(fs_info, sblock_bad, + is_metadata, have_csum, csum, + generation, sctx->csum_size); + if (!sblock_bad->header_error && !sblock_bad->checksum_error && sblock_bad->no_io_error_seen) goto corrected_error; @@ -1061,10 +1054,10 @@ leave_nomem: * to take those pages that are not errored from all the mirrors so that * the pages that are errored in the just handled mirror can be repaired. */ -static int scrub_recheck_block(struct btrfs_fs_info *fs_info, - struct scrub_block *sblock, int is_metadata, - int have_csum, u8 *csum, u64 generation, - u16 csum_size) +static void scrub_recheck_block(struct btrfs_fs_info *fs_info, + struct scrub_block *sblock, int is_metadata, + int have_csum, u8 *csum, u64 generation, + u16 csum_size) { int page_num; @@ -1074,7 +1067,6 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info, for (page_num = 0; page_num < sblock->page_count; page_num++) { struct bio *bio; - int ret; struct scrub_page *page = sblock->pagev[page_num]; DECLARE_COMPLETION_ONSTACK(complete); @@ -1086,18 +1078,17 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info, WARN_ON(!page->page); bio = bio_alloc(GFP_NOFS, 1); - if (!bio) - return -EIO; + if (!bio) { + page->io_error = 1; + sblock->no_io_error_seen = 0; + continue; + } bio->bi_bdev = page->dev->bdev; bio->bi_sector = page->physical >> 9; bio->bi_end_io = scrub_complete_bio_end_io; bio->bi_private = &complete; - ret = bio_add_page(bio, page->page, PAGE_SIZE, 0); - if (PAGE_SIZE != ret) { - bio_put(bio); - return -EIO; - } + bio_add_page(bio, page->page, PAGE_SIZE, 0); btrfsic_submit_bio(READ, bio); /* this will also unplug the queue */ @@ -1114,7 +1105,7 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info, have_csum, csum, generation, csum_size); - return 0; + return; } static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info, -- cgit v0.10.2 From b6bfebc13218f1fc1502041a810919d3a81b8b4e Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Fri, 2 Nov 2012 16:44:58 +0100 Subject: Btrfs: cleanup scrub bio and worker wait code Just move some code into functions to make everything more readable. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index fcd5bcc..a67b1a1 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 STRATO. All rights reserved. + * Copyright (C) 2011, 2012 STRATO. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public @@ -104,8 +104,8 @@ struct scrub_ctx { struct btrfs_root *dev_root; int first_free; int curr; - atomic_t in_flight; - atomic_t fixup_cnt; + atomic_t bios_in_flight; + atomic_t workers_pending; spinlock_t list_lock; wait_queue_head_t list_wait; u16 csum_size; @@ -146,6 +146,10 @@ struct scrub_warning { }; +static void scrub_pending_bio_inc(struct scrub_ctx *sctx); +static void scrub_pending_bio_dec(struct scrub_ctx *sctx); +static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx); +static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx); static int scrub_handle_errored_block(struct scrub_block *sblock_to_check); static int scrub_setup_recheck_block(struct scrub_ctx *sctx, struct btrfs_mapping_tree *map_tree, @@ -184,6 +188,59 @@ static void scrub_bio_end_io_worker(struct btrfs_work *work); static void scrub_block_complete(struct scrub_block *sblock); +static void scrub_pending_bio_inc(struct scrub_ctx *sctx) +{ + atomic_inc(&sctx->bios_in_flight); +} + +static void scrub_pending_bio_dec(struct scrub_ctx *sctx) +{ + atomic_dec(&sctx->bios_in_flight); + wake_up(&sctx->list_wait); +} + +/* + * used for workers that require transaction commits (i.e., for the + * NOCOW case) + */ +static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx) +{ + struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; + + /* + * increment scrubs_running to prevent cancel requests from + * completing as long as a worker is running. we must also + * increment scrubs_paused to prevent deadlocking on pause + * requests used for transactions commits (as the worker uses a + * transaction context). it is safe to regard the worker + * as paused for all matters practical. effectively, we only + * avoid cancellation requests from completing. + */ + mutex_lock(&fs_info->scrub_lock); + atomic_inc(&fs_info->scrubs_running); + atomic_inc(&fs_info->scrubs_paused); + mutex_unlock(&fs_info->scrub_lock); + atomic_inc(&sctx->workers_pending); +} + +/* used for workers that require transaction commits */ +static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx) +{ + struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; + + /* + * see scrub_pending_trans_workers_inc() why we're pretending + * to be paused in the scrub counters + */ + mutex_lock(&fs_info->scrub_lock); + atomic_dec(&fs_info->scrubs_running); + atomic_dec(&fs_info->scrubs_paused); + mutex_unlock(&fs_info->scrub_lock); + atomic_dec(&sctx->workers_pending); + wake_up(&fs_info->scrub_pause_wait); + wake_up(&sctx->list_wait); +} + static void scrub_free_csums(struct scrub_ctx *sctx) { while (!list_empty(&sctx->csum_list)) { @@ -264,8 +321,8 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev) sctx->nodesize = dev->dev_root->nodesize; sctx->leafsize = dev->dev_root->leafsize; sctx->sectorsize = dev->dev_root->sectorsize; - atomic_set(&sctx->in_flight, 0); - atomic_set(&sctx->fixup_cnt, 0); + atomic_set(&sctx->bios_in_flight, 0); + atomic_set(&sctx->workers_pending, 0); atomic_set(&sctx->cancel_req, 0); sctx->csum_size = btrfs_super_csum_size(fs_info->super_copy); INIT_LIST_HEAD(&sctx->csum_list); @@ -609,14 +666,7 @@ out: btrfs_free_path(path); kfree(fixup); - /* see caller why we're pretending to be paused in the scrub counters */ - mutex_lock(&fs_info->scrub_lock); - atomic_dec(&fs_info->scrubs_running); - atomic_dec(&fs_info->scrubs_paused); - mutex_unlock(&fs_info->scrub_lock); - atomic_dec(&sctx->fixup_cnt); - wake_up(&fs_info->scrub_pause_wait); - wake_up(&sctx->list_wait); + scrub_pending_trans_workers_dec(sctx); } /* @@ -789,20 +839,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) fixup_nodatasum->logical = logical; fixup_nodatasum->root = fs_info->extent_root; fixup_nodatasum->mirror_num = failed_mirror_index + 1; - /* - * increment scrubs_running to prevent cancel requests from - * completing as long as a fixup worker is running. we must also - * increment scrubs_paused to prevent deadlocking on pause - * requests used for transactions commits (as the worker uses a - * transaction context). it is safe to regard the fixup worker - * as paused for all matters practical. effectively, we only - * avoid cancellation requests from completing. - */ - mutex_lock(&fs_info->scrub_lock); - atomic_inc(&fs_info->scrubs_running); - atomic_inc(&fs_info->scrubs_paused); - mutex_unlock(&fs_info->scrub_lock); - atomic_inc(&sctx->fixup_cnt); + scrub_pending_trans_workers_inc(sctx); fixup_nodatasum->work.func = scrub_fixup_nodatasum; btrfs_queue_worker(&fs_info->scrub_workers, &fixup_nodatasum->work); @@ -1491,7 +1528,7 @@ static void scrub_submit(struct scrub_ctx *sctx) sbio = sctx->bios[sctx->curr]; sctx->curr = -1; - atomic_inc(&sctx->in_flight); + scrub_pending_bio_inc(sctx); btrfsic_submit_bio(READ, sbio->bio); } @@ -1692,8 +1729,7 @@ static void scrub_bio_end_io_worker(struct btrfs_work *work) sbio->next_free = sctx->first_free; sctx->first_free = sbio->index; spin_unlock(&sctx->list_lock); - atomic_dec(&sctx->in_flight); - wake_up(&sctx->list_wait); + scrub_pending_bio_dec(sctx); } static void scrub_block_complete(struct scrub_block *sblock) @@ -1863,7 +1899,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, logical = base + offset; wait_event(sctx->list_wait, - atomic_read(&sctx->in_flight) == 0); + atomic_read(&sctx->bios_in_flight) == 0); atomic_inc(&fs_info->scrubs_paused); wake_up(&fs_info->scrub_pause_wait); @@ -1928,7 +1964,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, /* push queued extents */ scrub_submit(sctx); wait_event(sctx->list_wait, - atomic_read(&sctx->in_flight) == 0); + atomic_read(&sctx->bios_in_flight) == 0); atomic_inc(&fs_info->scrubs_paused); wake_up(&fs_info->scrub_pause_wait); mutex_lock(&fs_info->scrub_lock); @@ -2218,7 +2254,7 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx, if (ret) return ret; } - wait_event(sctx->list_wait, atomic_read(&sctx->in_flight) == 0); + wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0); return 0; } @@ -2363,11 +2399,11 @@ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, if (!ret) ret = scrub_enumerate_chunks(sctx, dev, start, end); - wait_event(sctx->list_wait, atomic_read(&sctx->in_flight) == 0); + wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0); atomic_dec(&fs_info->scrubs_running); wake_up(&fs_info->scrub_pause_wait); - wait_event(sctx->list_wait, atomic_read(&sctx->fixup_cnt) == 0); + wait_event(sctx->list_wait, atomic_read(&sctx->workers_pending) == 0); if (progress) memcpy(progress, &sctx->stat, sizeof(*progress)); -- cgit v0.10.2 From beaf8ab3afef27ed81255d9808b67f6d390ca06f Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 12 Nov 2012 14:03:45 +0100 Subject: Btrfs: move some common code into a subfunction Some code to open block devices, to read the superblock and to handle errors was repeated multiple times in 3 places, and the following patch makes use of it as well. This code is now moved into a subfunction. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 92e586b..4def1fd 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -108,6 +108,44 @@ static noinline struct btrfs_fs_devices *find_fsid(u8 *fsid) return NULL; } +static int +btrfs_get_bdev_and_sb(const char *device_path, fmode_t flags, void *holder, + int flush, struct block_device **bdev, + struct buffer_head **bh) +{ + int ret; + + *bdev = blkdev_get_by_path(device_path, flags, holder); + + if (IS_ERR(*bdev)) { + ret = PTR_ERR(*bdev); + printk(KERN_INFO "btrfs: open %s failed\n", device_path); + goto error; + } + + if (flush) + filemap_write_and_wait((*bdev)->bd_inode->i_mapping); + ret = set_blocksize(*bdev, 4096); + if (ret) { + blkdev_put(*bdev, flags); + goto error; + } + invalidate_bdev(*bdev); + *bh = btrfs_read_dev_super(*bdev); + if (!*bh) { + ret = -EINVAL; + blkdev_put(*bdev, flags); + goto error; + } + + return 0; + +error: + *bdev = NULL; + *bh = NULL; + return ret; +} + static void requeue_list(struct btrfs_pending_bios *pending_bios, struct bio *head, struct bio *tail) { @@ -637,18 +675,10 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, if (!device->name) continue; - bdev = blkdev_get_by_path(device->name->str, flags, holder); - if (IS_ERR(bdev)) { - printk(KERN_INFO "btrfs: open %s failed\n", device->name->str); - goto error; - } - filemap_write_and_wait(bdev->bd_inode->i_mapping); - invalidate_bdev(bdev); - set_blocksize(bdev, 4096); - - bh = btrfs_read_dev_super(bdev); - if (!bh) - goto error_close; + ret = btrfs_get_bdev_and_sb(device->name->str, flags, holder, 1, + &bdev, &bh); + if (ret) + continue; disk_super = (struct btrfs_super_block *)bh->b_data; devid = btrfs_stack_device_id(&disk_super->dev_item); @@ -697,9 +727,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, error_brelse: brelse(bh); -error_close: blkdev_put(bdev, flags); -error: continue; } if (fs_devices->open_devices == 0) { @@ -744,22 +772,10 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, u64 total_devices; flags |= FMODE_EXCL; - bdev = blkdev_get_by_path(path, flags, holder); - - if (IS_ERR(bdev)) { - ret = PTR_ERR(bdev); - goto error; - } - mutex_lock(&uuid_mutex); - ret = set_blocksize(bdev, 4096); + ret = btrfs_get_bdev_and_sb(path, flags, holder, 0, &bdev, &bh); if (ret) - goto error_close; - bh = btrfs_read_dev_super(bdev); - if (!bh) { - ret = -EINVAL; - goto error_close; - } + goto error; disk_super = (struct btrfs_super_block *)bh->b_data; devid = btrfs_stack_device_id(&disk_super->dev_item); transid = btrfs_super_generation(disk_super); @@ -777,10 +793,9 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, if (!ret && fs_devices_ret) (*fs_devices_ret)->total_devices = total_devices; brelse(bh); -error_close: - mutex_unlock(&uuid_mutex); blkdev_put(bdev, flags); error: + mutex_unlock(&uuid_mutex); return ret; } @@ -1374,20 +1389,12 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) goto out; } } else { - bdev = blkdev_get_by_path(device_path, FMODE_READ | FMODE_EXCL, - root->fs_info->bdev_holder); - if (IS_ERR(bdev)) { - ret = PTR_ERR(bdev); + ret = btrfs_get_bdev_and_sb(device_path, + FMODE_READ | FMODE_EXCL, + root->fs_info->bdev_holder, 0, + &bdev, &bh); + if (ret) goto out; - } - - set_blocksize(bdev, 4096); - invalidate_bdev(bdev); - bh = btrfs_read_dev_super(bdev); - if (!bh) { - ret = -EINVAL; - goto error_close; - } disk_super = (struct btrfs_super_block *)bh->b_data; devid = btrfs_stack_device_id(&disk_super->dev_item); dev_uuid = disk_super->dev_item.uuid; -- cgit v0.10.2 From 7ba15b7d211846c187a7c5dc75a5964476f8bc89 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 14:42:30 +0100 Subject: Btrfs: add two more find_device() methods The new function btrfs_find_device_missing_or_by_path() will be used for the device replace procedure. This function itself calls the second new function btrfs_find_device_by_path(). Unfortunately, it is not possible to currently make the rest of the code use these functions as well, since all functions that look similar at first view are all a little bit different in what they are doing. But in the future, new code could benefit from these two new functions, and currently, device replace uses them. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 4def1fd..1483041 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1522,6 +1522,65 @@ error_undo: goto error_brelse; } +int btrfs_find_device_by_path(struct btrfs_root *root, char *device_path, + struct btrfs_device **device) +{ + int ret = 0; + struct btrfs_super_block *disk_super; + u64 devid; + u8 *dev_uuid; + struct block_device *bdev; + struct buffer_head *bh; + + *device = NULL; + ret = btrfs_get_bdev_and_sb(device_path, FMODE_READ, + root->fs_info->bdev_holder, 0, &bdev, &bh); + if (ret) + return ret; + disk_super = (struct btrfs_super_block *)bh->b_data; + devid = btrfs_stack_device_id(&disk_super->dev_item); + dev_uuid = disk_super->dev_item.uuid; + *device = btrfs_find_device(root, devid, dev_uuid, + disk_super->fsid); + brelse(bh); + if (!*device) + ret = -ENOENT; + blkdev_put(bdev, FMODE_READ); + return ret; +} + +int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, + char *device_path, + struct btrfs_device **device) +{ + *device = NULL; + if (strcmp(device_path, "missing") == 0) { + struct list_head *devices; + struct btrfs_device *tmp; + + devices = &root->fs_info->fs_devices->devices; + /* + * It is safe to read the devices since the volume_mutex + * is held by the caller. + */ + list_for_each_entry(tmp, devices, dev_list) { + if (tmp->in_fs_metadata && !tmp->bdev) { + *device = tmp; + break; + } + } + + if (!*device) { + pr_err("btrfs: no missing device found\n"); + return -ENOENT; + } + + return 0; + } else { + return btrfs_find_device_by_path(root, device_path, device); + } +} + /* * does all the dirty work required for changing file system's UUID. */ diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 1789cda..657bb12 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -268,6 +268,11 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, struct btrfs_fs_devices **fs_devices_ret); int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices); +int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, + char *device_path, + struct btrfs_device **device); +int btrfs_find_device_by_path(struct btrfs_root *root, char *device_path, + struct btrfs_device **device); int btrfs_add_device(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_device *device); -- cgit v0.10.2 From 5d9640517d92d05843711ea982cbeff42d7ed32d Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 14:59:07 +0100 Subject: Btrfs: Pass fs_info to btrfs_num_copies() instead of mapping_tree This is required for the device replace procedure in a later step. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index 5a3e45d..58dfac1 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -723,7 +723,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state, } num_copies = - btrfs_num_copies(&state->root->fs_info->mapping_tree, + btrfs_num_copies(state->root->fs_info, next_bytenr, state->metablock_size); if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", @@ -903,7 +903,7 @@ static int btrfsic_process_superblock_dev_mirror( } num_copies = - btrfs_num_copies(&state->root->fs_info->mapping_tree, + btrfs_num_copies(state->root->fs_info, next_bytenr, state->metablock_size); if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", @@ -1287,7 +1287,7 @@ static int btrfsic_create_link_to_next_block( *next_blockp = NULL; if (0 == *num_copiesp) { *num_copiesp = - btrfs_num_copies(&state->root->fs_info->mapping_tree, + btrfs_num_copies(state->root->fs_info, next_bytenr, state->metablock_size); if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", @@ -1489,7 +1489,7 @@ static int btrfsic_handle_extent_data( chunk_len = num_bytes; num_copies = - btrfs_num_copies(&state->root->fs_info->mapping_tree, + btrfs_num_copies(state->root->fs_info, next_bytenr, state->datablock_size); if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", @@ -2463,7 +2463,7 @@ static int btrfsic_process_written_superblock( } num_copies = - btrfs_num_copies(&state->root->fs_info->mapping_tree, + btrfs_num_copies(state->root->fs_info, next_bytenr, BTRFS_SUPER_INFO_SIZE); if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", @@ -2960,7 +2960,7 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state, struct btrfsic_block_data_ctx block_ctx; int match = 0; - num_copies = btrfs_num_copies(&state->root->fs_info->mapping_tree, + num_copies = btrfs_num_copies(state->root->fs_info, bytenr, state->metablock_size); for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) { diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index ff5d259..ba2b931 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -387,7 +387,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags)) break; - num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, + num_copies = btrfs_num_copies(root->fs_info, eb->start, eb->len); if (num_copies == 1) break; diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 3c062c8..e0b7138 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2044,10 +2044,10 @@ static int clean_io_failure(u64 start, struct page *page) spin_unlock(&BTRFS_I(inode)->io_tree.lock); if (state && state->start == failrec->start) { - map_tree = &BTRFS_I(inode)->root->fs_info->mapping_tree; - num_copies = btrfs_num_copies(map_tree, failrec->logical, - failrec->len); + num_copies = btrfs_num_copies(BTRFS_I(inode)->root->fs_info, + failrec->logical, failrec->len); if (num_copies > 1) { + map_tree = &BTRFS_I(inode)->root->fs_info->mapping_tree; ret = repair_io_failure(map_tree, start, failrec->len, failrec->logical, page, failrec->failed_mirror); @@ -2157,9 +2157,8 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page, * clean_io_failure() clean all those errors at once. */ } - num_copies = btrfs_num_copies( - &BTRFS_I(inode)->root->fs_info->mapping_tree, - failrec->logical, failrec->len); + num_copies = btrfs_num_copies(BTRFS_I(inode)->root->fs_info, + failrec->logical, failrec->len); if (num_copies == 1) { /* * we only have a single copy of the data, so don't bother with diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 1483041..5612767 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3785,8 +3785,9 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree) } } -int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len) +int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) { + struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; struct extent_map *em; struct map_lookup *map; struct extent_map_tree *em_tree = &map_tree->map_tree; diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 657bb12..35ea442 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -278,7 +278,7 @@ int btrfs_add_device(struct btrfs_trans_handle *trans, struct btrfs_device *device); int btrfs_rm_device(struct btrfs_root *root, char *device_path); void btrfs_cleanup_fs_uuids(void); -int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); +int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len); int btrfs_grow_device(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 new_size); struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid, -- cgit v0.10.2 From 3ec706c831d4c96905c287013c8228b21619a1d9 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 15:46:42 +0100 Subject: Btrfs: pass fs_info to btrfs_map_block() instead of mapping_tree This is required for the device replace procedure in a later step. Two calling functions also had to be changed to have the fs_info pointer: repair_io_failure() and scrub_setup_recheck_block(). Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index 58dfac1..8f9abed 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -1582,7 +1582,7 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len, struct btrfs_device *device; length = len; - ret = btrfs_map_block(&state->root->fs_info->mapping_tree, READ, + ret = btrfs_map_block(state->root->fs_info, READ, bytenr, &length, &multi, mirror_num); device = multi->stripes[0].dev; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index f8a358a..b4d438f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1818,7 +1818,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, /* Tell the block device(s) that the sectors can be discarded */ - ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD, + ret = btrfs_map_block(root->fs_info, REQ_DISCARD, bytenr, &num_bytes, &bbio, 0); /* Error condition is -ENOMEM */ if (!ret) { diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index e0b7138..62ec6e4 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1917,12 +1917,12 @@ static void repair_io_failure_callback(struct bio *bio, int err) * the standard behavior is to write all copies in a raid setup. here we only * want to write the one bad copy. so we do the mapping for ourselves and issue * submit_bio directly. - * to avoid any synchonization issues, wait for the data after writing, which + * to avoid any synchronization issues, wait for the data after writing, which * actually prevents the read that triggered the error from finishing. * currently, there can be no more than two copies of every data bit. thus, * exactly one rewrite is required. */ -int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start, +int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start, u64 length, u64 logical, struct page *page, int mirror_num) { @@ -1944,7 +1944,7 @@ int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start, bio->bi_size = 0; map_length = length; - ret = btrfs_map_block(map_tree, WRITE, logical, + ret = btrfs_map_block(fs_info, WRITE, logical, &map_length, &bbio, mirror_num); if (ret) { bio_put(bio); @@ -1982,14 +1982,13 @@ int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start, int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb, int mirror_num) { - struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; u64 start = eb->start; unsigned long i, num_pages = num_extent_pages(eb->start, eb->len); int ret = 0; for (i = 0; i < num_pages; i++) { struct page *p = extent_buffer_page(eb, i); - ret = repair_io_failure(map_tree, start, PAGE_CACHE_SIZE, + ret = repair_io_failure(root->fs_info, start, PAGE_CACHE_SIZE, start, p, mirror_num); if (ret) break; @@ -2008,7 +2007,7 @@ static int clean_io_failure(u64 start, struct page *page) u64 private; u64 private_failure; struct io_failure_record *failrec; - struct btrfs_mapping_tree *map_tree; + struct btrfs_fs_info *fs_info; struct extent_state *state; int num_copies; int did_repair = 0; @@ -2044,11 +2043,11 @@ static int clean_io_failure(u64 start, struct page *page) spin_unlock(&BTRFS_I(inode)->io_tree.lock); if (state && state->start == failrec->start) { - num_copies = btrfs_num_copies(BTRFS_I(inode)->root->fs_info, - failrec->logical, failrec->len); + fs_info = BTRFS_I(inode)->root->fs_info; + num_copies = btrfs_num_copies(fs_info, failrec->logical, + failrec->len); if (num_copies > 1) { - map_tree = &BTRFS_I(inode)->root->fs_info->mapping_tree; - ret = repair_io_failure(map_tree, start, failrec->len, + ret = repair_io_failure(fs_info, start, failrec->len, failrec->logical, page, failrec->failed_mirror); did_repair = !ret; diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 711d12b..2eacfab 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -337,9 +337,9 @@ struct bio * btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, gfp_t gfp_flags); -struct btrfs_mapping_tree; +struct btrfs_fs_info; -int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start, +int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start, u64 length, u64 logical, struct page *page, int mirror_num); int end_extent_writepage(struct page *page, int err, u64 start, u64 end); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index aabf747..5d1675a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1549,7 +1549,6 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, unsigned long bio_flags) { struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; - struct btrfs_mapping_tree *map_tree; u64 logical = (u64)bio->bi_sector << 9; u64 length = 0; u64 map_length; @@ -1559,11 +1558,10 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, return 0; length = bio->bi_size; - map_tree = &root->fs_info->mapping_tree; map_length = length; - ret = btrfs_map_block(map_tree, READ, logical, + ret = btrfs_map_block(root->fs_info, READ, logical, &map_length, NULL, 0); - /* Will always return 0 or 1 with map_multi == NULL */ + /* Will always return 0 with map_multi == NULL */ BUG_ON(ret < 0); if (map_length < length + size) return 1; @@ -6364,7 +6362,6 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, { struct inode *inode = dip->inode; struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; struct bio *bio; struct bio *orig_bio = dip->orig_bio; struct bio_vec *bvec = orig_bio->bi_io_vec; @@ -6377,7 +6374,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, int async_submit = 0; map_length = orig_bio->bi_size; - ret = btrfs_map_block(map_tree, READ, start_sector << 9, + ret = btrfs_map_block(root->fs_info, READ, start_sector << 9, &map_length, NULL, 0); if (ret) { bio_put(orig_bio); @@ -6431,7 +6428,8 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, bio->bi_end_io = btrfs_end_dio_bio; map_length = orig_bio->bi_size; - ret = btrfs_map_block(map_tree, READ, start_sector << 9, + ret = btrfs_map_block(root->fs_info, READ, + start_sector << 9, &map_length, NULL, 0); if (ret) { bio_put(bio); diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index a955669..0ddc565 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -323,7 +323,6 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, struct reada_extent *re = NULL; struct reada_extent *re_exist = NULL; struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; struct btrfs_bio *bbio = NULL; struct btrfs_device *dev; struct btrfs_device *prev_dev; @@ -358,7 +357,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, * map block */ length = blocksize; - ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length, &bbio, 0); + ret = btrfs_map_block(fs_info, REQ_WRITE, logical, &length, &bbio, 0); if (ret || !bbio || length < blocksize) goto error; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index a67b1a1..894bb27 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -152,7 +152,7 @@ static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx); static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx); static int scrub_handle_errored_block(struct scrub_block *sblock_to_check); static int scrub_setup_recheck_block(struct scrub_ctx *sctx, - struct btrfs_mapping_tree *map_tree, + struct btrfs_fs_info *fs_info, u64 length, u64 logical, struct scrub_block *sblock); static void scrub_recheck_block(struct btrfs_fs_info *fs_info, @@ -523,7 +523,7 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *ctx) } if (PageUptodate(page)) { - struct btrfs_mapping_tree *map_tree; + struct btrfs_fs_info *fs_info; if (PageDirty(page)) { /* * we need to write the data to the defect sector. the @@ -544,8 +544,8 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *ctx) ret = -EIO; goto out; } - map_tree = &BTRFS_I(inode)->root->fs_info->mapping_tree; - ret = repair_io_failure(map_tree, offset, PAGE_SIZE, + fs_info = BTRFS_I(inode)->root->fs_info; + ret = repair_io_failure(fs_info, offset, PAGE_SIZE, fixup->logical, page, fixup->mirror_num); unlock_page(page); @@ -754,7 +754,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) } /* setup the context, map the logical blocks and alloc the pages */ - ret = scrub_setup_recheck_block(sctx, &fs_info->mapping_tree, length, + ret = scrub_setup_recheck_block(sctx, fs_info, length, logical, sblocks_for_recheck); if (ret) { spin_lock(&sctx->stat_lock); @@ -1012,7 +1012,7 @@ out: } static int scrub_setup_recheck_block(struct scrub_ctx *sctx, - struct btrfs_mapping_tree *map_tree, + struct btrfs_fs_info *fs_info, u64 length, u64 logical, struct scrub_block *sblocks_for_recheck) { @@ -1036,7 +1036,7 @@ static int scrub_setup_recheck_block(struct scrub_ctx *sctx, * with a length of PAGE_SIZE, each returned stripe * represents one mirror */ - ret = btrfs_map_block(map_tree, WRITE, logical, &mapped_length, + ret = btrfs_map_block(fs_info, WRITE, logical, &mapped_length, &bbio, 0); if (ret || !bbio || mapped_length < sublen) { kfree(bbio); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5612767..96bb2e4 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3826,13 +3826,14 @@ static int find_live_mirror(struct map_lookup *map, int first, int num, return optimal; } -static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, +static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, u64 logical, u64 *length, struct btrfs_bio **bbio_ret, int mirror_num) { struct extent_map *em; struct map_lookup *map; + struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; struct extent_map_tree *em_tree = &map_tree->map_tree; u64 offset; u64 stripe_offset; @@ -4061,11 +4062,11 @@ out: return ret; } -int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, +int btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, u64 logical, u64 *length, struct btrfs_bio **bbio_ret, int mirror_num) { - return __btrfs_map_block(map_tree, rw, logical, length, bbio_ret, + return __btrfs_map_block(fs_info, rw, logical, length, bbio_ret, mirror_num); } @@ -4394,7 +4395,6 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, int mirror_num, int async_submit) { - struct btrfs_mapping_tree *map_tree; struct btrfs_device *dev; struct bio *first_bio = bio; u64 logical = (u64)bio->bi_sector << 9; @@ -4406,10 +4406,9 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, struct btrfs_bio *bbio = NULL; length = bio->bi_size; - map_tree = &root->fs_info->mapping_tree; map_length = length; - ret = btrfs_map_block(map_tree, rw, logical, &map_length, &bbio, + ret = btrfs_map_block(root->fs_info, rw, logical, &map_length, &bbio, mirror_num); if (ret) /* -ENOMEM */ return ret; diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 35ea442..ad5566d 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -248,7 +248,7 @@ int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 start, u64 num_bytes); -int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, +int btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, u64 logical, u64 *length, struct btrfs_bio **bbio_ret, int mirror_num); int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, -- cgit v0.10.2 From a8a6dab77997a371f1925a4001021eea3ee5cb88 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 15:50:14 +0100 Subject: Btrfs: add btrfs_scratch_superblock() function This new function is used by the device replace procedure in a later patch. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 96bb2e4..6cd8a32 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5106,3 +5106,21 @@ int btrfs_get_dev_stats(struct btrfs_root *root, stats->nr_items = BTRFS_DEV_STAT_VALUES_MAX; return 0; } + +int btrfs_scratch_superblock(struct btrfs_device *device) +{ + struct buffer_head *bh; + struct btrfs_super_block *disk_super; + + bh = btrfs_read_dev_super(device->bdev); + if (!bh) + return -EINVAL; + disk_super = (struct btrfs_super_block *)bh->b_data; + + memset(&disk_super->magic, 0, sizeof(disk_super->magic)); + set_buffer_dirty(bh); + sync_dirty_buffer(bh); + brelse(bh); + + return 0; +} diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index ad5566d..7eaaf4e 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -301,6 +301,7 @@ int btrfs_get_dev_stats(struct btrfs_root *root, int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info); int btrfs_run_dev_stats(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info); +int btrfs_scratch_superblock(struct btrfs_device *device); static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, int index) -- cgit v0.10.2 From aa1b8cd409f05e1489ec77ff219eff6ed4b801b8 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 17:03:39 +0100 Subject: Btrfs: pass fs_info instead of root A small number of functions that are used in a device replace procedure when the operation is resumed at mount time are unable to pass the same root pointer that would be used in the regular (ioctl) context. And since the root pointer is not required, only the fs_info is, the root pointer argument is replaced with the fs_info pointer argument. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f9a0786..f8bb62c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3540,15 +3540,16 @@ int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, struct btrfs_pending_snapshot *pending); /* scrub.c */ -int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, - struct btrfs_scrub_progress *progress, int readonly); +int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, + u64 end, struct btrfs_scrub_progress *progress, + int readonly); void btrfs_scrub_pause(struct btrfs_root *root); void btrfs_scrub_pause_super(struct btrfs_root *root); void btrfs_scrub_continue(struct btrfs_root *root); void btrfs_scrub_continue_super(struct btrfs_root *root); -int __btrfs_scrub_cancel(struct btrfs_fs_info *info); -int btrfs_scrub_cancel(struct btrfs_root *root); -int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev); +int btrfs_scrub_cancel(struct btrfs_fs_info *info); +int btrfs_scrub_cancel_dev(struct btrfs_fs_info *info, + struct btrfs_device *dev); int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid); int btrfs_scrub_progress(struct btrfs_root *root, u64 devid, struct btrfs_scrub_progress *progress); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index ba2b931..42a8024 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3283,9 +3283,9 @@ int close_ctree(struct btrfs_root *root) smp_mb(); /* pause restriper - we want to resume on mount */ - btrfs_pause_balance(root->fs_info); + btrfs_pause_balance(fs_info); - btrfs_scrub_cancel(root); + btrfs_scrub_cancel(fs_info); /* wait for any defraggers to finish */ wait_event(fs_info->transaction_wait, diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index e262cd8..b40b827 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1343,7 +1343,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, printk(KERN_INFO "btrfs: resizing devid %llu\n", (unsigned long long)devid); } - device = btrfs_find_device(root, devid, NULL, NULL); + device = btrfs_find_device(root->fs_info, devid, NULL, NULL); if (!device) { printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", (unsigned long long)devid); @@ -2332,7 +2332,7 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg) s_uuid = di_args->uuid; mutex_lock(&fs_devices->device_list_mutex); - dev = btrfs_find_device(root, di_args->devid, s_uuid, NULL); + dev = btrfs_find_device(root->fs_info, di_args->devid, s_uuid, NULL); mutex_unlock(&fs_devices->device_list_mutex); if (!dev) { @@ -3089,7 +3089,7 @@ static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg) if (IS_ERR(sa)) return PTR_ERR(sa); - ret = btrfs_scrub_dev(root, sa->devid, sa->start, sa->end, + ret = btrfs_scrub_dev(root->fs_info, sa->devid, sa->start, sa->end, &sa->progress, sa->flags & BTRFS_SCRUB_READONLY); if (copy_to_user(arg, sa, sizeof(*sa))) @@ -3104,7 +3104,7 @@ static long btrfs_ioctl_scrub_cancel(struct btrfs_root *root, void __user *arg) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - return btrfs_scrub_cancel(root); + return btrfs_scrub_cancel(root->fs_info); } static long btrfs_ioctl_scrub_progress(struct btrfs_root *root, diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 894bb27..6cf23f4 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -2262,9 +2262,8 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx, /* * get a reference count on fs_info->scrub_workers. start worker if necessary */ -static noinline_for_stack int scrub_workers_get(struct btrfs_root *root) +static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info) { - struct btrfs_fs_info *fs_info = root->fs_info; int ret = 0; mutex_lock(&fs_info->scrub_lock); @@ -2283,10 +2282,8 @@ out: return ret; } -static noinline_for_stack void scrub_workers_put(struct btrfs_root *root) +static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info) { - struct btrfs_fs_info *fs_info = root->fs_info; - mutex_lock(&fs_info->scrub_lock); if (--fs_info->scrub_workers_refcnt == 0) btrfs_stop_workers(&fs_info->scrub_workers); @@ -2294,29 +2291,29 @@ static noinline_for_stack void scrub_workers_put(struct btrfs_root *root) mutex_unlock(&fs_info->scrub_lock); } - -int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, - struct btrfs_scrub_progress *progress, int readonly) +int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, + u64 end, struct btrfs_scrub_progress *progress, + int readonly) { struct scrub_ctx *sctx; - struct btrfs_fs_info *fs_info = root->fs_info; int ret; struct btrfs_device *dev; - if (btrfs_fs_closing(root->fs_info)) + if (btrfs_fs_closing(fs_info)) return -EINVAL; /* * check some assumptions */ - if (root->nodesize != root->leafsize) { + if (fs_info->chunk_root->nodesize != fs_info->chunk_root->leafsize) { printk(KERN_ERR "btrfs_scrub: size assumption nodesize == leafsize (%d == %d) fails\n", - root->nodesize, root->leafsize); + fs_info->chunk_root->nodesize, + fs_info->chunk_root->leafsize); return -EINVAL; } - if (root->nodesize > BTRFS_STRIPE_LEN) { + if (fs_info->chunk_root->nodesize > BTRFS_STRIPE_LEN) { /* * in this case scrub is unable to calculate the checksum * the way scrub is implemented. Do not handle this @@ -2324,15 +2321,16 @@ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, */ printk(KERN_ERR "btrfs_scrub: size assumption nodesize <= BTRFS_STRIPE_LEN (%d <= %d) fails\n", - root->nodesize, BTRFS_STRIPE_LEN); + fs_info->chunk_root->nodesize, BTRFS_STRIPE_LEN); return -EINVAL; } - if (root->sectorsize != PAGE_SIZE) { + if (fs_info->chunk_root->sectorsize != PAGE_SIZE) { /* not supported for data w/o checksums */ printk(KERN_ERR "btrfs_scrub: size assumption sectorsize != PAGE_SIZE (%d != %lld) fails\n", - root->sectorsize, (unsigned long long)PAGE_SIZE); + fs_info->chunk_root->sectorsize, + (unsigned long long)PAGE_SIZE); return -EINVAL; } @@ -2352,37 +2350,37 @@ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, return -EINVAL; } - ret = scrub_workers_get(root); + ret = scrub_workers_get(fs_info); if (ret) return ret; - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - dev = btrfs_find_device(root, devid, NULL, NULL); + mutex_lock(&fs_info->fs_devices->device_list_mutex); + dev = btrfs_find_device(fs_info, devid, NULL, NULL); if (!dev || dev->missing) { - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - scrub_workers_put(root); + mutex_unlock(&fs_info->fs_devices->device_list_mutex); + scrub_workers_put(fs_info); return -ENODEV; } mutex_lock(&fs_info->scrub_lock); if (!dev->in_fs_metadata) { mutex_unlock(&fs_info->scrub_lock); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - scrub_workers_put(root); - return -ENODEV; + mutex_unlock(&fs_info->fs_devices->device_list_mutex); + scrub_workers_put(fs_info); + return -EIO; } if (dev->scrub_device) { mutex_unlock(&fs_info->scrub_lock); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - scrub_workers_put(root); + mutex_unlock(&fs_info->fs_devices->device_list_mutex); + scrub_workers_put(fs_info); return -EINPROGRESS; } sctx = scrub_setup_ctx(dev); if (IS_ERR(sctx)) { mutex_unlock(&fs_info->scrub_lock); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - scrub_workers_put(root); + mutex_unlock(&fs_info->fs_devices->device_list_mutex); + scrub_workers_put(fs_info); return PTR_ERR(sctx); } sctx->readonly = readonly; @@ -2390,7 +2388,7 @@ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, atomic_inc(&fs_info->scrubs_running); mutex_unlock(&fs_info->scrub_lock); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); + mutex_unlock(&fs_info->fs_devices->device_list_mutex); down_read(&fs_info->scrub_super_lock); ret = scrub_supers(sctx, dev); @@ -2413,7 +2411,7 @@ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end, mutex_unlock(&fs_info->scrub_lock); scrub_free_ctx(sctx); - scrub_workers_put(root); + scrub_workers_put(fs_info); return ret; } @@ -2453,9 +2451,8 @@ void btrfs_scrub_continue_super(struct btrfs_root *root) up_write(&root->fs_info->scrub_super_lock); } -int __btrfs_scrub_cancel(struct btrfs_fs_info *fs_info) +int btrfs_scrub_cancel(struct btrfs_fs_info *fs_info) { - mutex_lock(&fs_info->scrub_lock); if (!atomic_read(&fs_info->scrubs_running)) { mutex_unlock(&fs_info->scrub_lock); @@ -2475,14 +2472,9 @@ int __btrfs_scrub_cancel(struct btrfs_fs_info *fs_info) return 0; } -int btrfs_scrub_cancel(struct btrfs_root *root) +int btrfs_scrub_cancel_dev(struct btrfs_fs_info *fs_info, + struct btrfs_device *dev) { - return __btrfs_scrub_cancel(root->fs_info); -} - -int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev) -{ - struct btrfs_fs_info *fs_info = root->fs_info; struct scrub_ctx *sctx; mutex_lock(&fs_info->scrub_lock); @@ -2514,12 +2506,12 @@ int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid) * does not go away in cancel_dev. FIXME: find a better solution */ mutex_lock(&fs_info->fs_devices->device_list_mutex); - dev = btrfs_find_device(root, devid, NULL, NULL); + dev = btrfs_find_device(fs_info, devid, NULL, NULL); if (!dev) { mutex_unlock(&fs_info->fs_devices->device_list_mutex); return -ENODEV; } - ret = btrfs_scrub_cancel_dev(root, dev); + ret = btrfs_scrub_cancel_dev(fs_info, dev); mutex_unlock(&fs_info->fs_devices->device_list_mutex); return ret; @@ -2532,7 +2524,7 @@ int btrfs_scrub_progress(struct btrfs_root *root, u64 devid, struct scrub_ctx *sctx = NULL; mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - dev = btrfs_find_device(root, devid, NULL, NULL); + dev = btrfs_find_device(root->fs_info, devid, NULL, NULL); if (dev) sctx = dev->scrub_device; if (sctx) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index acd2df8..a1a6c296 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -116,7 +116,7 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info) if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { sb->s_flags |= MS_RDONLY; printk(KERN_INFO "btrfs is forced readonly\n"); - __btrfs_scrub_cancel(fs_info); + btrfs_scrub_cancel(fs_info); // WARN_ON(1); } } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 6cd8a32..d2c0bcc 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1398,7 +1398,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) disk_super = (struct btrfs_super_block *)bh->b_data; devid = btrfs_stack_device_id(&disk_super->dev_item); dev_uuid = disk_super->dev_item.uuid; - device = btrfs_find_device(root, devid, dev_uuid, + device = btrfs_find_device(root->fs_info, devid, dev_uuid, disk_super->fsid); if (!device) { ret = -ENOENT; @@ -1435,7 +1435,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) spin_unlock(&root->fs_info->free_chunk_lock); device->in_fs_metadata = 0; - btrfs_scrub_cancel_dev(root, device); + btrfs_scrub_cancel_dev(root->fs_info, device); /* * the device list mutex makes sure that we don't change @@ -1492,7 +1492,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) * at this point, the device is zero sized. We want to * remove it from the devices list and zero out the old super */ - if (clear_super) { + if (clear_super && disk_super) { /* make sure this device isn't detected as part of * the FS anymore */ @@ -1540,7 +1540,7 @@ int btrfs_find_device_by_path(struct btrfs_root *root, char *device_path, disk_super = (struct btrfs_super_block *)bh->b_data; devid = btrfs_stack_device_id(&disk_super->dev_item); dev_uuid = disk_super->dev_item.uuid; - *device = btrfs_find_device(root, devid, dev_uuid, + *device = btrfs_find_device(root->fs_info, devid, dev_uuid, disk_super->fsid); brelse(bh); if (!*device) @@ -1699,7 +1699,8 @@ next_slot: read_extent_buffer(leaf, fs_uuid, (unsigned long)btrfs_device_fsid(dev_item), BTRFS_UUID_SIZE); - device = btrfs_find_device(root, devid, dev_uuid, fs_uuid); + device = btrfs_find_device(root->fs_info, devid, dev_uuid, + fs_uuid); BUG_ON(!device); /* Logic error */ if (device->fs_devices->seeding) { @@ -4463,13 +4464,13 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, return 0; } -struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid, +struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid, u8 *uuid, u8 *fsid) { struct btrfs_device *device; struct btrfs_fs_devices *cur_devices; - cur_devices = root->fs_info->fs_devices; + cur_devices = fs_info->fs_devices; while (cur_devices) { if (!fsid || !memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE)) { @@ -4567,8 +4568,8 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, read_extent_buffer(leaf, uuid, (unsigned long) btrfs_stripe_dev_uuid_nr(chunk, i), BTRFS_UUID_SIZE); - map->stripes[i].dev = btrfs_find_device(root, devid, uuid, - NULL); + map->stripes[i].dev = btrfs_find_device(root->fs_info, devid, + uuid, NULL); if (!map->stripes[i].dev && !btrfs_test_opt(root, DEGRADED)) { kfree(map); free_extent_map(em); @@ -4686,7 +4687,7 @@ static int read_one_dev(struct btrfs_root *root, return ret; } - device = btrfs_find_device(root, devid, dev_uuid, fs_uuid); + device = btrfs_find_device(root->fs_info, devid, dev_uuid, fs_uuid); if (!device || !device->bdev) { if (!btrfs_test_opt(root, DEGRADED)) return -EIO; @@ -5078,7 +5079,7 @@ int btrfs_get_dev_stats(struct btrfs_root *root, int i; mutex_lock(&fs_devices->device_list_mutex); - dev = btrfs_find_device(root, stats->devid, NULL, NULL); + dev = btrfs_find_device(root->fs_info, stats->devid, NULL, NULL); mutex_unlock(&fs_devices->device_list_mutex); if (!dev) { diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 7eaaf4e..802e2ba 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -281,7 +281,7 @@ void btrfs_cleanup_fs_uuids(void); int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len); int btrfs_grow_device(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 new_size); -struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid, +struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid, u8 *uuid, u8 *fsid); int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); int btrfs_init_new_device(struct btrfs_root *root, char *path); -- cgit v0.10.2 From 1acd6831d98779c88cd57f0a5826d6df0b09f3fa Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 17:11:06 +0100 Subject: Btrfs: avoid risk of a deadlock in btrfs_handle_error Remove the attempt to cancel a running scrub or device replace operation in btrfs_handle_error() because it adds the risk of a deadlock. The only penalty of not canceling the operation is that some I/O remains active until the procedure completes. This is basically the same thing that happens to other tasks that are running in user mode context, they are not affected or stopped in btrfs_handle_error(), these tasks just need to handle write errors correctly. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index a1a6c296..ef24158 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -116,7 +116,16 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info) if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { sb->s_flags |= MS_RDONLY; printk(KERN_INFO "btrfs is forced readonly\n"); - btrfs_scrub_cancel(fs_info); + /* + * Note that a running device replace operation is not + * canceled here although there is no way to update + * the progress. It would add the risk of a deadlock, + * therefore the canceling is ommited. The only penalty + * is that some I/O remains active until the procedure + * completes. The next time when the filesystem is + * mounted writeable again, the device replace + * operation continues. + */ // WARN_ON(1); } } -- cgit v0.10.2 From e922e087a35c437acef3bc88ce31e59c699c38bd Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 17:26:40 +0100 Subject: Btrfs: enhance btrfs structures for device replace support Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f8bb62c..0781fd4 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -885,6 +885,42 @@ struct btrfs_dev_stats_item { __le64 values[BTRFS_DEV_STAT_VALUES_MAX]; } __attribute__ ((__packed__)); +#define BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_ALWAYS 0 +#define BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_AVOID 1 +#define BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED 0 +#define BTRFS_DEV_REPLACE_ITEM_STATE_STARTED 1 +#define BTRFS_DEV_REPLACE_ITEM_STATE_SUSPENDED 2 +#define BTRFS_DEV_REPLACE_ITEM_STATE_FINISHED 3 +#define BTRFS_DEV_REPLACE_ITEM_STATE_CANCELED 4 + +struct btrfs_dev_replace { + u64 replace_state; /* see #define above */ + u64 time_started; /* seconds since 1-Jan-1970 */ + u64 time_stopped; /* seconds since 1-Jan-1970 */ + atomic64_t num_write_errors; + atomic64_t num_uncorrectable_read_errors; + + u64 cursor_left; + u64 committed_cursor_left; + u64 cursor_left_last_write_of_item; + u64 cursor_right; + + u64 cont_reading_from_srcdev_mode; /* see #define above */ + + int is_valid; + int item_needs_writeback; + struct btrfs_device *srcdev; + struct btrfs_device *tgtdev; + + pid_t lock_owner; + atomic_t nesting_level; + struct mutex lock_finishing_cancel_unmount; + struct mutex lock_management_lock; + struct mutex lock; + + struct btrfs_scrub_progress scrub_progress; +}; + /* different types of block groups (and chunks) */ #define BTRFS_BLOCK_GROUP_DATA (1ULL << 0) #define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1) @@ -1471,6 +1507,9 @@ struct btrfs_fs_info { int backup_root_index; int num_tolerated_disk_barrier_failures; + + /* device replace state */ + struct btrfs_dev_replace dev_replace; }; /* diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 42a8024..9d1b710 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2131,6 +2131,11 @@ int open_ctree(struct super_block *sb, init_rwsem(&fs_info->extent_commit_sem); init_rwsem(&fs_info->cleanup_work_sem); init_rwsem(&fs_info->subvol_sem); + fs_info->dev_replace.lock_owner = 0; + atomic_set(&fs_info->dev_replace.nesting_level, 0); + mutex_init(&fs_info->dev_replace.lock_finishing_cancel_unmount); + mutex_init(&fs_info->dev_replace.lock_management_lock); + mutex_init(&fs_info->dev_replace.lock); spin_lock_init(&fs_info->qgroup_lock); fs_info->qgroup_tree = RB_ROOT; -- cgit v0.10.2 From a2bff64025d7a707ac49155bb6678a636e55096e Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 17:32:20 +0100 Subject: Btrfs: introduce a btrfs_dev_replace_item type Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 0781fd4..147406d 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -921,6 +921,23 @@ struct btrfs_dev_replace { struct btrfs_scrub_progress scrub_progress; }; +struct btrfs_dev_replace_item { + /* + * grow this item struct at the end for future enhancements and keep + * the existing values unchanged + */ + __le64 src_devid; + __le64 cursor_left; + __le64 cursor_right; + __le64 cont_reading_from_srcdev_mode; + + __le64 replace_state; + __le64 time_started; + __le64 time_stopped; + __le64 num_write_errors; + __le64 num_uncorrectable_read_errors; +} __attribute__ ((__packed__)); + /* different types of block groups (and chunks) */ #define BTRFS_BLOCK_GROUP_DATA (1ULL << 0) #define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1) @@ -1763,6 +1780,12 @@ struct btrfs_ioctl_defrag_range_args { #define BTRFS_DEV_STATS_KEY 249 /* + * Persistantly stores the device replace state in the device tree. + * The key is built like this: (0, BTRFS_DEV_REPLACE_KEY, 0). + */ +#define BTRFS_DEV_REPLACE_KEY 250 + +/* * string items are for debugging. They just store a short string of * data in the FS */ @@ -2795,6 +2818,49 @@ BTRFS_SETGET_FUNCS(qgroup_limit_rsv_rfer, struct btrfs_qgroup_limit_item, BTRFS_SETGET_FUNCS(qgroup_limit_rsv_excl, struct btrfs_qgroup_limit_item, rsv_excl, 64); +/* btrfs_dev_replace_item */ +BTRFS_SETGET_FUNCS(dev_replace_src_devid, + struct btrfs_dev_replace_item, src_devid, 64); +BTRFS_SETGET_FUNCS(dev_replace_cont_reading_from_srcdev_mode, + struct btrfs_dev_replace_item, cont_reading_from_srcdev_mode, + 64); +BTRFS_SETGET_FUNCS(dev_replace_replace_state, struct btrfs_dev_replace_item, + replace_state, 64); +BTRFS_SETGET_FUNCS(dev_replace_time_started, struct btrfs_dev_replace_item, + time_started, 64); +BTRFS_SETGET_FUNCS(dev_replace_time_stopped, struct btrfs_dev_replace_item, + time_stopped, 64); +BTRFS_SETGET_FUNCS(dev_replace_num_write_errors, struct btrfs_dev_replace_item, + num_write_errors, 64); +BTRFS_SETGET_FUNCS(dev_replace_num_uncorrectable_read_errors, + struct btrfs_dev_replace_item, num_uncorrectable_read_errors, + 64); +BTRFS_SETGET_FUNCS(dev_replace_cursor_left, struct btrfs_dev_replace_item, + cursor_left, 64); +BTRFS_SETGET_FUNCS(dev_replace_cursor_right, struct btrfs_dev_replace_item, + cursor_right, 64); + +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_src_devid, + struct btrfs_dev_replace_item, src_devid, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cont_reading_from_srcdev_mode, + struct btrfs_dev_replace_item, + cont_reading_from_srcdev_mode, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_replace_state, + struct btrfs_dev_replace_item, replace_state, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_started, + struct btrfs_dev_replace_item, time_started, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_stopped, + struct btrfs_dev_replace_item, time_stopped, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_write_errors, + struct btrfs_dev_replace_item, num_write_errors, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_uncorrectable_read_errors, + struct btrfs_dev_replace_item, + num_uncorrectable_read_errors, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_left, + struct btrfs_dev_replace_item, cursor_left, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right, + struct btrfs_dev_replace_item, cursor_right, 64); + static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb) { return sb->s_fs_info; diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index 5e23684..50d95fd 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -297,6 +297,9 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) case BTRFS_DEV_STATS_KEY: printk(KERN_INFO "\t\tdevice stats\n"); break; + case BTRFS_DEV_REPLACE_KEY: + printk(KERN_INFO "\t\tdev replace\n"); + break; }; } } -- cgit v0.10.2 From 5ac00addc7ac09110995fe967071d191b5981cc1 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 17:54:08 +0100 Subject: Btrfs: disallow mutually exclusive admin operations from user mode Btrfs admin operations that are manually started from user mode and that cannot be executed at the same time return -EINPROGRESS. A common way to enter and leave this locked section is introduced since it used to be specific to the balance operation. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 147406d..e9dc780 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1527,6 +1527,8 @@ struct btrfs_fs_info { /* device replace state */ struct btrfs_dev_replace dev_replace; + + atomic_t mutually_exclusive_operation_running; }; /* diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index b40b827..26f46da 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1317,13 +1317,13 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - mutex_lock(&root->fs_info->volume_mutex); - if (root->fs_info->balance_ctl) { - printk(KERN_INFO "btrfs: balance in progress\n"); - ret = -EINVAL; - goto out; + if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, + 1)) { + pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); + return -EINPROGRESS; } + mutex_lock(&root->fs_info->volume_mutex); vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) { ret = PTR_ERR(vol_args); @@ -1419,6 +1419,7 @@ out_free: kfree(vol_args); out: mutex_unlock(&root->fs_info->volume_mutex); + atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); return ret; } @@ -2160,9 +2161,17 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) if (btrfs_root_readonly(root)) return -EROFS; + if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, + 1)) { + pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); + return -EINPROGRESS; + } ret = mnt_want_write_file(file); - if (ret) + if (ret) { + atomic_set(&root->fs_info->mutually_exclusive_operation_running, + 0); return ret; + } switch (inode->i_mode & S_IFMT) { case S_IFDIR: @@ -2214,6 +2223,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) } out: mnt_drop_write_file(file); + atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); return ret; } @@ -2225,13 +2235,13 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - mutex_lock(&root->fs_info->volume_mutex); - if (root->fs_info->balance_ctl) { - printk(KERN_INFO "btrfs: balance in progress\n"); - ret = -EINVAL; - goto out; + if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, + 1)) { + pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); + return -EINPROGRESS; } + mutex_lock(&root->fs_info->volume_mutex); vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) { ret = PTR_ERR(vol_args); @@ -2244,6 +2254,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) kfree(vol_args); out: mutex_unlock(&root->fs_info->volume_mutex); + atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); return ret; } @@ -2258,13 +2269,13 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) if (root->fs_info->sb->s_flags & MS_RDONLY) return -EROFS; - mutex_lock(&root->fs_info->volume_mutex); - if (root->fs_info->balance_ctl) { - printk(KERN_INFO "btrfs: balance in progress\n"); - ret = -EINVAL; - goto out; + if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, + 1)) { + pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); + return -EINPROGRESS; } + mutex_lock(&root->fs_info->volume_mutex); vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) { ret = PTR_ERR(vol_args); @@ -2277,6 +2288,7 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) kfree(vol_args); out: mutex_unlock(&root->fs_info->volume_mutex); + atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); return ret; } @@ -3319,6 +3331,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) struct btrfs_ioctl_balance_args *bargs; struct btrfs_balance_control *bctl; int ret; + int need_to_clear_lock = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -3354,10 +3367,13 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg) bargs = NULL; } - if (fs_info->balance_ctl) { + if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, + 1)) { + pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n"); ret = -EINPROGRESS; goto out_bargs; } + need_to_clear_lock = 1; bctl = kzalloc(sizeof(*bctl), GFP_NOFS); if (!bctl) { @@ -3391,6 +3407,9 @@ do_balance: out_bargs: kfree(bargs); out: + if (need_to_clear_lock) + atomic_set(&root->fs_info->mutually_exclusive_operation_running, + 0); mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); mnt_drop_write_file(file); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d2c0bcc..33ca36b 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2952,6 +2952,7 @@ static int balance_kthread(void *data) ret = btrfs_balance(fs_info->balance_ctl, NULL); } + atomic_set(&fs_info->mutually_exclusive_operation_running, 0); mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); @@ -2974,6 +2975,7 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info) return 0; } + WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)); tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance"); if (IS_ERR(tsk)) return PTR_ERR(tsk); -- cgit v0.10.2 From 63a212abc2315972b245f93cb11ae3acf3c0b513 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 18:29:28 +0100 Subject: Btrfs: disallow some operations on the device replace target device This patch adds some code to disallow operations on the device that is used as the target for the device replace operation. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index e9dc780..746cb6a 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3649,7 +3649,7 @@ int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, /* scrub.c */ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, u64 end, struct btrfs_scrub_progress *progress, - int readonly); + int readonly, int is_dev_replace); void btrfs_scrub_pause(struct btrfs_root *root); void btrfs_scrub_pause_super(struct btrfs_root *root); void btrfs_scrub_continue(struct btrfs_root *root); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b4d438f..98af837 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -7468,7 +7468,8 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) * check to make sure we can actually find a chunk with enough * space to fit our block group in. */ - if (device->total_bytes > device->bytes_used + min_free) { + if (device->total_bytes > device->bytes_used + min_free && + !device->is_tgtdev_for_dev_replace) { ret = find_free_dev_extent(device, min_free, &dev_offset, NULL); if (!ret) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 26f46da..e54b5e5 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -1375,6 +1375,11 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, } } + if (device->is_tgtdev_for_dev_replace) { + ret = -EINVAL; + goto out_free; + } + old_size = device->total_bytes; if (mod < 0) { @@ -3102,7 +3107,8 @@ static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg) return PTR_ERR(sa); ret = btrfs_scrub_dev(root->fs_info, sa->devid, sa->start, sa->end, - &sa->progress, sa->flags & BTRFS_SCRUB_READONLY); + &sa->progress, sa->flags & BTRFS_SCRUB_READONLY, + 0); if (copy_to_user(arg, sa, sizeof(*sa))) ret = -EFAULT; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 6cf23f4..460e30b 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -116,6 +116,9 @@ struct scrub_ctx { u32 sectorsize; u32 nodesize; u32 leafsize; + + int is_dev_replace; + /* * statistics */ @@ -284,7 +287,7 @@ static noinline_for_stack void scrub_free_ctx(struct scrub_ctx *sctx) } static noinline_for_stack -struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev) +struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace) { struct scrub_ctx *sctx; int i; @@ -296,6 +299,7 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev) sctx = kzalloc(sizeof(*sctx), GFP_NOFS); if (!sctx) goto nomem; + sctx->is_dev_replace = is_dev_replace; sctx->pages_per_bio = pages_per_bio; sctx->curr = -1; sctx->dev_root = dev->dev_root; @@ -2293,7 +2297,7 @@ static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info) int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, u64 end, struct btrfs_scrub_progress *progress, - int readonly) + int readonly, int is_dev_replace) { struct scrub_ctx *sctx; int ret; @@ -2356,14 +2360,14 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, mutex_lock(&fs_info->fs_devices->device_list_mutex); dev = btrfs_find_device(fs_info, devid, NULL, NULL); - if (!dev || dev->missing) { + if (!dev || (dev->missing && !is_dev_replace)) { mutex_unlock(&fs_info->fs_devices->device_list_mutex); scrub_workers_put(fs_info); return -ENODEV; } mutex_lock(&fs_info->scrub_lock); - if (!dev->in_fs_metadata) { + if (!dev->in_fs_metadata || dev->is_tgtdev_for_dev_replace) { mutex_unlock(&fs_info->scrub_lock); mutex_unlock(&fs_info->fs_devices->device_list_mutex); scrub_workers_put(fs_info); @@ -2376,7 +2380,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, scrub_workers_put(fs_info); return -EINPROGRESS; } - sctx = scrub_setup_ctx(dev); + sctx = scrub_setup_ctx(dev, is_dev_replace); if (IS_ERR(sctx)) { mutex_unlock(&fs_info->scrub_lock); mutex_unlock(&fs_info->fs_devices->device_list_mutex); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index ef24158..837ad2d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1354,7 +1354,8 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes) min_stripe_size = BTRFS_STRIPE_LEN; list_for_each_entry(device, &fs_devices->devices, dev_list) { - if (!device->in_fs_metadata || !device->bdev) + if (!device->in_fs_metadata || !device->bdev || + device->is_tgtdev_for_dev_replace) continue; avail_space = device->total_bytes - device->bytes_used; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 33ca36b..31f7af8 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -518,8 +518,9 @@ again: /* This is the initialized path, it is safe to release the devices. */ list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) { if (device->in_fs_metadata) { - if (!latest_transid || - device->generation > latest_transid) { + if (!device->is_tgtdev_for_dev_replace && + (!latest_transid || + device->generation > latest_transid)) { latest_devid = device->devid; latest_transid = device->generation; latest_bdev = device->bdev; @@ -814,7 +815,7 @@ int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, *length = 0; - if (start >= device->total_bytes) + if (start >= device->total_bytes || device->is_tgtdev_for_dev_replace) return 0; path = btrfs_alloc_path(); @@ -931,7 +932,7 @@ int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, max_hole_size = 0; hole_size = 0; - if (search_start >= search_end) { + if (search_start >= search_end || device->is_tgtdev_for_dev_replace) { ret = -ENOSPC; goto error; } @@ -1114,6 +1115,7 @@ int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, struct btrfs_key key; WARN_ON(!device->in_fs_metadata); + WARN_ON(device->is_tgtdev_for_dev_replace); path = btrfs_alloc_path(); if (!path) return -ENOMEM; @@ -1375,7 +1377,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) * is held. */ list_for_each_entry(tmp, devices, dev_list) { - if (tmp->in_fs_metadata && !tmp->bdev) { + if (tmp->in_fs_metadata && + !tmp->is_tgtdev_for_dev_replace && + !tmp->bdev) { device = tmp; break; } @@ -1406,6 +1410,12 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) } } + if (device->is_tgtdev_for_dev_replace) { + pr_err("btrfs: unable to remove the dev_replace target dev\n"); + ret = -EINVAL; + goto error_brelse; + } + if (device->writeable && root->fs_info->fs_devices->rw_devices == 1) { printk(KERN_ERR "btrfs: unable to remove the only writeable " "device\n"); @@ -1425,6 +1435,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) if (ret) goto error_undo; + /* + * TODO: the superblock still includes this device in its num_devices + * counter although write_all_supers() is not locked out. This + * could give a filesystem state which requires a degraded mount. + */ ret = btrfs_rm_dev_item(root->fs_info->chunk_root, device); if (ret) goto error_undo; @@ -1808,6 +1823,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) device->dev_root = root->fs_info->dev_root; device->bdev = bdev; device->in_fs_metadata = 1; + device->is_tgtdev_for_dev_replace = 0; device->mode = FMODE_EXCL; set_blocksize(device->bdev, 4096); @@ -1971,7 +1987,8 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans, if (!device->writeable) return -EACCES; - if (new_size <= device->total_bytes) + if (new_size <= device->total_bytes || + device->is_tgtdev_for_dev_replace) return -EINVAL; btrfs_set_super_total_bytes(super_copy, old_total + diff); @@ -2600,7 +2617,8 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info) size_to_free = div_factor(old_size, 1); size_to_free = min(size_to_free, (u64)1 * 1024 * 1024); if (!device->writeable || - device->total_bytes - device->bytes_used > size_to_free) + device->total_bytes - device->bytes_used > size_to_free || + device->is_tgtdev_for_dev_replace) continue; ret = btrfs_shrink_device(device, old_size - size_to_free); @@ -3132,6 +3150,9 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) u64 old_size = device->total_bytes; u64 diff = device->total_bytes - new_size; + if (device->is_tgtdev_for_dev_replace) + return -EINVAL; + path = btrfs_alloc_path(); if (!path) return -ENOMEM; @@ -3401,7 +3422,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, continue; } - if (!device->in_fs_metadata) + if (!device->in_fs_metadata || + device->is_tgtdev_for_dev_replace) continue; if (device->total_bytes > device->bytes_used) @@ -4612,6 +4634,7 @@ static void fill_device_from_item(struct extent_buffer *leaf, device->io_align = btrfs_device_io_align(leaf, dev_item); device->io_width = btrfs_device_io_width(leaf, dev_item); device->sector_size = btrfs_device_sector_size(leaf, dev_item); + device->is_tgtdev_for_dev_replace = 0; ptr = (unsigned long)btrfs_device_uuid(dev_item); read_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE); @@ -4722,7 +4745,7 @@ static int read_one_dev(struct btrfs_root *root, fill_device_from_item(leaf, dev_item, device); device->dev_root = root->fs_info->dev_root; device->in_fs_metadata = 1; - if (device->writeable) { + if (device->writeable && !device->is_tgtdev_for_dev_replace) { device->fs_devices->total_rw_bytes += device->total_bytes; spin_lock(&root->fs_info->free_chunk_lock); root->fs_info->free_chunk_space += device->total_bytes - diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 802e2ba..8fd5a4d 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -50,6 +50,7 @@ struct btrfs_device { int in_fs_metadata; int missing; int can_discard; + int is_tgtdev_for_dev_replace; spinlock_t io_lock; -- cgit v0.10.2 From 618919236ba54361e93106f4951d233a7ade63cd Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 18:51:52 +0100 Subject: Btrfs: handle errors from btrfs_map_bio() everywhere With the addition of the device replace procedure, it is possible for btrfs_map_bio(READ) to report an error. This happens when the specific mirror is requested which is located on the target disk, and the copy operation has not yet copied this block. Hence the block cannot be read and this error state is indicated by returning EIO. Some background information follows now. A new mirror is added while the device replace procedure is running. btrfs_get_num_copies() returns one more, and btrfs_map_bio(GET_READ_MIRROR) adds one more mirror if a disk location is involved that was already handled by the device replace copy operation. The assigned mirror num is the highest mirror number, e.g. the value 3 in case of RAID1. If btrfs_map_bio() is invoked with mirror_num == 0 (i.e., select any mirror), the copy on the target drive is never selected because that disk shall be able to perform the write requests as quickly as possible. The parallel execution of read requests would only slow down the disk copy procedure. Second case is that btrfs_map_bio() is called with mirror_num > 0. This is done from the repair code only. In this case, the highest mirror num is assigned to the target disk, since it is used last. And when this mirror is not available because the copy procedure has not yet handled this area, an error is returned. Everywhere in the code the handling of such errors is added now. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index 8f9abed..badc6f1 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -1585,6 +1585,18 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len, ret = btrfs_map_block(state->root->fs_info, READ, bytenr, &length, &multi, mirror_num); + if (ret) { + block_ctx_out->start = 0; + block_ctx_out->dev_bytenr = 0; + block_ctx_out->len = 0; + block_ctx_out->dev = NULL; + block_ctx_out->datav = NULL; + block_ctx_out->pagev = NULL; + block_ctx_out->mem_to_free = NULL; + + return ret; + } + device = multi->stripes[0].dev; block_ctx_out->dev = btrfsic_dev_state_lookup(device->bdev); block_ctx_out->dev_bytenr = multi->stripes[0].physical; @@ -1594,8 +1606,7 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len, block_ctx_out->pagev = NULL; block_ctx_out->mem_to_free = NULL; - if (0 == ret) - kfree(multi); + kfree(multi); if (NULL == block_ctx_out->dev) { ret = -ENXIO; printk(KERN_INFO "btrfsic: error, cannot lookup dev (#1)!\n"); diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index c6467aa..94ab2f8 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -687,7 +687,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + bio_endio(comp_bio, ret); bio_put(comp_bio); @@ -712,7 +713,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, } ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); - BUG_ON(ret); /* -ENOMEM */ + if (ret) + bio_endio(comp_bio, ret); bio_put(comp_bio); return 0; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 9d1b710..0e41047 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -852,11 +852,16 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio, int mirror_num, unsigned long bio_flags, u64 bio_offset) { + int ret; + /* * when we're called for a write, we're already in the async * submission context. Just jump into btrfs_map_bio */ - return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1); + ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1); + if (ret) + bio_endio(bio, ret); + return ret; } static int check_async_write(struct inode *inode, unsigned long bio_flags) @@ -878,7 +883,6 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, int ret; if (!(rw & REQ_WRITE)) { - /* * called for a read, do the setup so that checksum validation * can happen in the async kernel threads @@ -886,26 +890,32 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info, bio, 1); if (ret) - return ret; - return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, - mirror_num, 0); + goto out_w_error; + ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, + mirror_num, 0); } else if (!async) { ret = btree_csum_one_bio(bio); if (ret) - return ret; - return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, - mirror_num, 0); + goto out_w_error; + ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, + mirror_num, 0); + } else { + /* + * kthread helpers are used to submit writes so that + * checksumming can happen in parallel across all CPUs + */ + ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, + inode, rw, bio, mirror_num, 0, + bio_offset, + __btree_submit_bio_start, + __btree_submit_bio_done); } - /* - * kthread helpers are used to submit writes so that checksumming - * can happen in parallel across all CPUs - */ - return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, - inode, rw, bio, mirror_num, 0, - bio_offset, - __btree_submit_bio_start, - __btree_submit_bio_done); + if (ret) { +out_w_error: + bio_endio(bio, ret); + } + return ret; } #ifdef CONFIG_MIGRATION diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 62ec6e4..1b319df 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2462,10 +2462,6 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, return bio; } -/* - * Since writes are async, they will only return -ENOMEM. - * Reads can return the full range of I/O error conditions. - */ static int __must_check submit_one_bio(int rw, struct bio *bio, int mirror_num, unsigned long bio_flags) { diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5d1675a..d7bf2e7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1602,7 +1602,12 @@ static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio, u64 bio_offset) { struct btrfs_root *root = BTRFS_I(inode)->root; - return btrfs_map_bio(root, rw, bio, mirror_num, 1); + int ret; + + ret = btrfs_map_bio(root, rw, bio, mirror_num, 1); + if (ret) + bio_endio(bio, ret); + return ret; } /* @@ -1626,15 +1631,17 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, if (!(rw & REQ_WRITE)) { ret = btrfs_bio_wq_end_io(root->fs_info, bio, metadata); if (ret) - return ret; + goto out; if (bio_flags & EXTENT_BIO_COMPRESSED) { - return btrfs_submit_compressed_read(inode, bio, - mirror_num, bio_flags); + ret = btrfs_submit_compressed_read(inode, bio, + mirror_num, + bio_flags); + goto out; } else if (!skip_sum) { ret = btrfs_lookup_bio_sums(root, inode, bio, NULL); if (ret) - return ret; + goto out; } goto mapit; } else if (!skip_sum) { @@ -1642,15 +1649,21 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID) goto mapit; /* we're doing a write, do the async checksumming */ - return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, + ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, inode, rw, bio, mirror_num, bio_flags, bio_offset, __btrfs_submit_bio_start, __btrfs_submit_bio_done); + goto out; } mapit: - return btrfs_map_bio(root, rw, bio, mirror_num, 0); + ret = btrfs_map_bio(root, rw, bio, mirror_num, 0); + +out: + if (ret < 0) + bio_endio(bio, ret); + return ret; } /* diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 31f7af8..4158628 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4435,7 +4435,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, ret = btrfs_map_block(root->fs_info, rw, logical, &map_length, &bbio, mirror_num); - if (ret) /* -ENOMEM */ + if (ret) return ret; total_devs = bbio->num_stripes; -- cgit v0.10.2 From ff023aac31198e88507d626825379b28ea481d4d Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Tue, 6 Nov 2012 11:43:11 +0100 Subject: Btrfs: add code to scrub to copy read data to another disk The device replace procedure makes use of the scrub code. The scrub code is the most efficient code to read the allocated data of a disk, i.e. it reads sequentially in order to avoid disk head movements, it skips unallocated blocks, it uses read ahead mechanisms, and it contains all the code to detect and repair defects. This commit adds code to scrub to allow the scrub code to copy read data to another disk. One goal is to be able to perform as fast as possible. Therefore the write requests are collected until huge bios are built, and the write process is decoupled from the read process with some kind of flow control, of course, in order to limit the allocated memory. The best performance on spinning disks could by reached when the head movements are avoided as much as possible. Therefore a single worker is used to interface the read process with the write process. The regular scrub operation works as fast as before, it is not negatively influenced and actually it is more or less unchanged. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 746cb6a..ded7caa 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1483,6 +1483,8 @@ struct btrfs_fs_info { struct rw_semaphore scrub_super_lock; int scrub_workers_refcnt; struct btrfs_workers scrub_workers; + struct btrfs_workers scrub_wr_completion_workers; + struct btrfs_workers scrub_nocow_workers; #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY u32 check_integrity_print_mask; diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h new file mode 100644 index 0000000..1fb5c89 --- /dev/null +++ b/fs/btrfs/dev-replace.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) STRATO AG 2012. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#if !defined(__BTRFS_DEV_REPLACE__) +#define __BTRFS_DEV_REPLACE__ + +static inline void btrfs_dev_replace_stats_inc(atomic64_t *stat_value) +{ + atomic64_inc(stat_value); +} +#endif diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index 0ddc565..9f363e1 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -418,12 +418,17 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, */ continue; } + if (!dev->bdev) { + /* cannot read ahead on missing device */ + continue; + } prev_dev = dev; ret = radix_tree_insert(&dev->reada_extents, index, re); if (ret) { while (--i >= 0) { dev = bbio->stripes[i].dev; BUG_ON(dev == NULL); + /* ignore whether the entry was inserted */ radix_tree_delete(&dev->reada_extents, index); } BUG_ON(fs_info == NULL); @@ -914,7 +919,10 @@ struct reada_control *btrfs_reada_add(struct btrfs_root *root, generation = btrfs_header_generation(node); free_extent_buffer(node); - reada_add_block(rc, start, &max_key, level, generation); + if (reada_add_block(rc, start, &max_key, level, generation)) { + kfree(rc); + return ERR_PTR(-ENOMEM); + } reada_start_machine(root->fs_info); diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 460e30b..61157a2 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -25,6 +25,7 @@ #include "transaction.h" #include "backref.h" #include "extent_io.h" +#include "dev-replace.h" #include "check-integrity.h" #include "rcu-string.h" @@ -44,8 +45,15 @@ struct scrub_block; struct scrub_ctx; -#define SCRUB_PAGES_PER_BIO 16 /* 64k per bio */ -#define SCRUB_BIOS_PER_CTX 16 /* 1 MB per device in flight */ +/* + * the following three values only influence the performance. + * The last one configures the number of parallel and outstanding I/O + * operations. The first two values configure an upper limit for the number + * of (dynamically allocated) pages that are added to a bio. + */ +#define SCRUB_PAGES_PER_RD_BIO 32 /* 128k per bio */ +#define SCRUB_PAGES_PER_WR_BIO 32 /* 128k per bio */ +#define SCRUB_BIOS_PER_SCTX 64 /* 8MB per device in flight */ /* * the following value times PAGE_SIZE needs to be large enough to match the @@ -62,6 +70,7 @@ struct scrub_page { u64 generation; u64 logical; u64 physical; + u64 physical_for_dev_replace; atomic_t ref_count; struct { unsigned int mirror_num:8; @@ -79,7 +88,11 @@ struct scrub_bio { int err; u64 logical; u64 physical; - struct scrub_page *pagev[SCRUB_PAGES_PER_BIO]; +#if SCRUB_PAGES_PER_WR_BIO >= SCRUB_PAGES_PER_RD_BIO + struct scrub_page *pagev[SCRUB_PAGES_PER_WR_BIO]; +#else + struct scrub_page *pagev[SCRUB_PAGES_PER_RD_BIO]; +#endif int page_count; int next_free; struct btrfs_work work; @@ -99,8 +112,16 @@ struct scrub_block { }; }; +struct scrub_wr_ctx { + struct scrub_bio *wr_curr_bio; + struct btrfs_device *tgtdev; + int pages_per_wr_bio; /* <= SCRUB_PAGES_PER_WR_BIO */ + atomic_t flush_all_writes; + struct mutex wr_lock; +}; + struct scrub_ctx { - struct scrub_bio *bios[SCRUB_BIOS_PER_CTX]; + struct scrub_bio *bios[SCRUB_BIOS_PER_SCTX]; struct btrfs_root *dev_root; int first_free; int curr; @@ -112,12 +133,13 @@ struct scrub_ctx { struct list_head csum_list; atomic_t cancel_req; int readonly; - int pages_per_bio; /* <= SCRUB_PAGES_PER_BIO */ + int pages_per_rd_bio; u32 sectorsize; u32 nodesize; u32 leafsize; int is_dev_replace; + struct scrub_wr_ctx wr_ctx; /* * statistics @@ -135,6 +157,15 @@ struct scrub_fixup_nodatasum { int mirror_num; }; +struct scrub_copy_nocow_ctx { + struct scrub_ctx *sctx; + u64 logical; + u64 len; + int mirror_num; + u64 physical_for_dev_replace; + struct btrfs_work work; +}; + struct scrub_warning { struct btrfs_path *path; u64 extent_item_size; @@ -156,8 +187,9 @@ static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx); static int scrub_handle_errored_block(struct scrub_block *sblock_to_check); static int scrub_setup_recheck_block(struct scrub_ctx *sctx, struct btrfs_fs_info *fs_info, + struct scrub_block *original_sblock, u64 length, u64 logical, - struct scrub_block *sblock); + struct scrub_block *sblocks_for_recheck); static void scrub_recheck_block(struct btrfs_fs_info *fs_info, struct scrub_block *sblock, int is_metadata, int have_csum, u8 *csum, u64 generation, @@ -174,6 +206,9 @@ static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad, static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, struct scrub_block *sblock_good, int page_num, int force_write); +static void scrub_write_block_to_dev_replace(struct scrub_block *sblock); +static int scrub_write_page_to_dev_replace(struct scrub_block *sblock, + int page_num); static int scrub_checksum_data(struct scrub_block *sblock); static int scrub_checksum_tree_block(struct scrub_block *sblock); static int scrub_checksum_super(struct scrub_block *sblock); @@ -181,14 +216,38 @@ static void scrub_block_get(struct scrub_block *sblock); static void scrub_block_put(struct scrub_block *sblock); static void scrub_page_get(struct scrub_page *spage); static void scrub_page_put(struct scrub_page *spage); -static int scrub_add_page_to_bio(struct scrub_ctx *sctx, - struct scrub_page *spage); +static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx, + struct scrub_page *spage); static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, u64 physical, struct btrfs_device *dev, u64 flags, - u64 gen, int mirror_num, u8 *csum, int force); + u64 gen, int mirror_num, u8 *csum, int force, + u64 physical_for_dev_replace); static void scrub_bio_end_io(struct bio *bio, int err); static void scrub_bio_end_io_worker(struct btrfs_work *work); static void scrub_block_complete(struct scrub_block *sblock); +static void scrub_remap_extent(struct btrfs_fs_info *fs_info, + u64 extent_logical, u64 extent_len, + u64 *extent_physical, + struct btrfs_device **extent_dev, + int *extent_mirror_num); +static int scrub_setup_wr_ctx(struct scrub_ctx *sctx, + struct scrub_wr_ctx *wr_ctx, + struct btrfs_fs_info *fs_info, + struct btrfs_device *dev, + int is_dev_replace); +static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx); +static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx, + struct scrub_page *spage); +static void scrub_wr_submit(struct scrub_ctx *sctx); +static void scrub_wr_bio_end_io(struct bio *bio, int err); +static void scrub_wr_bio_end_io_worker(struct btrfs_work *work); +static int write_page_nocow(struct scrub_ctx *sctx, + u64 physical_for_dev_replace, struct page *page); +static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, + void *ctx); +static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len, + int mirror_num, u64 physical_for_dev_replace); +static void copy_nocow_pages_worker(struct btrfs_work *work); static void scrub_pending_bio_inc(struct scrub_ctx *sctx) @@ -262,19 +321,20 @@ static noinline_for_stack void scrub_free_ctx(struct scrub_ctx *sctx) if (!sctx) return; + scrub_free_wr_ctx(&sctx->wr_ctx); + /* this can happen when scrub is cancelled */ if (sctx->curr != -1) { struct scrub_bio *sbio = sctx->bios[sctx->curr]; for (i = 0; i < sbio->page_count; i++) { - BUG_ON(!sbio->pagev[i]); - BUG_ON(!sbio->pagev[i]->page); + WARN_ON(!sbio->pagev[i]->page); scrub_block_put(sbio->pagev[i]->sblock); } bio_put(sbio->bio); } - for (i = 0; i < SCRUB_BIOS_PER_CTX; ++i) { + for (i = 0; i < SCRUB_BIOS_PER_SCTX; ++i) { struct scrub_bio *sbio = sctx->bios[i]; if (!sbio) @@ -292,18 +352,29 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace) struct scrub_ctx *sctx; int i; struct btrfs_fs_info *fs_info = dev->dev_root->fs_info; - int pages_per_bio; + int pages_per_rd_bio; + int ret; - pages_per_bio = min_t(int, SCRUB_PAGES_PER_BIO, - bio_get_nr_vecs(dev->bdev)); + /* + * the setting of pages_per_rd_bio is correct for scrub but might + * be wrong for the dev_replace code where we might read from + * different devices in the initial huge bios. However, that + * code is able to correctly handle the case when adding a page + * to a bio fails. + */ + if (dev->bdev) + pages_per_rd_bio = min_t(int, SCRUB_PAGES_PER_RD_BIO, + bio_get_nr_vecs(dev->bdev)); + else + pages_per_rd_bio = SCRUB_PAGES_PER_RD_BIO; sctx = kzalloc(sizeof(*sctx), GFP_NOFS); if (!sctx) goto nomem; sctx->is_dev_replace = is_dev_replace; - sctx->pages_per_bio = pages_per_bio; + sctx->pages_per_rd_bio = pages_per_rd_bio; sctx->curr = -1; sctx->dev_root = dev->dev_root; - for (i = 0; i < SCRUB_BIOS_PER_CTX; ++i) { + for (i = 0; i < SCRUB_BIOS_PER_SCTX; ++i) { struct scrub_bio *sbio; sbio = kzalloc(sizeof(*sbio), GFP_NOFS); @@ -316,7 +387,7 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace) sbio->page_count = 0; sbio->work.func = scrub_bio_end_io_worker; - if (i != SCRUB_BIOS_PER_CTX - 1) + if (i != SCRUB_BIOS_PER_SCTX - 1) sctx->bios[i]->next_free = i + 1; else sctx->bios[i]->next_free = -1; @@ -334,6 +405,13 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace) spin_lock_init(&sctx->list_lock); spin_lock_init(&sctx->stat_lock); init_waitqueue_head(&sctx->list_wait); + + ret = scrub_setup_wr_ctx(sctx, &sctx->wr_ctx, fs_info, + fs_info->dev_replace.tgtdev, is_dev_replace); + if (ret) { + scrub_free_ctx(sctx); + return ERR_PTR(ret); + } return sctx; nomem: @@ -341,7 +419,8 @@ nomem: return ERR_PTR(-ENOMEM); } -static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, void *ctx) +static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, + void *warn_ctx) { u64 isize; u32 nlink; @@ -349,7 +428,7 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, void *ctx) int i; struct extent_buffer *eb; struct btrfs_inode_item *inode_item; - struct scrub_warning *swarn = ctx; + struct scrub_warning *swarn = warn_ctx; struct btrfs_fs_info *fs_info = swarn->dev->dev_root->fs_info; struct inode_fs_paths *ipath = NULL; struct btrfs_root *local_root; @@ -492,11 +571,11 @@ out: kfree(swarn.msg_buf); } -static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *ctx) +static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx) { struct page *page = NULL; unsigned long index; - struct scrub_fixup_nodatasum *fixup = ctx; + struct scrub_fixup_nodatasum *fixup = fixup_ctx; int ret; int corrected = 0; struct btrfs_key key; @@ -660,7 +739,9 @@ out: spin_lock(&sctx->stat_lock); ++sctx->stat.uncorrectable_errors; spin_unlock(&sctx->stat_lock); - + btrfs_dev_replace_stats_inc( + &sctx->dev_root->fs_info->dev_replace. + num_uncorrectable_read_errors); printk_ratelimited_in_rcu(KERN_ERR "btrfs: unable to fixup (nodatasum) error at logical %llu on dev %s\n", (unsigned long long)fixup->logical, @@ -715,6 +796,11 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) csum = sblock_to_check->pagev[0]->csum; dev = sblock_to_check->pagev[0]->dev; + if (sctx->is_dev_replace && !is_metadata && !have_csum) { + sblocks_for_recheck = NULL; + goto nodatasum_case; + } + /* * read all mirrors one after the other. This includes to * re-read the extent or metadata block that failed (that was @@ -758,7 +844,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) } /* setup the context, map the logical blocks and alloc the pages */ - ret = scrub_setup_recheck_block(sctx, fs_info, length, + ret = scrub_setup_recheck_block(sctx, fs_info, sblock_to_check, length, logical, sblocks_for_recheck); if (ret) { spin_lock(&sctx->stat_lock); @@ -789,6 +875,8 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) sctx->stat.unverified_errors++; spin_unlock(&sctx->stat_lock); + if (sctx->is_dev_replace) + scrub_write_block_to_dev_replace(sblock_bad); goto out; } @@ -822,12 +910,15 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) BTRFS_DEV_STAT_CORRUPTION_ERRS); } - if (sctx->readonly) + if (sctx->readonly && !sctx->is_dev_replace) goto did_not_correct_error; if (!is_metadata && !have_csum) { struct scrub_fixup_nodatasum *fixup_nodatasum; +nodatasum_case: + WARN_ON(sctx->is_dev_replace); + /* * !is_metadata and !have_csum, this means that the data * might not be COW'ed, that it might be modified @@ -883,18 +974,79 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) if (!sblock_other->header_error && !sblock_other->checksum_error && sblock_other->no_io_error_seen) { - int force_write = is_metadata || have_csum; - - ret = scrub_repair_block_from_good_copy(sblock_bad, - sblock_other, - force_write); + if (sctx->is_dev_replace) { + scrub_write_block_to_dev_replace(sblock_other); + } else { + int force_write = is_metadata || have_csum; + + ret = scrub_repair_block_from_good_copy( + sblock_bad, sblock_other, + force_write); + } if (0 == ret) goto corrected_error; } } /* - * in case of I/O errors in the area that is supposed to be + * for dev_replace, pick good pages and write to the target device. + */ + if (sctx->is_dev_replace) { + success = 1; + for (page_num = 0; page_num < sblock_bad->page_count; + page_num++) { + int sub_success; + + sub_success = 0; + for (mirror_index = 0; + mirror_index < BTRFS_MAX_MIRRORS && + sblocks_for_recheck[mirror_index].page_count > 0; + mirror_index++) { + struct scrub_block *sblock_other = + sblocks_for_recheck + mirror_index; + struct scrub_page *page_other = + sblock_other->pagev[page_num]; + + if (!page_other->io_error) { + ret = scrub_write_page_to_dev_replace( + sblock_other, page_num); + if (ret == 0) { + /* succeeded for this page */ + sub_success = 1; + break; + } else { + btrfs_dev_replace_stats_inc( + &sctx->dev_root-> + fs_info->dev_replace. + num_write_errors); + } + } + } + + if (!sub_success) { + /* + * did not find a mirror to fetch the page + * from. scrub_write_page_to_dev_replace() + * handles this case (page->io_error), by + * filling the block with zeros before + * submitting the write request + */ + success = 0; + ret = scrub_write_page_to_dev_replace( + sblock_bad, page_num); + if (ret) + btrfs_dev_replace_stats_inc( + &sctx->dev_root->fs_info-> + dev_replace.num_write_errors); + } + } + + goto out; + } + + /* + * for regular scrub, repair those pages that are errored. + * In case of I/O errors in the area that is supposed to be * repaired, continue by picking good copies of those pages. * Select the good pages from mirrors to rewrite bad pages from * the area to fix. Afterwards verify the checksum of the block @@ -1017,6 +1169,7 @@ out: static int scrub_setup_recheck_block(struct scrub_ctx *sctx, struct btrfs_fs_info *fs_info, + struct scrub_block *original_sblock, u64 length, u64 logical, struct scrub_block *sblocks_for_recheck) { @@ -1047,7 +1200,7 @@ static int scrub_setup_recheck_block(struct scrub_ctx *sctx, return -EIO; } - BUG_ON(page_index >= SCRUB_PAGES_PER_BIO); + BUG_ON(page_index >= SCRUB_PAGES_PER_RD_BIO); for (mirror_index = 0; mirror_index < (int)bbio->num_stripes; mirror_index++) { struct scrub_block *sblock; @@ -1071,6 +1224,10 @@ leave_nomem: sblock->pagev[page_index] = page; page->logical = logical; page->physical = bbio->stripes[mirror_index].physical; + BUG_ON(page_index >= original_sblock->page_count); + page->physical_for_dev_replace = + original_sblock->pagev[page_index]-> + physical_for_dev_replace; /* for missing devices, dev->bdev is NULL */ page->dev = bbio->stripes[mirror_index].dev; page->mirror_num = mirror_index + 1; @@ -1249,6 +1406,12 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, int ret; DECLARE_COMPLETION_ONSTACK(complete); + if (!page_bad->dev->bdev) { + printk_ratelimited(KERN_WARNING + "btrfs: scrub_repair_page_from_good_copy(bdev == NULL) is unexpected!\n"); + return -EIO; + } + bio = bio_alloc(GFP_NOFS, 1); if (!bio) return -EIO; @@ -1269,6 +1432,9 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, if (!bio_flagged(bio, BIO_UPTODATE)) { btrfs_dev_stat_inc_and_print(page_bad->dev, BTRFS_DEV_STAT_WRITE_ERRS); + btrfs_dev_replace_stats_inc( + &sblock_bad->sctx->dev_root->fs_info-> + dev_replace.num_write_errors); bio_put(bio); return -EIO; } @@ -1278,7 +1444,168 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, return 0; } -static void scrub_checksum(struct scrub_block *sblock) +static void scrub_write_block_to_dev_replace(struct scrub_block *sblock) +{ + int page_num; + + for (page_num = 0; page_num < sblock->page_count; page_num++) { + int ret; + + ret = scrub_write_page_to_dev_replace(sblock, page_num); + if (ret) + btrfs_dev_replace_stats_inc( + &sblock->sctx->dev_root->fs_info->dev_replace. + num_write_errors); + } +} + +static int scrub_write_page_to_dev_replace(struct scrub_block *sblock, + int page_num) +{ + struct scrub_page *spage = sblock->pagev[page_num]; + + BUG_ON(spage->page == NULL); + if (spage->io_error) { + void *mapped_buffer = kmap_atomic(spage->page); + + memset(mapped_buffer, 0, PAGE_CACHE_SIZE); + flush_dcache_page(spage->page); + kunmap_atomic(mapped_buffer); + } + return scrub_add_page_to_wr_bio(sblock->sctx, spage); +} + +static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx, + struct scrub_page *spage) +{ + struct scrub_wr_ctx *wr_ctx = &sctx->wr_ctx; + struct scrub_bio *sbio; + int ret; + + mutex_lock(&wr_ctx->wr_lock); +again: + if (!wr_ctx->wr_curr_bio) { + wr_ctx->wr_curr_bio = kzalloc(sizeof(*wr_ctx->wr_curr_bio), + GFP_NOFS); + if (!wr_ctx->wr_curr_bio) { + mutex_unlock(&wr_ctx->wr_lock); + return -ENOMEM; + } + wr_ctx->wr_curr_bio->sctx = sctx; + wr_ctx->wr_curr_bio->page_count = 0; + } + sbio = wr_ctx->wr_curr_bio; + if (sbio->page_count == 0) { + struct bio *bio; + + sbio->physical = spage->physical_for_dev_replace; + sbio->logical = spage->logical; + sbio->dev = wr_ctx->tgtdev; + bio = sbio->bio; + if (!bio) { + bio = bio_alloc(GFP_NOFS, wr_ctx->pages_per_wr_bio); + if (!bio) { + mutex_unlock(&wr_ctx->wr_lock); + return -ENOMEM; + } + sbio->bio = bio; + } + + bio->bi_private = sbio; + bio->bi_end_io = scrub_wr_bio_end_io; + bio->bi_bdev = sbio->dev->bdev; + bio->bi_sector = sbio->physical >> 9; + sbio->err = 0; + } else if (sbio->physical + sbio->page_count * PAGE_SIZE != + spage->physical_for_dev_replace || + sbio->logical + sbio->page_count * PAGE_SIZE != + spage->logical) { + scrub_wr_submit(sctx); + goto again; + } + + ret = bio_add_page(sbio->bio, spage->page, PAGE_SIZE, 0); + if (ret != PAGE_SIZE) { + if (sbio->page_count < 1) { + bio_put(sbio->bio); + sbio->bio = NULL; + mutex_unlock(&wr_ctx->wr_lock); + return -EIO; + } + scrub_wr_submit(sctx); + goto again; + } + + sbio->pagev[sbio->page_count] = spage; + scrub_page_get(spage); + sbio->page_count++; + if (sbio->page_count == wr_ctx->pages_per_wr_bio) + scrub_wr_submit(sctx); + mutex_unlock(&wr_ctx->wr_lock); + + return 0; +} + +static void scrub_wr_submit(struct scrub_ctx *sctx) +{ + struct scrub_wr_ctx *wr_ctx = &sctx->wr_ctx; + struct scrub_bio *sbio; + + if (!wr_ctx->wr_curr_bio) + return; + + sbio = wr_ctx->wr_curr_bio; + wr_ctx->wr_curr_bio = NULL; + WARN_ON(!sbio->bio->bi_bdev); + scrub_pending_bio_inc(sctx); + /* process all writes in a single worker thread. Then the block layer + * orders the requests before sending them to the driver which + * doubled the write performance on spinning disks when measured + * with Linux 3.5 */ + btrfsic_submit_bio(WRITE, sbio->bio); +} + +static void scrub_wr_bio_end_io(struct bio *bio, int err) +{ + struct scrub_bio *sbio = bio->bi_private; + struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info; + + sbio->err = err; + sbio->bio = bio; + + sbio->work.func = scrub_wr_bio_end_io_worker; + btrfs_queue_worker(&fs_info->scrub_wr_completion_workers, &sbio->work); +} + +static void scrub_wr_bio_end_io_worker(struct btrfs_work *work) +{ + struct scrub_bio *sbio = container_of(work, struct scrub_bio, work); + struct scrub_ctx *sctx = sbio->sctx; + int i; + + WARN_ON(sbio->page_count > SCRUB_PAGES_PER_WR_BIO); + if (sbio->err) { + struct btrfs_dev_replace *dev_replace = + &sbio->sctx->dev_root->fs_info->dev_replace; + + for (i = 0; i < sbio->page_count; i++) { + struct scrub_page *spage = sbio->pagev[i]; + + spage->io_error = 1; + btrfs_dev_replace_stats_inc(&dev_replace-> + num_write_errors); + } + } + + for (i = 0; i < sbio->page_count; i++) + scrub_page_put(sbio->pagev[i]); + + bio_put(sbio->bio); + kfree(sbio); + scrub_pending_bio_dec(sctx); +} + +static int scrub_checksum(struct scrub_block *sblock) { u64 flags; int ret; @@ -1296,6 +1623,8 @@ static void scrub_checksum(struct scrub_block *sblock) WARN_ON(1); if (ret) scrub_handle_errored_block(sblock); + + return ret; } static int scrub_checksum_data(struct scrub_block *sblock) @@ -1386,7 +1715,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) BTRFS_UUID_SIZE)) ++fail; - BUG_ON(sctx->nodesize != sctx->leafsize); + WARN_ON(sctx->nodesize != sctx->leafsize); len = sctx->nodesize - BTRFS_CSUM_SIZE; mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE; p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE; @@ -1534,11 +1863,24 @@ static void scrub_submit(struct scrub_ctx *sctx) sctx->curr = -1; scrub_pending_bio_inc(sctx); - btrfsic_submit_bio(READ, sbio->bio); + if (!sbio->bio->bi_bdev) { + /* + * this case should not happen. If btrfs_map_block() is + * wrong, it could happen for dev-replace operations on + * missing devices when no mirrors are available, but in + * this case it should already fail the mount. + * This case is handled correctly (but _very_ slowly). + */ + printk_ratelimited(KERN_WARNING + "btrfs: scrub_submit(bio bdev == NULL) is unexpected!\n"); + bio_endio(sbio->bio, -EIO); + } else { + btrfsic_submit_bio(READ, sbio->bio); + } } -static int scrub_add_page_to_bio(struct scrub_ctx *sctx, - struct scrub_page *spage) +static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx, + struct scrub_page *spage) { struct scrub_block *sblock = spage->sblock; struct scrub_bio *sbio; @@ -1570,7 +1912,7 @@ again: sbio->dev = spage->dev; bio = sbio->bio; if (!bio) { - bio = bio_alloc(GFP_NOFS, sctx->pages_per_bio); + bio = bio_alloc(GFP_NOFS, sctx->pages_per_rd_bio); if (!bio) return -ENOMEM; sbio->bio = bio; @@ -1602,10 +1944,10 @@ again: goto again; } - scrub_block_get(sblock); /* one for the added page */ + scrub_block_get(sblock); /* one for the page added to the bio */ atomic_inc(&sblock->outstanding_pages); sbio->page_count++; - if (sbio->page_count == sctx->pages_per_bio) + if (sbio->page_count == sctx->pages_per_rd_bio) scrub_submit(sctx); return 0; @@ -1613,7 +1955,8 @@ again: static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, u64 physical, struct btrfs_device *dev, u64 flags, - u64 gen, int mirror_num, u8 *csum, int force) + u64 gen, int mirror_num, u8 *csum, int force, + u64 physical_for_dev_replace) { struct scrub_block *sblock; int index; @@ -1654,6 +1997,7 @@ leave_nomem: spage->generation = gen; spage->logical = logical; spage->physical = physical; + spage->physical_for_dev_replace = physical_for_dev_replace; spage->mirror_num = mirror_num; if (csum) { spage->have_csum = 1; @@ -1668,6 +2012,7 @@ leave_nomem: len -= l; logical += l; physical += l; + physical_for_dev_replace += l; } WARN_ON(sblock->page_count == 0); @@ -1675,7 +2020,7 @@ leave_nomem: struct scrub_page *spage = sblock->pagev[index]; int ret; - ret = scrub_add_page_to_bio(sctx, spage); + ret = scrub_add_page_to_rd_bio(sctx, spage); if (ret) { scrub_block_put(sblock); return ret; @@ -1707,7 +2052,7 @@ static void scrub_bio_end_io_worker(struct btrfs_work *work) struct scrub_ctx *sctx = sbio->sctx; int i; - BUG_ON(sbio->page_count > SCRUB_PAGES_PER_BIO); + BUG_ON(sbio->page_count > SCRUB_PAGES_PER_RD_BIO); if (sbio->err) { for (i = 0; i < sbio->page_count; i++) { struct scrub_page *spage = sbio->pagev[i]; @@ -1733,15 +2078,30 @@ static void scrub_bio_end_io_worker(struct btrfs_work *work) sbio->next_free = sctx->first_free; sctx->first_free = sbio->index; spin_unlock(&sctx->list_lock); + + if (sctx->is_dev_replace && + atomic_read(&sctx->wr_ctx.flush_all_writes)) { + mutex_lock(&sctx->wr_ctx.wr_lock); + scrub_wr_submit(sctx); + mutex_unlock(&sctx->wr_ctx.wr_lock); + } + scrub_pending_bio_dec(sctx); } static void scrub_block_complete(struct scrub_block *sblock) { - if (!sblock->no_io_error_seen) + if (!sblock->no_io_error_seen) { scrub_handle_errored_block(sblock); - else - scrub_checksum(sblock); + } else { + /* + * if has checksum error, write via repair mechanism in + * dev replace case, otherwise write here in dev replace + * case. + */ + if (!scrub_checksum(sblock) && sblock->sctx->is_dev_replace) + scrub_write_block_to_dev_replace(sblock); + } } static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u64 len, @@ -1786,7 +2146,7 @@ static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u64 len, /* scrub extent tries to collect up to 64 kB for each bio */ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, u64 physical, struct btrfs_device *dev, u64 flags, - u64 gen, int mirror_num) + u64 gen, int mirror_num, u64 physical_for_dev_replace) { int ret; u8 csum[BTRFS_CSUM_SIZE]; @@ -1799,7 +2159,7 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, sctx->stat.data_bytes_scrubbed += len; spin_unlock(&sctx->stat_lock); } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { - BUG_ON(sctx->nodesize != sctx->leafsize); + WARN_ON(sctx->nodesize != sctx->leafsize); blocksize = sctx->nodesize; spin_lock(&sctx->stat_lock); sctx->stat.tree_extents_scrubbed++; @@ -1807,7 +2167,7 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, spin_unlock(&sctx->stat_lock); } else { blocksize = sctx->sectorsize; - BUG_ON(1); + WARN_ON(1); } while (len) { @@ -1819,14 +2179,23 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, have_csum = scrub_find_csum(sctx, logical, l, csum); if (have_csum == 0) ++sctx->stat.no_csum; + if (sctx->is_dev_replace && !have_csum) { + ret = copy_nocow_pages(sctx, logical, l, + mirror_num, + physical_for_dev_replace); + goto behind_scrub_pages; + } } ret = scrub_pages(sctx, logical, l, physical, dev, flags, gen, - mirror_num, have_csum ? csum : NULL, 0); + mirror_num, have_csum ? csum : NULL, 0, + physical_for_dev_replace); +behind_scrub_pages: if (ret) return ret; len -= l; logical += l; physical += l; + physical_for_dev_replace += l; } return 0; } @@ -1834,7 +2203,8 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, struct map_lookup *map, struct btrfs_device *scrub_dev, - int num, u64 base, u64 length) + int num, u64 base, u64 length, + int is_dev_replace) { struct btrfs_path *path; struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; @@ -1859,6 +2229,11 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, struct btrfs_key key_end; u64 increment = map->stripe_len; u64 offset; + u64 extent_logical; + u64 extent_physical; + u64 extent_len; + struct btrfs_device *extent_dev; + int extent_mirror_num; nstripes = length; offset = 0; @@ -1966,9 +2341,14 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, */ if (atomic_read(&fs_info->scrub_pause_req)) { /* push queued extents */ + atomic_set(&sctx->wr_ctx.flush_all_writes, 1); scrub_submit(sctx); + mutex_lock(&sctx->wr_ctx.wr_lock); + scrub_wr_submit(sctx); + mutex_unlock(&sctx->wr_ctx.wr_lock); wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0); + atomic_set(&sctx->wr_ctx.flush_all_writes, 0); atomic_inc(&fs_info->scrubs_paused); wake_up(&fs_info->scrub_pause_wait); mutex_lock(&fs_info->scrub_lock); @@ -2063,10 +2443,20 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, key.objectid; } - ret = scrub_extent(sctx, key.objectid, key.offset, - key.objectid - logical + physical, - scrub_dev, flags, generation, - mirror_num); + extent_logical = key.objectid; + extent_physical = key.objectid - logical + physical; + extent_len = key.offset; + extent_dev = scrub_dev; + extent_mirror_num = mirror_num; + if (is_dev_replace) + scrub_remap_extent(fs_info, extent_logical, + extent_len, &extent_physical, + &extent_dev, + &extent_mirror_num); + ret = scrub_extent(sctx, extent_logical, extent_len, + extent_physical, extent_dev, flags, + generation, extent_mirror_num, + key.objectid - logical + physical); if (ret) goto out; @@ -2080,10 +2470,13 @@ next: sctx->stat.last_physical = physical; spin_unlock(&sctx->stat_lock); } +out: /* push queued extents */ scrub_submit(sctx); + mutex_lock(&sctx->wr_ctx.wr_lock); + scrub_wr_submit(sctx); + mutex_unlock(&sctx->wr_ctx.wr_lock); -out: blk_finish_plug(&plug); btrfs_free_path(path); return ret < 0 ? ret : 0; @@ -2093,14 +2486,14 @@ static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, struct btrfs_device *scrub_dev, u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 length, - u64 dev_offset) + u64 dev_offset, int is_dev_replace) { struct btrfs_mapping_tree *map_tree = &sctx->dev_root->fs_info->mapping_tree; struct map_lookup *map; struct extent_map *em; int i; - int ret = -EINVAL; + int ret = 0; read_lock(&map_tree->map_tree.lock); em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1); @@ -2120,7 +2513,8 @@ static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, if (map->stripes[i].dev->bdev == scrub_dev->bdev && map->stripes[i].physical == dev_offset) { ret = scrub_stripe(sctx, map, scrub_dev, i, - chunk_offset, length); + chunk_offset, length, + is_dev_replace); if (ret) goto out; } @@ -2133,7 +2527,8 @@ out: static noinline_for_stack int scrub_enumerate_chunks(struct scrub_ctx *sctx, - struct btrfs_device *scrub_dev, u64 start, u64 end) + struct btrfs_device *scrub_dev, u64 start, u64 end, + int is_dev_replace) { struct btrfs_dev_extent *dev_extent = NULL; struct btrfs_path *path; @@ -2149,6 +2544,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, struct btrfs_key key; struct btrfs_key found_key; struct btrfs_block_group_cache *cache; + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; path = btrfs_alloc_path(); if (!path) @@ -2214,11 +2610,61 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, ret = -ENOENT; break; } + dev_replace->cursor_right = found_key.offset + length; + dev_replace->cursor_left = found_key.offset; + dev_replace->item_needs_writeback = 1; ret = scrub_chunk(sctx, scrub_dev, chunk_tree, chunk_objectid, - chunk_offset, length, found_key.offset); + chunk_offset, length, found_key.offset, + is_dev_replace); + + /* + * flush, submit all pending read and write bios, afterwards + * wait for them. + * Note that in the dev replace case, a read request causes + * write requests that are submitted in the read completion + * worker. Therefore in the current situation, it is required + * that all write requests are flushed, so that all read and + * write requests are really completed when bios_in_flight + * changes to 0. + */ + atomic_set(&sctx->wr_ctx.flush_all_writes, 1); + scrub_submit(sctx); + mutex_lock(&sctx->wr_ctx.wr_lock); + scrub_wr_submit(sctx); + mutex_unlock(&sctx->wr_ctx.wr_lock); + + wait_event(sctx->list_wait, + atomic_read(&sctx->bios_in_flight) == 0); + atomic_set(&sctx->wr_ctx.flush_all_writes, 0); + atomic_inc(&fs_info->scrubs_paused); + wake_up(&fs_info->scrub_pause_wait); + wait_event(sctx->list_wait, + atomic_read(&sctx->workers_pending) == 0); + + mutex_lock(&fs_info->scrub_lock); + while (atomic_read(&fs_info->scrub_pause_req)) { + mutex_unlock(&fs_info->scrub_lock); + wait_event(fs_info->scrub_pause_wait, + atomic_read(&fs_info->scrub_pause_req) == 0); + mutex_lock(&fs_info->scrub_lock); + } + atomic_dec(&fs_info->scrubs_paused); + mutex_unlock(&fs_info->scrub_lock); + wake_up(&fs_info->scrub_pause_wait); + + dev_replace->cursor_left = dev_replace->cursor_right; + dev_replace->item_needs_writeback = 1; btrfs_put_block_group(cache); if (ret) break; + if (atomic64_read(&dev_replace->num_write_errors) > 0) { + ret = -EIO; + break; + } + if (sctx->stat.malloc_errors > 0) { + ret = -ENOMEM; + break; + } key.offset = found_key.offset + length; btrfs_release_path(path); @@ -2254,7 +2700,7 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx, ret = scrub_pages(sctx, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr, scrub_dev, BTRFS_EXTENT_FLAG_SUPER, gen, i, - NULL, 1); + NULL, 1, bytenr); if (ret) return ret; } @@ -2266,18 +2712,38 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx, /* * get a reference count on fs_info->scrub_workers. start worker if necessary */ -static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info) +static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info, + int is_dev_replace) { int ret = 0; mutex_lock(&fs_info->scrub_lock); if (fs_info->scrub_workers_refcnt == 0) { - btrfs_init_workers(&fs_info->scrub_workers, "scrub", - fs_info->thread_pool_size, &fs_info->generic_worker); + if (is_dev_replace) + btrfs_init_workers(&fs_info->scrub_workers, "scrub", 1, + &fs_info->generic_worker); + else + btrfs_init_workers(&fs_info->scrub_workers, "scrub", + fs_info->thread_pool_size, + &fs_info->generic_worker); fs_info->scrub_workers.idle_thresh = 4; ret = btrfs_start_workers(&fs_info->scrub_workers); if (ret) goto out; + btrfs_init_workers(&fs_info->scrub_wr_completion_workers, + "scrubwrc", + fs_info->thread_pool_size, + &fs_info->generic_worker); + fs_info->scrub_wr_completion_workers.idle_thresh = 2; + ret = btrfs_start_workers( + &fs_info->scrub_wr_completion_workers); + if (ret) + goto out; + btrfs_init_workers(&fs_info->scrub_nocow_workers, "scrubnc", 1, + &fs_info->generic_worker); + ret = btrfs_start_workers(&fs_info->scrub_nocow_workers); + if (ret) + goto out; } ++fs_info->scrub_workers_refcnt; out: @@ -2289,8 +2755,11 @@ out: static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info) { mutex_lock(&fs_info->scrub_lock); - if (--fs_info->scrub_workers_refcnt == 0) + if (--fs_info->scrub_workers_refcnt == 0) { btrfs_stop_workers(&fs_info->scrub_workers); + btrfs_stop_workers(&fs_info->scrub_wr_completion_workers); + btrfs_stop_workers(&fs_info->scrub_nocow_workers); + } WARN_ON(fs_info->scrub_workers_refcnt < 0); mutex_unlock(&fs_info->scrub_lock); } @@ -2354,7 +2823,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, return -EINVAL; } - ret = scrub_workers_get(fs_info); + ret = scrub_workers_get(fs_info, is_dev_replace); if (ret) return ret; @@ -2394,12 +2863,15 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, mutex_unlock(&fs_info->scrub_lock); mutex_unlock(&fs_info->fs_devices->device_list_mutex); - down_read(&fs_info->scrub_super_lock); - ret = scrub_supers(sctx, dev); - up_read(&fs_info->scrub_super_lock); + if (!is_dev_replace) { + down_read(&fs_info->scrub_super_lock); + ret = scrub_supers(sctx, dev); + up_read(&fs_info->scrub_super_lock); + } if (!ret) - ret = scrub_enumerate_chunks(sctx, dev, start, end); + ret = scrub_enumerate_chunks(sctx, dev, start, end, + is_dev_replace); wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0); atomic_dec(&fs_info->scrubs_running); @@ -2537,3 +3009,272 @@ int btrfs_scrub_progress(struct btrfs_root *root, u64 devid, return dev ? (sctx ? 0 : -ENOTCONN) : -ENODEV; } + +static void scrub_remap_extent(struct btrfs_fs_info *fs_info, + u64 extent_logical, u64 extent_len, + u64 *extent_physical, + struct btrfs_device **extent_dev, + int *extent_mirror_num) +{ + u64 mapped_length; + struct btrfs_bio *bbio = NULL; + int ret; + + mapped_length = extent_len; + ret = btrfs_map_block(fs_info, READ, extent_logical, + &mapped_length, &bbio, 0); + if (ret || !bbio || mapped_length < extent_len || + !bbio->stripes[0].dev->bdev) { + kfree(bbio); + return; + } + + *extent_physical = bbio->stripes[0].physical; + *extent_mirror_num = bbio->mirror_num; + *extent_dev = bbio->stripes[0].dev; + kfree(bbio); +} + +static int scrub_setup_wr_ctx(struct scrub_ctx *sctx, + struct scrub_wr_ctx *wr_ctx, + struct btrfs_fs_info *fs_info, + struct btrfs_device *dev, + int is_dev_replace) +{ + WARN_ON(wr_ctx->wr_curr_bio != NULL); + + mutex_init(&wr_ctx->wr_lock); + wr_ctx->wr_curr_bio = NULL; + if (!is_dev_replace) + return 0; + + WARN_ON(!dev->bdev); + wr_ctx->pages_per_wr_bio = min_t(int, SCRUB_PAGES_PER_WR_BIO, + bio_get_nr_vecs(dev->bdev)); + wr_ctx->tgtdev = dev; + atomic_set(&wr_ctx->flush_all_writes, 0); + return 0; +} + +static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx) +{ + mutex_lock(&wr_ctx->wr_lock); + kfree(wr_ctx->wr_curr_bio); + wr_ctx->wr_curr_bio = NULL; + mutex_unlock(&wr_ctx->wr_lock); +} + +static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len, + int mirror_num, u64 physical_for_dev_replace) +{ + struct scrub_copy_nocow_ctx *nocow_ctx; + struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; + + nocow_ctx = kzalloc(sizeof(*nocow_ctx), GFP_NOFS); + if (!nocow_ctx) { + spin_lock(&sctx->stat_lock); + sctx->stat.malloc_errors++; + spin_unlock(&sctx->stat_lock); + return -ENOMEM; + } + + scrub_pending_trans_workers_inc(sctx); + + nocow_ctx->sctx = sctx; + nocow_ctx->logical = logical; + nocow_ctx->len = len; + nocow_ctx->mirror_num = mirror_num; + nocow_ctx->physical_for_dev_replace = physical_for_dev_replace; + nocow_ctx->work.func = copy_nocow_pages_worker; + btrfs_queue_worker(&fs_info->scrub_nocow_workers, + &nocow_ctx->work); + + return 0; +} + +static void copy_nocow_pages_worker(struct btrfs_work *work) +{ + struct scrub_copy_nocow_ctx *nocow_ctx = + container_of(work, struct scrub_copy_nocow_ctx, work); + struct scrub_ctx *sctx = nocow_ctx->sctx; + u64 logical = nocow_ctx->logical; + u64 len = nocow_ctx->len; + int mirror_num = nocow_ctx->mirror_num; + u64 physical_for_dev_replace = nocow_ctx->physical_for_dev_replace; + int ret; + struct btrfs_trans_handle *trans = NULL; + struct btrfs_fs_info *fs_info; + struct btrfs_path *path; + struct btrfs_root *root; + int not_written = 0; + + fs_info = sctx->dev_root->fs_info; + root = fs_info->extent_root; + + path = btrfs_alloc_path(); + if (!path) { + spin_lock(&sctx->stat_lock); + sctx->stat.malloc_errors++; + spin_unlock(&sctx->stat_lock); + not_written = 1; + goto out; + } + + trans = btrfs_join_transaction(root); + if (IS_ERR(trans)) { + not_written = 1; + goto out; + } + + ret = iterate_inodes_from_logical(logical, fs_info, path, + copy_nocow_pages_for_inode, + nocow_ctx); + if (ret != 0 && ret != -ENOENT) { + pr_warn("iterate_inodes_from_logical() failed: log %llu, phys %llu, len %llu, mir %llu, ret %d\n", + (unsigned long long)logical, + (unsigned long long)physical_for_dev_replace, + (unsigned long long)len, + (unsigned long long)mirror_num, ret); + not_written = 1; + goto out; + } + +out: + if (trans && !IS_ERR(trans)) + btrfs_end_transaction(trans, root); + if (not_written) + btrfs_dev_replace_stats_inc(&fs_info->dev_replace. + num_uncorrectable_read_errors); + + btrfs_free_path(path); + kfree(nocow_ctx); + + scrub_pending_trans_workers_dec(sctx); +} + +static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx) +{ + unsigned long index; + struct scrub_copy_nocow_ctx *nocow_ctx = ctx; + int ret = 0; + struct btrfs_key key; + struct inode *inode = NULL; + struct btrfs_root *local_root; + u64 physical_for_dev_replace; + u64 len; + struct btrfs_fs_info *fs_info = nocow_ctx->sctx->dev_root->fs_info; + + key.objectid = root; + key.type = BTRFS_ROOT_ITEM_KEY; + key.offset = (u64)-1; + local_root = btrfs_read_fs_root_no_name(fs_info, &key); + if (IS_ERR(local_root)) + return PTR_ERR(local_root); + + key.type = BTRFS_INODE_ITEM_KEY; + key.objectid = inum; + key.offset = 0; + inode = btrfs_iget(fs_info->sb, &key, local_root, NULL); + if (IS_ERR(inode)) + return PTR_ERR(inode); + + physical_for_dev_replace = nocow_ctx->physical_for_dev_replace; + len = nocow_ctx->len; + while (len >= PAGE_CACHE_SIZE) { + struct page *page = NULL; + int ret_sub; + + index = offset >> PAGE_CACHE_SHIFT; + + page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); + if (!page) { + pr_err("find_or_create_page() failed\n"); + ret = -ENOMEM; + goto next_page; + } + + if (PageUptodate(page)) { + if (PageDirty(page)) + goto next_page; + } else { + ClearPageError(page); + ret_sub = extent_read_full_page(&BTRFS_I(inode)-> + io_tree, + page, btrfs_get_extent, + nocow_ctx->mirror_num); + if (ret_sub) { + ret = ret_sub; + goto next_page; + } + wait_on_page_locked(page); + if (!PageUptodate(page)) { + ret = -EIO; + goto next_page; + } + } + ret_sub = write_page_nocow(nocow_ctx->sctx, + physical_for_dev_replace, page); + if (ret_sub) { + ret = ret_sub; + goto next_page; + } + +next_page: + if (page) { + unlock_page(page); + put_page(page); + } + offset += PAGE_CACHE_SIZE; + physical_for_dev_replace += PAGE_CACHE_SIZE; + len -= PAGE_CACHE_SIZE; + } + + if (inode) + iput(inode); + return ret; +} + +static int write_page_nocow(struct scrub_ctx *sctx, + u64 physical_for_dev_replace, struct page *page) +{ + struct bio *bio; + struct btrfs_device *dev; + int ret; + DECLARE_COMPLETION_ONSTACK(compl); + + dev = sctx->wr_ctx.tgtdev; + if (!dev) + return -EIO; + if (!dev->bdev) { + printk_ratelimited(KERN_WARNING + "btrfs: scrub write_page_nocow(bdev == NULL) is unexpected!\n"); + return -EIO; + } + bio = bio_alloc(GFP_NOFS, 1); + if (!bio) { + spin_lock(&sctx->stat_lock); + sctx->stat.malloc_errors++; + spin_unlock(&sctx->stat_lock); + return -ENOMEM; + } + bio->bi_private = &compl; + bio->bi_end_io = scrub_complete_bio_end_io; + bio->bi_size = 0; + bio->bi_sector = physical_for_dev_replace >> 9; + bio->bi_bdev = dev->bdev; + ret = bio_add_page(bio, page, PAGE_CACHE_SIZE, 0); + if (ret != PAGE_CACHE_SIZE) { +leave_with_eio: + bio_put(bio); + btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS); + return -EIO; + } + btrfsic_submit_bio(WRITE_SYNC, bio); + wait_for_completion(&compl); + + if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + goto leave_with_eio; + + bio_put(bio); + return 0; +} diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 837ad2d..ad43806 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1195,7 +1195,8 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, btrfs_set_max_workers(&fs_info->endio_freespace_worker, new_pool_size); btrfs_set_max_workers(&fs_info->delayed_workers, new_pool_size); btrfs_set_max_workers(&fs_info->readahead_workers, new_pool_size); - btrfs_set_max_workers(&fs_info->scrub_workers, new_pool_size); + btrfs_set_max_workers(&fs_info->scrub_wr_completion_workers, + new_pool_size); } static int btrfs_remount(struct super_block *sb, int *flags, char *data) -- cgit v0.10.2 From e93c89c1aaaaaec3487c4c18dd02360371790722 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Mon, 5 Nov 2012 17:33:06 +0100 Subject: Btrfs: add new sources for device replace code This adds a new file to the sources together with the header file and the changes to ioctl.h and ctree.h that are required by the new C source file. Additionally, 4 new functions are added to volume.c that deal with device creation and destruction. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index d7fcdba..7df3e0f 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -8,7 +8,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ export.o tree-log.o free-space-cache.o zlib.o lzo.o \ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ - reada.o backref.o ulist.o qgroup.o send.o + reada.o backref.o ulist.o qgroup.o send.o dev-replace.o btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index ded7caa..45e7f75 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -142,6 +142,8 @@ struct btrfs_ordered_sum; #define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2 +#define BTRFS_DEV_REPLACE_DEVID 0 + /* * the max metadata block size. This limit is somewhat artificial, * but the memmove costs go through the roof for larger blocks. diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c new file mode 100644 index 0000000..66dbc8d --- /dev/null +++ b/fs/btrfs/dev-replace.c @@ -0,0 +1,856 @@ +/* + * Copyright (C) STRATO AG 2012. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "compat.h" +#include "ctree.h" +#include "extent_map.h" +#include "disk-io.h" +#include "transaction.h" +#include "print-tree.h" +#include "volumes.h" +#include "async-thread.h" +#include "check-integrity.h" +#include "rcu-string.h" +#include "dev-replace.h" + +static u64 btrfs_get_seconds_since_1970(void); +static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, + int scrub_ret); +static void btrfs_dev_replace_update_device_in_mapping_tree( + struct btrfs_fs_info *fs_info, + struct btrfs_device *srcdev, + struct btrfs_device *tgtdev); +static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid, + char *srcdev_name, + struct btrfs_device **device); +static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info); +static int btrfs_dev_replace_kthread(void *data); +static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info); + + +int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info) +{ + struct btrfs_key key; + struct btrfs_root *dev_root = fs_info->dev_root; + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + struct extent_buffer *eb; + int slot; + int ret = 0; + struct btrfs_path *path = NULL; + int item_size; + struct btrfs_dev_replace_item *ptr; + u64 src_devid; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + + key.objectid = 0; + key.type = BTRFS_DEV_REPLACE_KEY; + key.offset = 0; + ret = btrfs_search_slot(NULL, dev_root, &key, path, 0, 0); + if (ret) { +no_valid_dev_replace_entry_found: + ret = 0; + dev_replace->replace_state = + BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED; + dev_replace->cont_reading_from_srcdev_mode = + BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_ALWAYS; + dev_replace->replace_state = 0; + dev_replace->time_started = 0; + dev_replace->time_stopped = 0; + atomic64_set(&dev_replace->num_write_errors, 0); + atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0); + dev_replace->cursor_left = 0; + dev_replace->committed_cursor_left = 0; + dev_replace->cursor_left_last_write_of_item = 0; + dev_replace->cursor_right = 0; + dev_replace->srcdev = NULL; + dev_replace->tgtdev = NULL; + dev_replace->is_valid = 0; + dev_replace->item_needs_writeback = 0; + goto out; + } + slot = path->slots[0]; + eb = path->nodes[0]; + item_size = btrfs_item_size_nr(eb, slot); + ptr = btrfs_item_ptr(eb, slot, struct btrfs_dev_replace_item); + + if (item_size != sizeof(struct btrfs_dev_replace_item)) { + pr_warn("btrfs: dev_replace entry found has unexpected size, ignore entry\n"); + goto no_valid_dev_replace_entry_found; + } + + src_devid = btrfs_dev_replace_src_devid(eb, ptr); + dev_replace->cont_reading_from_srcdev_mode = + btrfs_dev_replace_cont_reading_from_srcdev_mode(eb, ptr); + dev_replace->replace_state = btrfs_dev_replace_replace_state(eb, ptr); + dev_replace->time_started = btrfs_dev_replace_time_started(eb, ptr); + dev_replace->time_stopped = + btrfs_dev_replace_time_stopped(eb, ptr); + atomic64_set(&dev_replace->num_write_errors, + btrfs_dev_replace_num_write_errors(eb, ptr)); + atomic64_set(&dev_replace->num_uncorrectable_read_errors, + btrfs_dev_replace_num_uncorrectable_read_errors(eb, ptr)); + dev_replace->cursor_left = btrfs_dev_replace_cursor_left(eb, ptr); + dev_replace->committed_cursor_left = dev_replace->cursor_left; + dev_replace->cursor_left_last_write_of_item = dev_replace->cursor_left; + dev_replace->cursor_right = btrfs_dev_replace_cursor_right(eb, ptr); + dev_replace->is_valid = 1; + + dev_replace->item_needs_writeback = 0; + switch (dev_replace->replace_state) { + case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: + dev_replace->srcdev = NULL; + dev_replace->tgtdev = NULL; + break; + case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: + dev_replace->srcdev = btrfs_find_device(fs_info, src_devid, + NULL, NULL); + dev_replace->tgtdev = btrfs_find_device(fs_info, + BTRFS_DEV_REPLACE_DEVID, + NULL, NULL); + /* + * allow 'btrfs dev replace_cancel' if src/tgt device is + * missing + */ + if (!dev_replace->srcdev && + !btrfs_test_opt(dev_root, DEGRADED)) { + ret = -EIO; + pr_warn("btrfs: cannot mount because device replace operation is ongoing and\n" "srcdev (devid %llu) is missing, need to run 'btrfs dev scan'?\n", + (unsigned long long)src_devid); + } + if (!dev_replace->tgtdev && + !btrfs_test_opt(dev_root, DEGRADED)) { + ret = -EIO; + pr_warn("btrfs: cannot mount because device replace operation is ongoing and\n" "tgtdev (devid %llu) is missing, need to run btrfs dev scan?\n", + (unsigned long long)BTRFS_DEV_REPLACE_DEVID); + } + if (dev_replace->tgtdev) { + if (dev_replace->srcdev) { + dev_replace->tgtdev->total_bytes = + dev_replace->srcdev->total_bytes; + dev_replace->tgtdev->disk_total_bytes = + dev_replace->srcdev->disk_total_bytes; + dev_replace->tgtdev->bytes_used = + dev_replace->srcdev->bytes_used; + } + dev_replace->tgtdev->is_tgtdev_for_dev_replace = 1; + btrfs_init_dev_replace_tgtdev_for_resume(fs_info, + dev_replace->tgtdev); + } + break; + } + +out: + if (path) + btrfs_free_path(path); + return ret; +} + +/* + * called from commit_transaction. Writes changed device replace state to + * disk. + */ +int btrfs_run_dev_replace(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info) +{ + int ret; + struct btrfs_root *dev_root = fs_info->dev_root; + struct btrfs_path *path; + struct btrfs_key key; + struct extent_buffer *eb; + struct btrfs_dev_replace_item *ptr; + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + + btrfs_dev_replace_lock(dev_replace); + if (!dev_replace->is_valid || + !dev_replace->item_needs_writeback) { + btrfs_dev_replace_unlock(dev_replace); + return 0; + } + btrfs_dev_replace_unlock(dev_replace); + + key.objectid = 0; + key.type = BTRFS_DEV_REPLACE_KEY; + key.offset = 0; + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out; + } + ret = btrfs_search_slot(trans, dev_root, &key, path, -1, 1); + if (ret < 0) { + pr_warn("btrfs: error %d while searching for dev_replace item!\n", + ret); + goto out; + } + + if (ret == 0 && + btrfs_item_size_nr(path->nodes[0], path->slots[0]) < sizeof(*ptr)) { + /* + * need to delete old one and insert a new one. + * Since no attempt is made to recover any old state, if the + * dev_replace state is 'running', the data on the target + * drive is lost. + * It would be possible to recover the state: just make sure + * that the beginning of the item is never changed and always + * contains all the essential information. Then read this + * minimal set of information and use it as a base for the + * new state. + */ + ret = btrfs_del_item(trans, dev_root, path); + if (ret != 0) { + pr_warn("btrfs: delete too small dev_replace item failed %d!\n", + ret); + goto out; + } + ret = 1; + } + + if (ret == 1) { + /* need to insert a new item */ + btrfs_release_path(path); + ret = btrfs_insert_empty_item(trans, dev_root, path, + &key, sizeof(*ptr)); + if (ret < 0) { + pr_warn("btrfs: insert dev_replace item failed %d!\n", + ret); + goto out; + } + } + + eb = path->nodes[0]; + ptr = btrfs_item_ptr(eb, path->slots[0], + struct btrfs_dev_replace_item); + + btrfs_dev_replace_lock(dev_replace); + if (dev_replace->srcdev) + btrfs_set_dev_replace_src_devid(eb, ptr, + dev_replace->srcdev->devid); + else + btrfs_set_dev_replace_src_devid(eb, ptr, (u64)-1); + btrfs_set_dev_replace_cont_reading_from_srcdev_mode(eb, ptr, + dev_replace->cont_reading_from_srcdev_mode); + btrfs_set_dev_replace_replace_state(eb, ptr, + dev_replace->replace_state); + btrfs_set_dev_replace_time_started(eb, ptr, dev_replace->time_started); + btrfs_set_dev_replace_time_stopped(eb, ptr, dev_replace->time_stopped); + btrfs_set_dev_replace_num_write_errors(eb, ptr, + atomic64_read(&dev_replace->num_write_errors)); + btrfs_set_dev_replace_num_uncorrectable_read_errors(eb, ptr, + atomic64_read(&dev_replace->num_uncorrectable_read_errors)); + dev_replace->cursor_left_last_write_of_item = + dev_replace->cursor_left; + btrfs_set_dev_replace_cursor_left(eb, ptr, + dev_replace->cursor_left_last_write_of_item); + btrfs_set_dev_replace_cursor_right(eb, ptr, + dev_replace->cursor_right); + dev_replace->item_needs_writeback = 0; + btrfs_dev_replace_unlock(dev_replace); + + btrfs_mark_buffer_dirty(eb); + +out: + btrfs_free_path(path); + + return ret; +} + +void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info) +{ + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + + dev_replace->committed_cursor_left = + dev_replace->cursor_left_last_write_of_item; +} + +static u64 btrfs_get_seconds_since_1970(void) +{ + struct timespec t = CURRENT_TIME_SEC; + + return t.tv_sec; +} + +int btrfs_dev_replace_start(struct btrfs_root *root, + struct btrfs_ioctl_dev_replace_args *args) +{ + struct btrfs_trans_handle *trans; + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + int ret; + struct btrfs_device *tgt_device = NULL; + struct btrfs_device *src_device = NULL; + + switch (args->start.cont_reading_from_srcdev_mode) { + case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS: + case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID: + break; + default: + return -EINVAL; + } + + if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') || + args->start.tgtdev_name[0] == '\0') + return -EINVAL; + + mutex_lock(&fs_info->volume_mutex); + ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name, + &tgt_device); + if (ret) { + pr_err("btrfs: target device %s is invalid!\n", + args->start.tgtdev_name); + mutex_unlock(&fs_info->volume_mutex); + return -EINVAL; + } + + ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid, + args->start.srcdev_name, + &src_device); + mutex_unlock(&fs_info->volume_mutex); + if (ret) { + ret = -EINVAL; + goto leave_no_lock; + } + + if (tgt_device->total_bytes < src_device->total_bytes) { + pr_err("btrfs: target device is smaller than source device!\n"); + ret = -EINVAL; + goto leave_no_lock; + } + + btrfs_dev_replace_lock(dev_replace); + switch (dev_replace->replace_state) { + case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: + break; + case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: + args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED; + goto leave; + } + + dev_replace->cont_reading_from_srcdev_mode = + args->start.cont_reading_from_srcdev_mode; + WARN_ON(!src_device); + dev_replace->srcdev = src_device; + WARN_ON(!tgt_device); + dev_replace->tgtdev = tgt_device; + + printk_in_rcu(KERN_INFO + "btrfs: dev_replace from %s (devid %llu) to %s) started\n", + src_device->missing ? "" : + rcu_str_deref(src_device->name), + src_device->devid, + rcu_str_deref(tgt_device->name)); + + tgt_device->total_bytes = src_device->total_bytes; + tgt_device->disk_total_bytes = src_device->disk_total_bytes; + tgt_device->bytes_used = src_device->bytes_used; + + /* + * from now on, the writes to the srcdev are all duplicated to + * go to the tgtdev as well (refer to btrfs_map_block()). + */ + dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED; + dev_replace->time_started = btrfs_get_seconds_since_1970(); + dev_replace->cursor_left = 0; + dev_replace->committed_cursor_left = 0; + dev_replace->cursor_left_last_write_of_item = 0; + dev_replace->cursor_right = 0; + dev_replace->is_valid = 1; + dev_replace->item_needs_writeback = 1; + args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR; + btrfs_dev_replace_unlock(dev_replace); + + btrfs_wait_ordered_extents(root, 0); + + /* force writing the updated state information to disk */ + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + btrfs_dev_replace_lock(dev_replace); + goto leave; + } + + ret = btrfs_commit_transaction(trans, root); + WARN_ON(ret); + + /* the disk copy procedure reuses the scrub code */ + ret = btrfs_scrub_dev(fs_info, src_device->devid, 0, + src_device->total_bytes, + &dev_replace->scrub_progress, 0, 1); + + ret = btrfs_dev_replace_finishing(root->fs_info, ret); + WARN_ON(ret); + + return 0; + +leave: + dev_replace->srcdev = NULL; + dev_replace->tgtdev = NULL; + btrfs_dev_replace_unlock(dev_replace); +leave_no_lock: + if (tgt_device) + btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); + return ret; +} + +static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, + int scrub_ret) +{ + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + struct btrfs_device *tgt_device; + struct btrfs_device *src_device; + struct btrfs_root *root = fs_info->tree_root; + u8 uuid_tmp[BTRFS_UUID_SIZE]; + struct btrfs_trans_handle *trans; + int ret = 0; + + /* don't allow cancel or unmount to disturb the finishing procedure */ + mutex_lock(&dev_replace->lock_finishing_cancel_unmount); + + btrfs_dev_replace_lock(dev_replace); + /* was the operation canceled, or is it finished? */ + if (dev_replace->replace_state != + BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED) { + btrfs_dev_replace_unlock(dev_replace); + mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); + return 0; + } + + tgt_device = dev_replace->tgtdev; + src_device = dev_replace->srcdev; + btrfs_dev_replace_unlock(dev_replace); + + /* replace old device with new one in mapping tree */ + if (!scrub_ret) + btrfs_dev_replace_update_device_in_mapping_tree(fs_info, + src_device, + tgt_device); + + /* + * flush all outstanding I/O and inode extent mappings before the + * copy operation is declared as being finished + */ + btrfs_start_delalloc_inodes(root, 0); + btrfs_wait_ordered_extents(root, 0); + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); + return PTR_ERR(trans); + } + ret = btrfs_commit_transaction(trans, root); + WARN_ON(ret); + + /* keep away write_all_supers() during the finishing procedure */ + mutex_lock(&root->fs_info->fs_devices->device_list_mutex); + btrfs_dev_replace_lock(dev_replace); + dev_replace->replace_state = + scrub_ret ? BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED + : BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED; + dev_replace->tgtdev = NULL; + dev_replace->srcdev = NULL; + dev_replace->time_stopped = btrfs_get_seconds_since_1970(); + dev_replace->item_needs_writeback = 1; + + if (scrub_ret) { + printk_in_rcu(KERN_ERR + "btrfs: btrfs_scrub_dev(%s, %llu, %s) failed %d\n", + src_device->missing ? "" : + rcu_str_deref(src_device->name), + src_device->devid, + rcu_str_deref(tgt_device->name), scrub_ret); + btrfs_dev_replace_unlock(dev_replace); + mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); + if (tgt_device) + btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); + mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); + + return 0; + } + + printk_in_rcu(KERN_INFO + "btrfs: dev_replace from %s (devid %llu) to %s) finished\n", + src_device->missing ? "" : + rcu_str_deref(src_device->name), + src_device->devid, + rcu_str_deref(tgt_device->name)); + tgt_device->is_tgtdev_for_dev_replace = 0; + tgt_device->devid = src_device->devid; + src_device->devid = BTRFS_DEV_REPLACE_DEVID; + tgt_device->bytes_used = src_device->bytes_used; + memcpy(uuid_tmp, tgt_device->uuid, sizeof(uuid_tmp)); + memcpy(tgt_device->uuid, src_device->uuid, sizeof(tgt_device->uuid)); + memcpy(src_device->uuid, uuid_tmp, sizeof(src_device->uuid)); + tgt_device->total_bytes = src_device->total_bytes; + tgt_device->disk_total_bytes = src_device->disk_total_bytes; + tgt_device->bytes_used = src_device->bytes_used; + if (fs_info->sb->s_bdev == src_device->bdev) + fs_info->sb->s_bdev = tgt_device->bdev; + if (fs_info->fs_devices->latest_bdev == src_device->bdev) + fs_info->fs_devices->latest_bdev = tgt_device->bdev; + list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); + + btrfs_rm_dev_replace_srcdev(fs_info, src_device); + if (src_device->bdev) { + /* zero out the old super */ + btrfs_scratch_superblock(src_device); + } + /* + * this is again a consistent state where no dev_replace procedure + * is running, the target device is part of the filesystem, the + * source device is not part of the filesystem anymore and its 1st + * superblock is scratched out so that it is no longer marked to + * belong to this filesystem. + */ + btrfs_dev_replace_unlock(dev_replace); + mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); + + /* write back the superblocks */ + trans = btrfs_start_transaction(root, 0); + if (!IS_ERR(trans)) + btrfs_commit_transaction(trans, root); + + mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); + + return 0; +} + +static void btrfs_dev_replace_update_device_in_mapping_tree( + struct btrfs_fs_info *fs_info, + struct btrfs_device *srcdev, + struct btrfs_device *tgtdev) +{ + struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree; + struct extent_map *em; + struct map_lookup *map; + u64 start = 0; + int i; + + write_lock(&em_tree->lock); + do { + em = lookup_extent_mapping(em_tree, start, (u64)-1); + if (!em) + break; + map = (struct map_lookup *)em->bdev; + for (i = 0; i < map->num_stripes; i++) + if (srcdev == map->stripes[i].dev) + map->stripes[i].dev = tgtdev; + start = em->start + em->len; + free_extent_map(em); + } while (start); + write_unlock(&em_tree->lock); +} + +static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid, + char *srcdev_name, + struct btrfs_device **device) +{ + int ret; + + if (srcdevid) { + ret = 0; + *device = btrfs_find_device(root->fs_info, srcdevid, NULL, + NULL); + if (!*device) + ret = -ENOENT; + } else { + ret = btrfs_find_device_missing_or_by_path(root, srcdev_name, + device); + } + return ret; +} + +void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_dev_replace_args *args) +{ + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + + btrfs_dev_replace_lock(dev_replace); + /* even if !dev_replace_is_valid, the values are good enough for + * the replace_status ioctl */ + args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR; + args->status.replace_state = dev_replace->replace_state; + args->status.time_started = dev_replace->time_started; + args->status.time_stopped = dev_replace->time_stopped; + args->status.num_write_errors = + atomic64_read(&dev_replace->num_write_errors); + args->status.num_uncorrectable_read_errors = + atomic64_read(&dev_replace->num_uncorrectable_read_errors); + switch (dev_replace->replace_state) { + case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: + args->status.progress_1000 = 0; + break; + case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: + args->status.progress_1000 = 1000; + break; + case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: + args->status.progress_1000 = div64_u64(dev_replace->cursor_left, + div64_u64(dev_replace->srcdev->total_bytes, 1000)); + break; + } + btrfs_dev_replace_unlock(dev_replace); +} + +int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_dev_replace_args *args) +{ + args->result = __btrfs_dev_replace_cancel(fs_info); + return 0; +} + +static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info) +{ + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + struct btrfs_device *tgt_device = NULL; + struct btrfs_trans_handle *trans; + struct btrfs_root *root = fs_info->tree_root; + u64 result; + int ret; + + mutex_lock(&dev_replace->lock_finishing_cancel_unmount); + btrfs_dev_replace_lock(dev_replace); + switch (dev_replace->replace_state) { + case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: + result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED; + btrfs_dev_replace_unlock(dev_replace); + goto leave; + case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: + result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR; + tgt_device = dev_replace->tgtdev; + dev_replace->tgtdev = NULL; + dev_replace->srcdev = NULL; + break; + } + dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED; + dev_replace->time_stopped = btrfs_get_seconds_since_1970(); + dev_replace->item_needs_writeback = 1; + btrfs_dev_replace_unlock(dev_replace); + btrfs_scrub_cancel(fs_info); + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); + return PTR_ERR(trans); + } + ret = btrfs_commit_transaction(trans, root); + WARN_ON(ret); + if (tgt_device) + btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); + +leave: + mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); + return result; +} + +void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info) +{ + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + + mutex_lock(&dev_replace->lock_finishing_cancel_unmount); + btrfs_dev_replace_lock(dev_replace); + switch (dev_replace->replace_state) { + case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: + break; + case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: + dev_replace->replace_state = + BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED; + dev_replace->time_stopped = btrfs_get_seconds_since_1970(); + dev_replace->item_needs_writeback = 1; + pr_info("btrfs: suspending dev_replace for unmount\n"); + break; + } + + btrfs_dev_replace_unlock(dev_replace); + mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); +} + +/* resume dev_replace procedure that was interrupted by unmount */ +int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info) +{ + struct task_struct *task; + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + + btrfs_dev_replace_lock(dev_replace); + switch (dev_replace->replace_state) { + case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: + btrfs_dev_replace_unlock(dev_replace); + return 0; + case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: + break; + case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: + dev_replace->replace_state = + BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED; + break; + } + if (!dev_replace->tgtdev || !dev_replace->tgtdev->bdev) { + pr_info("btrfs: cannot continue dev_replace, tgtdev is missing\n" + "btrfs: you may cancel the operation after 'mount -o degraded'\n"); + btrfs_dev_replace_unlock(dev_replace); + return 0; + } + btrfs_dev_replace_unlock(dev_replace); + + WARN_ON(atomic_xchg( + &fs_info->mutually_exclusive_operation_running, 1)); + task = kthread_run(btrfs_dev_replace_kthread, fs_info, "btrfs-devrepl"); + return PTR_RET(task); +} + +static int btrfs_dev_replace_kthread(void *data) +{ + struct btrfs_fs_info *fs_info = data; + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + struct btrfs_ioctl_dev_replace_args *status_args; + u64 progress; + + status_args = kzalloc(sizeof(*status_args), GFP_NOFS); + if (status_args) { + btrfs_dev_replace_status(fs_info, status_args); + progress = status_args->status.progress_1000; + kfree(status_args); + do_div(progress, 10); + printk_in_rcu(KERN_INFO + "btrfs: continuing dev_replace from %s (devid %llu) to %s @%u%%\n", + dev_replace->srcdev->missing ? "" : + rcu_str_deref(dev_replace->srcdev->name), + dev_replace->srcdev->devid, + dev_replace->tgtdev ? + rcu_str_deref(dev_replace->tgtdev->name) : + "", + (unsigned int)progress); + } + btrfs_dev_replace_continue_on_mount(fs_info); + atomic_set(&fs_info->mutually_exclusive_operation_running, 0); + + return 0; +} + +static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info) +{ + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + int ret; + + ret = btrfs_scrub_dev(fs_info, dev_replace->srcdev->devid, + dev_replace->committed_cursor_left, + dev_replace->srcdev->total_bytes, + &dev_replace->scrub_progress, 0, 1); + ret = btrfs_dev_replace_finishing(fs_info, ret); + WARN_ON(ret); + return 0; +} + +int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace) +{ + if (!dev_replace->is_valid) + return 0; + + switch (dev_replace->replace_state) { + case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: + return 0; + case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: + /* + * return true even if tgtdev is missing (this is + * something that can happen if the dev_replace + * procedure is suspended by an umount and then + * the tgtdev is missing (or "btrfs dev scan") was + * not called and the the filesystem is remounted + * in degraded state. This does not stop the + * dev_replace procedure. It needs to be canceled + * manually if the cancelation is wanted. + */ + break; + } + return 1; +} + +void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace) +{ + /* the beginning is just an optimization for the typical case */ + if (atomic_read(&dev_replace->nesting_level) == 0) { +acquire_lock: + /* this is not a nested case where the same thread + * is trying to acqurire the same lock twice */ + mutex_lock(&dev_replace->lock); + mutex_lock(&dev_replace->lock_management_lock); + dev_replace->lock_owner = current->pid; + atomic_inc(&dev_replace->nesting_level); + mutex_unlock(&dev_replace->lock_management_lock); + return; + } + + mutex_lock(&dev_replace->lock_management_lock); + if (atomic_read(&dev_replace->nesting_level) > 0 && + dev_replace->lock_owner == current->pid) { + WARN_ON(!mutex_is_locked(&dev_replace->lock)); + atomic_inc(&dev_replace->nesting_level); + mutex_unlock(&dev_replace->lock_management_lock); + return; + } + + mutex_unlock(&dev_replace->lock_management_lock); + goto acquire_lock; +} + +void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace) +{ + WARN_ON(!mutex_is_locked(&dev_replace->lock)); + mutex_lock(&dev_replace->lock_management_lock); + WARN_ON(atomic_read(&dev_replace->nesting_level) < 1); + WARN_ON(dev_replace->lock_owner != current->pid); + atomic_dec(&dev_replace->nesting_level); + if (atomic_read(&dev_replace->nesting_level) == 0) { + dev_replace->lock_owner = 0; + mutex_unlock(&dev_replace->lock_management_lock); + mutex_unlock(&dev_replace->lock); + } else { + mutex_unlock(&dev_replace->lock_management_lock); + } +} diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h index 1fb5c89..20035cb 100644 --- a/fs/btrfs/dev-replace.h +++ b/fs/btrfs/dev-replace.h @@ -19,6 +19,24 @@ #if !defined(__BTRFS_DEV_REPLACE__) #define __BTRFS_DEV_REPLACE__ +struct btrfs_ioctl_dev_replace_args; + +int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info); +int btrfs_run_dev_replace(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info); +void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info); +int btrfs_dev_replace_start(struct btrfs_root *root, + struct btrfs_ioctl_dev_replace_args *args); +void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_dev_replace_args *args); +int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_dev_replace_args *args); +void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info); +int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info); +int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace); +void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace); +void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace); + static inline void btrfs_dev_replace_stats_inc(atomic64_t *stat_value) { atomic64_inc(stat_value); diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 731e287..62006ba 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h @@ -123,6 +123,48 @@ struct btrfs_ioctl_scrub_args { __u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8]; }; +#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS 0 +#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID 1 +struct btrfs_ioctl_dev_replace_start_params { + __u64 srcdevid; /* in, if 0, use srcdev_name instead */ + __u8 srcdev_name[BTRFS_PATH_NAME_MAX + 1]; /* in */ + __u8 tgtdev_name[BTRFS_PATH_NAME_MAX + 1]; /* in */ + __u64 cont_reading_from_srcdev_mode; /* in, see #define + * above */ +}; + +#define BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED 0 +#define BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED 1 +#define BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED 2 +#define BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED 3 +#define BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED 4 +struct btrfs_ioctl_dev_replace_status_params { + __u64 replace_state; /* out, see #define above */ + __u64 progress_1000; /* out, 0 <= x <= 1000 */ + __u64 time_started; /* out, seconds since 1-Jan-1970 */ + __u64 time_stopped; /* out, seconds since 1-Jan-1970 */ + __u64 num_write_errors; /* out */ + __u64 num_uncorrectable_read_errors; /* out */ +}; + +#define BTRFS_IOCTL_DEV_REPLACE_CMD_START 0 +#define BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS 1 +#define BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL 2 +#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR 0 +#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED 1 +#define BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED 2 +struct btrfs_ioctl_dev_replace_args { + __u64 cmd; /* in */ + __u64 result; /* out */ + + union { + struct btrfs_ioctl_dev_replace_start_params start; + struct btrfs_ioctl_dev_replace_status_params status; + }; /* in/out */ + + __u64 spare[64]; +}; + #define BTRFS_DEVICE_PATH_NAME_MAX 1024 struct btrfs_ioctl_dev_info_args { __u64 devid; /* in/out */ @@ -453,4 +495,7 @@ struct btrfs_ioctl_send_args { struct btrfs_ioctl_qgroup_limit_args) #define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \ struct btrfs_ioctl_get_dev_stats) +#define BTRFS_IOC_DEV_REPLACE _IOWR(BTRFS_IOCTL_MAGIC, 53, \ + struct btrfs_ioctl_dev_replace_args) + #endif diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 4158628..5777e6a 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1537,6 +1537,53 @@ error_undo: goto error_brelse; } +void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info, + struct btrfs_device *srcdev) +{ + WARN_ON(!mutex_is_locked(&fs_info->fs_devices->device_list_mutex)); + list_del_rcu(&srcdev->dev_list); + list_del_rcu(&srcdev->dev_alloc_list); + fs_info->fs_devices->num_devices--; + if (srcdev->missing) { + fs_info->fs_devices->missing_devices--; + fs_info->fs_devices->rw_devices++; + } + if (srcdev->can_discard) + fs_info->fs_devices->num_can_discard--; + if (srcdev->bdev) + fs_info->fs_devices->open_devices--; + + call_rcu(&srcdev->rcu, free_device); +} + +void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, + struct btrfs_device *tgtdev) +{ + struct btrfs_device *next_device; + + WARN_ON(!tgtdev); + mutex_lock(&fs_info->fs_devices->device_list_mutex); + if (tgtdev->bdev) { + btrfs_scratch_superblock(tgtdev); + fs_info->fs_devices->open_devices--; + } + fs_info->fs_devices->num_devices--; + if (tgtdev->can_discard) + fs_info->fs_devices->num_can_discard++; + + next_device = list_entry(fs_info->fs_devices->devices.next, + struct btrfs_device, dev_list); + if (tgtdev->bdev == fs_info->sb->s_bdev) + fs_info->sb->s_bdev = next_device->bdev; + if (tgtdev->bdev == fs_info->fs_devices->latest_bdev) + fs_info->fs_devices->latest_bdev = next_device->bdev; + list_del_rcu(&tgtdev->dev_list); + + call_rcu(&tgtdev->rcu, free_device); + + mutex_unlock(&fs_info->fs_devices->device_list_mutex); +} + int btrfs_find_device_by_path(struct btrfs_root *root, char *device_path, struct btrfs_device **device) { @@ -1931,6 +1978,98 @@ error: return ret; } +int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, + struct btrfs_device **device_out) +{ + struct request_queue *q; + struct btrfs_device *device; + struct block_device *bdev; + struct btrfs_fs_info *fs_info = root->fs_info; + struct list_head *devices; + struct rcu_string *name; + int ret = 0; + + *device_out = NULL; + if (fs_info->fs_devices->seeding) + return -EINVAL; + + bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL, + fs_info->bdev_holder); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + + filemap_write_and_wait(bdev->bd_inode->i_mapping); + + devices = &fs_info->fs_devices->devices; + list_for_each_entry(device, devices, dev_list) { + if (device->bdev == bdev) { + ret = -EEXIST; + goto error; + } + } + + device = kzalloc(sizeof(*device), GFP_NOFS); + if (!device) { + ret = -ENOMEM; + goto error; + } + + name = rcu_string_strdup(device_path, GFP_NOFS); + if (!name) { + kfree(device); + ret = -ENOMEM; + goto error; + } + rcu_assign_pointer(device->name, name); + + q = bdev_get_queue(bdev); + if (blk_queue_discard(q)) + device->can_discard = 1; + mutex_lock(&root->fs_info->fs_devices->device_list_mutex); + device->writeable = 1; + device->work.func = pending_bios_fn; + generate_random_uuid(device->uuid); + device->devid = BTRFS_DEV_REPLACE_DEVID; + spin_lock_init(&device->io_lock); + device->generation = 0; + device->io_width = root->sectorsize; + device->io_align = root->sectorsize; + device->sector_size = root->sectorsize; + device->total_bytes = i_size_read(bdev->bd_inode); + device->disk_total_bytes = device->total_bytes; + device->dev_root = fs_info->dev_root; + device->bdev = bdev; + device->in_fs_metadata = 1; + device->is_tgtdev_for_dev_replace = 1; + device->mode = FMODE_EXCL; + set_blocksize(device->bdev, 4096); + device->fs_devices = fs_info->fs_devices; + list_add(&device->dev_list, &fs_info->fs_devices->devices); + fs_info->fs_devices->num_devices++; + fs_info->fs_devices->open_devices++; + if (device->can_discard) + fs_info->fs_devices->num_can_discard++; + mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); + + *device_out = device; + return ret; + +error: + blkdev_put(bdev, FMODE_EXCL); + return ret; +} + +void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info, + struct btrfs_device *tgtdev) +{ + WARN_ON(fs_info->fs_devices->rw_devices == 0); + tgtdev->io_width = fs_info->dev_root->sectorsize; + tgtdev->io_align = fs_info->dev_root->sectorsize; + tgtdev->sector_size = fs_info->dev_root->sectorsize; + tgtdev->dev_root = fs_info->dev_root; + tgtdev->in_fs_metadata = 1; +} + static noinline int btrfs_update_device(struct btrfs_trans_handle *trans, struct btrfs_device *device) { diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 8fd5a4d..58d7937 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -286,6 +286,8 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid, u8 *uuid, u8 *fsid); int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); int btrfs_init_new_device(struct btrfs_root *root, char *path); +int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, + struct btrfs_device **device_out); int btrfs_balance(struct btrfs_balance_control *bctl, struct btrfs_ioctl_balance_args *bargs); int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info); @@ -302,6 +304,12 @@ int btrfs_get_dev_stats(struct btrfs_root *root, int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info); int btrfs_run_dev_stats(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info); +void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info, + struct btrfs_device *srcdev); +void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, + struct btrfs_device *tgtdev); +void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info, + struct btrfs_device *tgtdev); int btrfs_scratch_superblock(struct btrfs_device *device); static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, -- cgit v0.10.2 From 8dabb7420f014ab0f9f04afae8ae046c0f48b270 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Tue, 6 Nov 2012 13:15:27 +0100 Subject: Btrfs: change core code of btrfs to support the device replace operations This commit contains all the essential changes to the core code of Btrfs for support of the device replace procedure. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 0e41047..76b8250 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -45,6 +45,7 @@ #include "inode-map.h" #include "check-integrity.h" #include "rcu-string.h" +#include "dev-replace.h" #ifdef CONFIG_X86 #include @@ -2438,7 +2439,11 @@ int open_ctree(struct super_block *sb, goto fail_tree_roots; } - btrfs_close_extra_devices(fs_devices); + /* + * keep the device that is marked to be the target device for the + * dev_replace procedure + */ + btrfs_close_extra_devices(fs_info, fs_devices, 0); if (!fs_devices->latest_bdev) { printk(KERN_CRIT "btrfs: failed to read devices on %s\n", @@ -2510,6 +2515,14 @@ retry_root_backup: goto fail_block_groups; } + ret = btrfs_init_dev_replace(fs_info); + if (ret) { + pr_err("btrfs: failed to init dev_replace: %d\n", ret); + goto fail_block_groups; + } + + btrfs_close_extra_devices(fs_info, fs_devices, 1); + ret = btrfs_init_space_info(fs_info); if (ret) { printk(KERN_ERR "Failed to initial space info: %d\n", ret); @@ -2658,6 +2671,13 @@ retry_root_backup: return ret; } + ret = btrfs_resume_dev_replace_async(fs_info); + if (ret) { + pr_warn("btrfs: failed to resume dev_replace\n"); + close_ctree(tree_root); + return ret; + } + return 0; fail_qgroup: @@ -3300,6 +3320,8 @@ int close_ctree(struct btrfs_root *root) /* pause restriper - we want to resume on mount */ btrfs_pause_balance(fs_info); + btrfs_dev_replace_suspend_for_unmount(fs_info); + btrfs_scrub_cancel(fs_info); /* wait for any defraggers to finish */ diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index 9f363e1..c705a48 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -27,6 +27,7 @@ #include "volumes.h" #include "disk-io.h" #include "transaction.h" +#include "dev-replace.h" #undef DEBUG @@ -331,6 +332,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, int nzones = 0; int i; unsigned long index = logical >> PAGE_CACHE_SHIFT; + int dev_replace_is_ongoing; spin_lock(&fs_info->reada_lock); re = radix_tree_lookup(&fs_info->reada_tree, index); @@ -392,6 +394,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, } /* insert extent in reada_tree + all per-device trees, all or nothing */ + btrfs_dev_replace_lock(&fs_info->dev_replace); spin_lock(&fs_info->reada_lock); ret = radix_tree_insert(&fs_info->reada_tree, index, re); if (ret == -EEXIST) { @@ -399,13 +402,17 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, BUG_ON(!re_exist); re_exist->refcnt++; spin_unlock(&fs_info->reada_lock); + btrfs_dev_replace_unlock(&fs_info->dev_replace); goto error; } if (ret) { spin_unlock(&fs_info->reada_lock); + btrfs_dev_replace_unlock(&fs_info->dev_replace); goto error; } prev_dev = NULL; + dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing( + &fs_info->dev_replace); for (i = 0; i < nzones; ++i) { dev = bbio->stripes[i].dev; if (dev == prev_dev) { @@ -422,6 +429,14 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, /* cannot read ahead on missing device */ continue; } + if (dev_replace_is_ongoing && + dev == fs_info->dev_replace.tgtdev) { + /* + * as this device is selected for reading only as + * a last resort, skip it for read ahead. + */ + continue; + } prev_dev = dev; ret = radix_tree_insert(&dev->reada_extents, index, re); if (ret) { @@ -434,10 +449,12 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, BUG_ON(fs_info == NULL); radix_tree_delete(&fs_info->reada_tree, index); spin_unlock(&fs_info->reada_lock); + btrfs_dev_replace_unlock(&fs_info->dev_replace); goto error; } } spin_unlock(&fs_info->reada_lock); + btrfs_dev_replace_unlock(&fs_info->dev_replace); kfree(bbio); return re; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 61157a2..30cbf69 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -2843,12 +2843,17 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, return -EIO; } - if (dev->scrub_device) { + btrfs_dev_replace_lock(&fs_info->dev_replace); + if (dev->scrub_device || + (!is_dev_replace && + btrfs_dev_replace_is_ongoing(&fs_info->dev_replace))) { + btrfs_dev_replace_unlock(&fs_info->dev_replace); mutex_unlock(&fs_info->scrub_lock); mutex_unlock(&fs_info->fs_devices->device_list_mutex); scrub_workers_put(fs_info); return -EINPROGRESS; } + btrfs_dev_replace_unlock(&fs_info->dev_replace); sctx = scrub_setup_ctx(dev, is_dev_replace); if (IS_ERR(sctx)) { mutex_unlock(&fs_info->scrub_lock); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index ad43806..def4f24 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -55,6 +55,7 @@ #include "export.h" #include "compression.h" #include "rcu-string.h" +#include "dev-replace.h" #define CREATE_TRACE_POINTS #include @@ -1225,8 +1226,15 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) return 0; if (*flags & MS_RDONLY) { + /* + * this also happens on 'umount -rf' or on shutdown, when + * the filesystem is busy. + */ sb->s_flags |= MS_RDONLY; + btrfs_dev_replace_suspend_for_unmount(fs_info); + btrfs_scrub_cancel(fs_info); + ret = btrfs_commit_super(root); if (ret) goto restore; @@ -1263,6 +1271,11 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) if (ret) goto restore; + ret = btrfs_resume_dev_replace_async(fs_info); + if (ret) { + pr_warn("btrfs: failed to resume dev_replace\n"); + goto restore; + } sb->s_flags &= ~MS_RDONLY; } diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 7b29735..bcc6b65 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -30,6 +30,7 @@ #include "tree-log.h" #include "inode-map.h" #include "volumes.h" +#include "dev-replace.h" #define BTRFS_ROOT_TRANS_TAG 0 @@ -845,7 +846,9 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, return ret; ret = btrfs_run_dev_stats(trans, root->fs_info); - BUG_ON(ret); + WARN_ON(ret); + ret = btrfs_run_dev_replace(trans, root->fs_info); + WARN_ON(ret); ret = btrfs_run_qgroups(trans, root->fs_info); BUG_ON(ret); @@ -868,6 +871,8 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, switch_commit_root(fs_info->extent_root); up_write(&fs_info->extent_commit_sem); + btrfs_after_dev_replace_commit(fs_info); + return 0; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5777e6a..a4e0963 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -36,6 +36,7 @@ #include "check-integrity.h" #include "rcu-string.h" #include "math.h" +#include "dev-replace.h" static int init_first_rw_device(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -505,7 +506,8 @@ error: return ERR_PTR(-ENOMEM); } -void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices) +void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info, + struct btrfs_fs_devices *fs_devices, int step) { struct btrfs_device *device, *next; @@ -528,6 +530,21 @@ again: continue; } + if (device->devid == BTRFS_DEV_REPLACE_DEVID) { + /* + * In the first step, keep the device which has + * the correct fsid and the devid that is used + * for the dev_replace procedure. + * In the second step, the dev_replace state is + * read from the device tree and it is known + * whether the procedure is really active or + * not, which means whether this device is + * used or whether it should be removed. + */ + if (step == 0 || device->is_tgtdev_for_dev_replace) { + continue; + } + } if (device->bdev) { blkdev_put(device->bdev, device->mode); device->bdev = NULL; @@ -536,7 +553,8 @@ again: if (device->writeable) { list_del_init(&device->dev_alloc_list); device->writeable = 0; - fs_devices->rw_devices--; + if (!device->is_tgtdev_for_dev_replace) + fs_devices->rw_devices--; } list_del_init(&device->dev_list); fs_devices->num_devices--; @@ -594,7 +612,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) if (device->bdev) fs_devices->open_devices--; - if (device->writeable) { + if (device->writeable && !device->is_tgtdev_for_dev_replace) { list_del_init(&device->dev_alloc_list); fs_devices->rw_devices--; } @@ -718,7 +736,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, fs_devices->rotating = 1; fs_devices->open_devices++; - if (device->writeable) { + if (device->writeable && !device->is_tgtdev_for_dev_replace) { fs_devices->rw_devices++; list_add(&device->dev_alloc_list, &fs_devices->alloc_list); @@ -1350,16 +1368,22 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) root->fs_info->avail_system_alloc_bits | root->fs_info->avail_metadata_alloc_bits; - if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) && - root->fs_info->fs_devices->num_devices <= 4) { + num_devices = root->fs_info->fs_devices->num_devices; + btrfs_dev_replace_lock(&root->fs_info->dev_replace); + if (btrfs_dev_replace_is_ongoing(&root->fs_info->dev_replace)) { + WARN_ON(num_devices < 1); + num_devices--; + } + btrfs_dev_replace_unlock(&root->fs_info->dev_replace); + + if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) && num_devices <= 4) { printk(KERN_ERR "btrfs: unable to go below four devices " "on raid10\n"); ret = -EINVAL; goto out; } - if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) && - root->fs_info->fs_devices->num_devices <= 2) { + if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) && num_devices <= 2) { printk(KERN_ERR "btrfs: unable to go below two " "devices on raid1\n"); ret = -EINVAL; @@ -2935,6 +2959,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl, u64 allowed; int mixed = 0; int ret; + u64 num_devices; if (btrfs_fs_closing(fs_info) || atomic_read(&fs_info->balance_pause_req) || @@ -2963,10 +2988,17 @@ int btrfs_balance(struct btrfs_balance_control *bctl, } } + num_devices = fs_info->fs_devices->num_devices; + btrfs_dev_replace_lock(&fs_info->dev_replace); + if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) { + BUG_ON(num_devices < 1); + num_devices--; + } + btrfs_dev_replace_unlock(&fs_info->dev_replace); allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE; - if (fs_info->fs_devices->num_devices == 1) + if (num_devices == 1) allowed |= BTRFS_BLOCK_GROUP_DUP; - else if (fs_info->fs_devices->num_devices < 4) + else if (num_devices < 4) allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1); else allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | @@ -3591,6 +3623,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, devices_info[ndevs].total_avail = total_avail; devices_info[ndevs].dev = device; ++ndevs; + WARN_ON(ndevs > fs_devices->rw_devices); } /* @@ -4773,6 +4806,7 @@ static void fill_device_from_item(struct extent_buffer *leaf, device->io_align = btrfs_device_io_align(leaf, dev_item); device->io_width = btrfs_device_io_width(leaf, dev_item); device->sector_size = btrfs_device_sector_size(leaf, dev_item); + WARN_ON(device->devid == BTRFS_DEV_REPLACE_DEVID); device->is_tgtdev_for_dev_replace = 0; ptr = (unsigned long)btrfs_device_uuid(dev_item); diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 58d7937..37d0157 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -268,7 +268,8 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, struct btrfs_fs_devices **fs_devices_ret); int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); -void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices); +void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info, + struct btrfs_fs_devices *fs_devices, int step); int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, char *device_path, struct btrfs_device **device); -- cgit v0.10.2 From 29a8d9a0bce6a5abac1f313400c2e189e8d10e67 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Tue, 6 Nov 2012 14:16:24 +0100 Subject: Btrfs: introduce GET_READ_MIRRORS functionality for btrfs_map_block() Before this commit, btrfs_map_block() was called with REQ_WRITE in order to retrieve the list of mirrors for a disk block. This needs to be changed for the device replace procedure since it makes a difference whether you are asking for read mirrors or for locations to write to. GET_READ_MIRRORS is introduced as a new interface to call btrfs_map_block(). In the current commit, the functionality is not yet changed, only the interface for GET_READ_MIRRORS is introduced and all the places that should use this new interface are adapted. The reason that REQ_WRITE cannot be abused anymore to retrieve a list of read mirrors is that during a running dev replace operation all write requests to the live filesystem are duplicated to also write to the target drive. Keep in mind that the target disk is only partially a valid copy of the source disk while the operation is ongoing. All writes go to the target disk, but not all reads would return valid data on the target disk. Therefore it is not possible anymore to abuse a REQ_WRITE interface to find valid mirrors for a REQ_READ. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 45e7f75..46bd7d5 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -174,6 +174,9 @@ static int btrfs_csum_sizes[] = { 4, 0 }; /* four bytes for CRC32 */ #define BTRFS_EMPTY_DIR_SIZE 0 +/* spefic to btrfs_map_block(), therefore not in include/linux/blk_types.h */ +#define REQ_GET_READ_MIRRORS (1 << 30) + #define BTRFS_FT_UNKNOWN 0 #define BTRFS_FT_REG_FILE 1 #define BTRFS_FT_DIR 2 diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index c705a48..96b93da 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -359,7 +359,8 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root, * map block */ length = blocksize; - ret = btrfs_map_block(fs_info, REQ_WRITE, logical, &length, &bbio, 0); + ret = btrfs_map_block(fs_info, REQ_GET_READ_MIRRORS, logical, &length, + &bbio, 0); if (ret || !bbio || length < blocksize) goto error; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 30cbf69..30ba997 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1193,8 +1193,8 @@ static int scrub_setup_recheck_block(struct scrub_ctx *sctx, * with a length of PAGE_SIZE, each returned stripe * represents one mirror */ - ret = btrfs_map_block(fs_info, WRITE, logical, &mapped_length, - &bbio, 0); + ret = btrfs_map_block(fs_info, REQ_GET_READ_MIRRORS, logical, + &mapped_length, &bbio, 0); if (ret || !bbio || mapped_length < sublen) { kfree(bbio); return -EIO; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index a4e0963..de0c05c 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4103,7 +4103,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, stripe_nr_end - stripe_nr_orig); stripe_index = do_div(stripe_nr, map->num_stripes); } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) { - if (rw & (REQ_WRITE | REQ_DISCARD)) + if (rw & (REQ_WRITE | REQ_DISCARD | REQ_GET_READ_MIRRORS)) num_stripes = map->num_stripes; else if (mirror_num) stripe_index = mirror_num - 1; @@ -4115,7 +4115,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, } } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { - if (rw & (REQ_WRITE | REQ_DISCARD)) { + if (rw & (REQ_WRITE | REQ_DISCARD | REQ_GET_READ_MIRRORS)) { num_stripes = map->num_stripes; } else if (mirror_num) { stripe_index = mirror_num - 1; @@ -4129,7 +4129,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, stripe_index = do_div(stripe_nr, factor); stripe_index *= map->sub_stripes; - if (rw & REQ_WRITE) + if (rw & (REQ_WRITE | REQ_GET_READ_MIRRORS)) num_stripes = map->sub_stripes; else if (rw & REQ_DISCARD) num_stripes = min_t(u64, map->sub_stripes * @@ -4242,7 +4242,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, } } - if (rw & REQ_WRITE) { + if (rw & (REQ_WRITE | REQ_GET_READ_MIRRORS)) { if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10 | BTRFS_BLOCK_GROUP_DUP)) { -- cgit v0.10.2 From 472262f35a6b3407e761b700d74c53530e5f144d Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Tue, 6 Nov 2012 14:43:46 +0100 Subject: Btrfs: changes to live filesystem are also written to replacement disk During a running dev replace operation, all write requests to the live filesystem are duplicated to also write to the target drive. Therefore btrfs_map_block() is changed to duplicate stripes that are written to the source disk of a device replace procedure to be written to the target disk as well. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index de0c05c..4d3bf18 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4044,6 +4044,9 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, int num_stripes; int max_errors = 0; struct btrfs_bio *bbio = NULL; + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; + int dev_replace_is_ongoing = 0; + int num_alloc_stripes; read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, logical, *length); @@ -4089,6 +4092,11 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, if (!bbio_ret) goto out; + btrfs_dev_replace_lock(dev_replace); + dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace); + if (!dev_replace_is_ongoing) + btrfs_dev_replace_unlock(dev_replace); + num_stripes = 1; stripe_index = 0; stripe_nr_orig = stripe_nr; @@ -4155,7 +4163,10 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, } BUG_ON(stripe_index >= map->num_stripes); - bbio = kzalloc(btrfs_bio_size(num_stripes), GFP_NOFS); + num_alloc_stripes = num_stripes; + if (dev_replace_is_ongoing && (rw & (REQ_WRITE | REQ_DISCARD))) + num_alloc_stripes <<= 1; + bbio = kzalloc(btrfs_bio_size(num_alloc_stripes), GFP_NOFS); if (!bbio) { ret = -ENOMEM; goto out; @@ -4250,11 +4261,48 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, } } + if (dev_replace_is_ongoing && (rw & (REQ_WRITE | REQ_DISCARD)) && + dev_replace->tgtdev != NULL) { + int index_where_to_add; + u64 srcdev_devid = dev_replace->srcdev->devid; + + /* + * duplicate the write operations while the dev replace + * procedure is running. Since the copying of the old disk + * to the new disk takes place at run time while the + * filesystem is mounted writable, the regular write + * operations to the old disk have to be duplicated to go + * to the new disk as well. + * Note that device->missing is handled by the caller, and + * that the write to the old disk is already set up in the + * stripes array. + */ + index_where_to_add = num_stripes; + for (i = 0; i < num_stripes; i++) { + if (bbio->stripes[i].dev->devid == srcdev_devid) { + /* write to new disk, too */ + struct btrfs_bio_stripe *new = + bbio->stripes + index_where_to_add; + struct btrfs_bio_stripe *old = + bbio->stripes + i; + + new->physical = old->physical; + new->length = old->length; + new->dev = dev_replace->tgtdev; + index_where_to_add++; + max_errors++; + } + } + num_stripes = index_where_to_add; + } + *bbio_ret = bbio; bbio->num_stripes = num_stripes; bbio->max_errors = max_errors; bbio->mirror_num = mirror_num; out: + if (dev_replace_is_ongoing) + btrfs_dev_replace_unlock(dev_replace); free_extent_map(em); return ret; } -- cgit v0.10.2 From 30d9861ff9520e2a112eae71029bc9f7e915a441 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Tue, 6 Nov 2012 14:52:18 +0100 Subject: Btrfs: optionally avoid reads from device replace source drive It is desirable to be able to configure the device replace procedure to avoid reading the source drive (the one to be copied) whenever possible. This is useful when the number of read errors on this disk is high, because it would delay the copy procedure alot. Therefore there is an option to avoid reading from the source disk unless the repair procedure really needs to access it. The regular read req asks for mapping the block with mirror_num == 0, in this case the source disk is avoided whenever possible. The repair code selects the mirror_num explicitly (mirror_num != 0), this case is not changed by this commit. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 4d3bf18..e2e01a3 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4007,16 +4007,37 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) return ret; } -static int find_live_mirror(struct map_lookup *map, int first, int num, - int optimal) +static int find_live_mirror(struct btrfs_fs_info *fs_info, + struct map_lookup *map, int first, int num, + int optimal, int dev_replace_is_ongoing) { int i; - if (map->stripes[optimal].dev->bdev) - return optimal; - for (i = first; i < first + num; i++) { - if (map->stripes[i].dev->bdev) - return i; + int tolerance; + struct btrfs_device *srcdev; + + if (dev_replace_is_ongoing && + fs_info->dev_replace.cont_reading_from_srcdev_mode == + BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_AVOID) + srcdev = fs_info->dev_replace.srcdev; + else + srcdev = NULL; + + /* + * try to avoid the drive that is the source drive for a + * dev-replace procedure, only choose it if no other non-missing + * mirror is available + */ + for (tolerance = 0; tolerance < 2; tolerance++) { + if (map->stripes[optimal].dev->bdev && + (tolerance || map->stripes[optimal].dev != srcdev)) + return optimal; + for (i = first; i < first + num; i++) { + if (map->stripes[i].dev->bdev && + (tolerance || map->stripes[i].dev != srcdev)) + return i; + } } + /* we couldn't find one that doesn't fail. Just return something * and the io error handling code will clean up eventually */ @@ -4116,9 +4137,10 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, else if (mirror_num) stripe_index = mirror_num - 1; else { - stripe_index = find_live_mirror(map, 0, + stripe_index = find_live_mirror(fs_info, map, 0, map->num_stripes, - current->pid % map->num_stripes); + current->pid % map->num_stripes, + dev_replace_is_ongoing); mirror_num = stripe_index + 1; } @@ -4147,9 +4169,11 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, stripe_index += mirror_num - 1; else { int old_stripe_index = stripe_index; - stripe_index = find_live_mirror(map, stripe_index, + stripe_index = find_live_mirror(fs_info, map, + stripe_index, map->sub_stripes, stripe_index + - current->pid % map->sub_stripes); + current->pid % map->sub_stripes, + dev_replace_is_ongoing); mirror_num = stripe_index - old_stripe_index + 1; } } else { -- cgit v0.10.2 From 72d7aefccd512b66cd5543e652eae04be12085fc Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Tue, 6 Nov 2012 14:57:46 +0100 Subject: Btrfs: increase BTRFS_MAX_MIRRORS by one for dev replace This change of the define is effective in all modes, it is required and used only in the case when a device replace procedure is running. The reason is that during an active device replace procedure, the target device of the copy operation is a mirror for the filesystem data as well that can be used to read data in order to repair read errors on other disks. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 46bd7d5..91ff078 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -48,7 +48,7 @@ struct btrfs_ordered_sum; #define BTRFS_MAGIC "_BHRfS_M" -#define BTRFS_MAX_MIRRORS 2 +#define BTRFS_MAX_MIRRORS 3 #define BTRFS_MAX_LEVEL 8 -- cgit v0.10.2 From ad6d620e2a5704f6bf3a39c92a75aad962c51cb3 Mon Sep 17 00:00:00 2001 From: Stefan Behrens Date: Tue, 6 Nov 2012 15:06:47 +0100 Subject: Btrfs: allow repair code to include target disk when searching mirrors Make the target disk of a running device replace operation available for reading. This is only used as a last ressort for the defect repair procedure. And it is dependent on the location of the data block to read, because during an ongoing device replace operation, the target drive is only partially filled with the filesystem data. Signed-off-by: Stefan Behrens Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e2e01a3..32a4948 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4004,6 +4004,12 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) else ret = 1; free_extent_map(em); + + btrfs_dev_replace_lock(&fs_info->dev_replace); + if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) + ret++; + btrfs_dev_replace_unlock(&fs_info->dev_replace); + return ret; } @@ -4068,6 +4074,8 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; int dev_replace_is_ongoing = 0; int num_alloc_stripes; + int patch_the_first_stripe_for_dev_replace = 0; + u64 physical_to_patch_in_first_stripe = 0; read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, logical, *length); @@ -4084,9 +4092,6 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, map = (struct map_lookup *)em->bdev; offset = logical - em->start; - if (mirror_num > map->num_stripes) - mirror_num = 0; - stripe_nr = offset; /* * stripe_nr counts the total number of stripes we have to stride @@ -4118,6 +4123,88 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, if (!dev_replace_is_ongoing) btrfs_dev_replace_unlock(dev_replace); + if (dev_replace_is_ongoing && mirror_num == map->num_stripes + 1 && + !(rw & (REQ_WRITE | REQ_DISCARD | REQ_GET_READ_MIRRORS)) && + dev_replace->tgtdev != NULL) { + /* + * in dev-replace case, for repair case (that's the only + * case where the mirror is selected explicitly when + * calling btrfs_map_block), blocks left of the left cursor + * can also be read from the target drive. + * For REQ_GET_READ_MIRRORS, the target drive is added as + * the last one to the array of stripes. For READ, it also + * needs to be supported using the same mirror number. + * If the requested block is not left of the left cursor, + * EIO is returned. This can happen because btrfs_num_copies() + * returns one more in the dev-replace case. + */ + u64 tmp_length = *length; + struct btrfs_bio *tmp_bbio = NULL; + int tmp_num_stripes; + u64 srcdev_devid = dev_replace->srcdev->devid; + int index_srcdev = 0; + int found = 0; + u64 physical_of_found = 0; + + ret = __btrfs_map_block(fs_info, REQ_GET_READ_MIRRORS, + logical, &tmp_length, &tmp_bbio, 0); + if (ret) { + WARN_ON(tmp_bbio != NULL); + goto out; + } + + tmp_num_stripes = tmp_bbio->num_stripes; + if (mirror_num > tmp_num_stripes) { + /* + * REQ_GET_READ_MIRRORS does not contain this + * mirror, that means that the requested area + * is not left of the left cursor + */ + ret = -EIO; + kfree(tmp_bbio); + goto out; + } + + /* + * process the rest of the function using the mirror_num + * of the source drive. Therefore look it up first. + * At the end, patch the device pointer to the one of the + * target drive. + */ + for (i = 0; i < tmp_num_stripes; i++) { + if (tmp_bbio->stripes[i].dev->devid == srcdev_devid) { + /* + * In case of DUP, in order to keep it + * simple, only add the mirror with the + * lowest physical address + */ + if (found && + physical_of_found <= + tmp_bbio->stripes[i].physical) + continue; + index_srcdev = i; + found = 1; + physical_of_found = + tmp_bbio->stripes[i].physical; + } + } + + if (found) { + mirror_num = index_srcdev + 1; + patch_the_first_stripe_for_dev_replace = 1; + physical_to_patch_in_first_stripe = physical_of_found; + } else { + WARN_ON(1); + ret = -EIO; + kfree(tmp_bbio); + goto out; + } + + kfree(tmp_bbio); + } else if (mirror_num > map->num_stripes) { + mirror_num = 0; + } + num_stripes = 1; stripe_index = 0; stripe_nr_orig = stripe_nr; @@ -4188,8 +4275,12 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, BUG_ON(stripe_index >= map->num_stripes); num_alloc_stripes = num_stripes; - if (dev_replace_is_ongoing && (rw & (REQ_WRITE | REQ_DISCARD))) - num_alloc_stripes <<= 1; + if (dev_replace_is_ongoing) { + if (rw & (REQ_WRITE | REQ_DISCARD)) + num_alloc_stripes <<= 1; + if (rw & REQ_GET_READ_MIRRORS) + num_alloc_stripes++; + } bbio = kzalloc(btrfs_bio_size(num_alloc_stripes), GFP_NOFS); if (!bbio) { ret = -ENOMEM; @@ -4318,12 +4409,70 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw, } } num_stripes = index_where_to_add; + } else if (dev_replace_is_ongoing && (rw & REQ_GET_READ_MIRRORS) && + dev_replace->tgtdev != NULL) { + u64 srcdev_devid = dev_replace->srcdev->devid; + int index_srcdev = 0; + int found = 0; + u64 physical_of_found = 0; + + /* + * During the dev-replace procedure, the target drive can + * also be used to read data in case it is needed to repair + * a corrupt block elsewhere. This is possible if the + * requested area is left of the left cursor. In this area, + * the target drive is a full copy of the source drive. + */ + for (i = 0; i < num_stripes; i++) { + if (bbio->stripes[i].dev->devid == srcdev_devid) { + /* + * In case of DUP, in order to keep it + * simple, only add the mirror with the + * lowest physical address + */ + if (found && + physical_of_found <= + bbio->stripes[i].physical) + continue; + index_srcdev = i; + found = 1; + physical_of_found = bbio->stripes[i].physical; + } + } + if (found) { + u64 length = map->stripe_len; + + if (physical_of_found + length <= + dev_replace->cursor_left) { + struct btrfs_bio_stripe *tgtdev_stripe = + bbio->stripes + num_stripes; + + tgtdev_stripe->physical = physical_of_found; + tgtdev_stripe->length = + bbio->stripes[index_srcdev].length; + tgtdev_stripe->dev = dev_replace->tgtdev; + + num_stripes++; + } + } } *bbio_ret = bbio; bbio->num_stripes = num_stripes; bbio->max_errors = max_errors; bbio->mirror_num = mirror_num; + + /* + * this is the case that REQ_READ && dev_replace_is_ongoing && + * mirror_num == num_stripes + 1 && dev_replace target drive is + * available as a mirror + */ + if (patch_the_first_stripe_for_dev_replace && num_stripes > 0) { + WARN_ON(num_stripes > 1); + bbio->stripes[0].dev = dev_replace->tgtdev; + bbio->stripes[0].physical = physical_to_patch_in_first_stripe; + bbio->mirror_num = map->num_stripes + 1; + } out: if (dev_replace_is_ongoing) btrfs_dev_replace_unlock(dev_replace); -- cgit v0.10.2 From 5955a5966632d0f49cb9418ae437db604db295d9 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Thu, 25 Oct 2012 16:36:11 -0400 Subject: tilegx: remove __init from pci fixup hook Support having the PCI bus be removed at runtime and rediscovered. gregkh@linuxfoundation.org argued for removing __init rather than converting it to __devinit. Signed-off-by: Chris Metcalf diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c index 2ba6d05..94810d4 100644 --- a/arch/tile/kernel/pci_gx.c +++ b/arch/tile/kernel/pci_gx.c @@ -1047,8 +1047,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) } /* Called for each device after PCI setup is done. */ -static void __init -pcibios_fixup_final(struct pci_dev *pdev) +static void pcibios_fixup_final(struct pci_dev *pdev) { set_dma_ops(&pdev->dev, gx_pci_dma_map_ops); set_dma_offset(&pdev->dev, TILE_PCI_MEM_MAP_BASE_OFFSET); -- cgit v0.10.2 From 17a263540cebd4c615755300f34c695b15378a58 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 3 Dec 2012 08:28:36 -0500 Subject: tile/PCI: use for_each_pci_dev to simplify the code Use for_each_pci_dev to simplify the code. Signed-off-by: Wei Yongjun Signed-off-by: Chris Metcalf diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c index 7598226..aac1cd5 100644 --- a/arch/tile/kernel/pci.c +++ b/arch/tile/kernel/pci.c @@ -245,7 +245,7 @@ static void __devinit fixup_read_and_payload_sizes(void) u16 new_values; /* Scan for the smallest maximum payload size. */ - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + for_each_pci_dev(dev) { u32 devcap; int max_payload; @@ -260,7 +260,7 @@ static void __devinit fixup_read_and_payload_sizes(void) /* Now, set the max_payload_size for all devices to that value. */ new_values = (max_read_size << 12) | (smallest_max_payload << 5); - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) + for_each_pci_dev(dev) pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ, new_values); -- cgit v0.10.2 From 4bfe24ac1d9d9f06b30b2909f53ea462c72cfe1d Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 12 Dec 2012 20:24:12 -0800 Subject: x86, doc: Add a formal bootloader ID for kexec-tools Add bootloader id D for kexec-tools (it is kexec-tools, not the kexec system call, that builds the data structures, therefore it is kexec-tools which is the "bootloader" for this purpose.) Signed-off-by: H. Peter Anvin Cc: Eric W. Biederman Cc: Yinghai Lu Link: http://lkml.kernel.org/r/50C95832.5030306@zytor.com diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index 9efceff..c25a53e 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt @@ -381,6 +381,7 @@ Protocol: 2.00+ A Gujin B Qemu C Arcturus Networks uCbootloader + D kexec-tools E Extended (see ext_loader_type) F Special (0xFF = undefined) 10 Reserved -- cgit v0.10.2 From cd34ab8b16ffaa9753d85adb4fb6cd98e7e1d22a Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 12 Dec 2012 20:28:39 -0800 Subject: x86, doc: Document that bootloader ID 4 is used also by iPXE Etherboot -> gPXE -> iPXE... Signed-off-by: H. Peter Anvin Cc: Michael Brown diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt index c25a53e..9a89e01 100644 --- a/Documentation/x86/boot.txt +++ b/Documentation/x86/boot.txt @@ -373,7 +373,7 @@ Protocol: 2.00+ 1 Loadlin 2 bootsect-loader (0x20, all other values reserved) 3 Syslinux - 4 Etherboot/gPXE + 4 Etherboot/gPXE/iPXE 5 ELILO 7 GRUB 8 U-Boot -- cgit v0.10.2 From f259613a1e4b44a0cf85a5dafd931be96ee7c9e5 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 13 Dec 2012 15:14:36 +1100 Subject: NFS: avoid NULL dereference in nfs_destroy_server In rare circumstances, nfs_clone_server() of a v2 or v3 server can get an error between setting server->destory (to nfs_destroy_server), and calling nfs_start_lockd (which will set server->nlm_host). If this happens, nfs_clone_server will call nfs_free_server which will call nfs_destroy_server and thence nlmclnt_done(NULL). This causes the NULL to be dereferenced. So add a guard to only call nlmclnt_done() if ->nlm_host is not NULL. The other guards there are irrelevant as nlm_host can only be non-NULL if one of these flags are set - so remove those tests. (Thanks to Trond for this suggestion). This is suitable for any stable kernel since 2.6.25. Cc: stable@vger.kernel.org Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust diff --git a/fs/nfs/client.c b/fs/nfs/client.c index c285e0a..9f3c664 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -615,8 +615,7 @@ EXPORT_SYMBOL_GPL(nfs_create_rpc_client); */ static void nfs_destroy_server(struct nfs_server *server) { - if (!(server->flags & NFS_MOUNT_LOCAL_FLOCK) || - !(server->flags & NFS_MOUNT_LOCAL_FCNTL)) + if (server->nlm_host) nlmclnt_done(server->nlm_host); } -- cgit v0.10.2 From 35d78c66969fbbb51046e9f251849cf54e9ed88c Mon Sep 17 00:00:00 2001 From: kernelmail Date: Wed, 31 Oct 2012 11:59:10 +1100 Subject: md:Add place to update ->recovery_cp. In resyncing, recovery_cp only updated when resync aborted or completed. But in md drives,many place used it to judge.So add a place to update. Signed-off-by: Jianpeng Ma Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index 520056a..f970834 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7462,6 +7462,9 @@ void md_do_sync(struct md_thread *thread) wait_event(mddev->recovery_wait, atomic_read(&mddev->recovery_active) == 0); mddev->curr_resync_completed = j; + if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && + j > mddev->recovery_cp) + mddev->recovery_cp = j; set_bit(MD_CHANGE_CLEAN, &mddev->flags); sysfs_notify(&mddev->kobj, NULL, "sync_completed"); } -- cgit v0.10.2 From 54f89341e8b8da0cdac8a7b873491739de19f098 Mon Sep 17 00:00:00 2001 From: majianpeng Date: Wed, 31 Oct 2012 11:59:10 +1100 Subject: md: Update checkpoint of resync/recovery based on time. md will current only only checkpoint recovery or resync ever 1/16th of the device size. As devices get larger this can become a long time an so a lot of work that might need to be duplicated after a shutdown. So add a time-based checkpoint. Every 5 minutes limits the amount of duplicated effort to at most 5 minutes, and has almost zero impact on performance. [changelog entry re-written by NeilBrown] Signed-off-by: Jianpeng Ma Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index f970834..6aefa44 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7277,6 +7277,7 @@ EXPORT_SYMBOL_GPL(md_allow_write); #define SYNC_MARKS 10 #define SYNC_MARK_STEP (3*HZ) +#define UPDATE_FREQUENCY (5*60*HZ) void md_do_sync(struct md_thread *thread) { struct mddev *mddev = thread->mddev; @@ -7285,6 +7286,7 @@ void md_do_sync(struct md_thread *thread) window; sector_t max_sectors,j, io_sectors; unsigned long mark[SYNC_MARKS]; + unsigned long update_time; sector_t mark_cnt[SYNC_MARKS]; int last_mark,m; struct list_head *tmp; @@ -7444,6 +7446,7 @@ void md_do_sync(struct md_thread *thread) mddev->curr_resync_completed = j; sysfs_notify(&mddev->kobj, NULL, "sync_completed"); md_new_event(mddev); + update_time = jiffies; blk_start_plug(&plug); while (j < max_sectors) { @@ -7455,6 +7458,7 @@ void md_do_sync(struct md_thread *thread) ((mddev->curr_resync > mddev->curr_resync_completed && (mddev->curr_resync - mddev->curr_resync_completed) > (max_sectors >> 4)) || + time_after_eq(jiffies, update_time + UPDATE_FREQUENCY) || (j - mddev->curr_resync_completed)*2 >= mddev->resync_max - mddev->curr_resync_completed )) { @@ -7465,6 +7469,7 @@ void md_do_sync(struct md_thread *thread) if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && j > mddev->recovery_cp) mddev->recovery_cp = j; + update_time = jiffies; set_bit(MD_CHANGE_CLEAN, &mddev->flags); sysfs_notify(&mddev->kobj, NULL, "sync_completed"); } -- cgit v0.10.2 From 7056741fd9fc14a65608549a4657cf5178f05f63 Mon Sep 17 00:00:00 2001 From: Jim Kukunas Date: Thu, 8 Nov 2012 13:47:44 -0800 Subject: lib/raid6: Add AVX2 optimized recovery functions Optimize RAID6 recovery functions to take advantage of the 256-bit YMM integer instructions introduced in AVX2. The patch was tested and benchmarked before submission. However hardware is not yet released so benchmark numbers cannot be reported. Acked-by: "H. Peter Anvin" Signed-off-by: Jim Kukunas Signed-off-by: NeilBrown diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 58790bd..95477aa 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -123,9 +123,10 @@ cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTI # does binutils support specific instructions? asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1) avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1) +avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1) -KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) -KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) +KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) +KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) LDFLAGS := -m elf_$(UTS_MACHINE) diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h index 640c69c..3156347 100644 --- a/include/linux/raid/pq.h +++ b/include/linux/raid/pq.h @@ -109,6 +109,7 @@ struct raid6_recov_calls { extern const struct raid6_recov_calls raid6_recov_intx1; extern const struct raid6_recov_calls raid6_recov_ssse3; +extern const struct raid6_recov_calls raid6_recov_avx2; /* Algorithm list */ extern const struct raid6_calls * const raid6_algos[]; diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile index de06dfe..8c2e22b 100644 --- a/lib/raid6/Makefile +++ b/lib/raid6/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_RAID6_PQ) += raid6_pq.o -raid6_pq-y += algos.o recov.o recov_ssse3.o tables.o int1.o int2.o int4.o \ +raid6_pq-y += algos.o recov.o recov_ssse3.o recov_avx2.o tables.o int1.o int2.o int4.o \ int8.o int16.o int32.o altivec1.o altivec2.o altivec4.o \ altivec8.o mmx.o sse1.o sse2.o hostprogs-y += mktables diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c index 589f5f5..8b7f55c 100644 --- a/lib/raid6/algos.c +++ b/lib/raid6/algos.c @@ -72,6 +72,9 @@ EXPORT_SYMBOL_GPL(raid6_datap_recov); const struct raid6_recov_calls *const raid6_recov_algos[] = { #if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__) +#ifdef CONFIG_AS_AVX2 + &raid6_recov_avx2, +#endif &raid6_recov_ssse3, #endif &raid6_recov_intx1, diff --git a/lib/raid6/recov_avx2.c b/lib/raid6/recov_avx2.c new file mode 100644 index 0000000..43a9bab --- /dev/null +++ b/lib/raid6/recov_avx2.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2012 Intel Corporation + * Author: Jim Kukunas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__) + +#if CONFIG_AS_AVX2 + +#include +#include "x86.h" + +static int raid6_has_avx2(void) +{ + return boot_cpu_has(X86_FEATURE_AVX2) && + boot_cpu_has(X86_FEATURE_AVX); +} + +static void raid6_2data_recov_avx2(int disks, size_t bytes, int faila, + int failb, void **ptrs) +{ + u8 *p, *q, *dp, *dq; + const u8 *pbmul; /* P multiplier table for B data */ + const u8 *qmul; /* Q multiplier table (for both) */ + const u8 x0f = 0x0f; + + p = (u8 *)ptrs[disks-2]; + q = (u8 *)ptrs[disks-1]; + + /* Compute syndrome with zero for the missing data pages + Use the dead data pages as temporary storage for + delta p and delta q */ + dp = (u8 *)ptrs[faila]; + ptrs[faila] = (void *)raid6_empty_zero_page; + ptrs[disks-2] = dp; + dq = (u8 *)ptrs[failb]; + ptrs[failb] = (void *)raid6_empty_zero_page; + ptrs[disks-1] = dq; + + raid6_call.gen_syndrome(disks, bytes, ptrs); + + /* Restore pointer table */ + ptrs[faila] = dp; + ptrs[failb] = dq; + ptrs[disks-2] = p; + ptrs[disks-1] = q; + + /* Now, pick the proper data tables */ + pbmul = raid6_vgfmul[raid6_gfexi[failb-faila]]; + qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila] ^ + raid6_gfexp[failb]]]; + + kernel_fpu_begin(); + + /* ymm0 = x0f[16] */ + asm volatile("vpbroadcastb %0, %%ymm7" : : "m" (x0f)); + + while (bytes) { +#ifdef CONFIG_X86_64 + asm volatile("vmovdqa %0, %%ymm1" : : "m" (q[0])); + asm volatile("vmovdqa %0, %%ymm9" : : "m" (q[32])); + asm volatile("vmovdqa %0, %%ymm0" : : "m" (p[0])); + asm volatile("vmovdqa %0, %%ymm8" : : "m" (p[32])); + asm volatile("vpxor %0, %%ymm1, %%ymm1" : : "m" (dq[0])); + asm volatile("vpxor %0, %%ymm9, %%ymm9" : : "m" (dq[32])); + asm volatile("vpxor %0, %%ymm0, %%ymm0" : : "m" (dp[0])); + asm volatile("vpxor %0, %%ymm8, %%ymm8" : : "m" (dp[32])); + + /* + * 1 = dq[0] ^ q[0] + * 9 = dq[32] ^ q[32] + * 0 = dp[0] ^ p[0] + * 8 = dp[32] ^ p[32] + */ + + asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (qmul[0])); + asm volatile("vbroadcasti128 %0, %%ymm5" : : "m" (qmul[16])); + + asm volatile("vpsraw $4, %ymm1, %ymm3"); + asm volatile("vpsraw $4, %ymm9, %ymm12"); + asm volatile("vpand %ymm7, %ymm1, %ymm1"); + asm volatile("vpand %ymm7, %ymm9, %ymm9"); + asm volatile("vpand %ymm7, %ymm3, %ymm3"); + asm volatile("vpand %ymm7, %ymm12, %ymm12"); + asm volatile("vpshufb %ymm9, %ymm4, %ymm14"); + asm volatile("vpshufb %ymm1, %ymm4, %ymm4"); + asm volatile("vpshufb %ymm12, %ymm5, %ymm15"); + asm volatile("vpshufb %ymm3, %ymm5, %ymm5"); + asm volatile("vpxor %ymm14, %ymm15, %ymm15"); + asm volatile("vpxor %ymm4, %ymm5, %ymm5"); + + /* + * 5 = qx[0] + * 15 = qx[32] + */ + + asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (pbmul[0])); + asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (pbmul[16])); + asm volatile("vpsraw $4, %ymm0, %ymm2"); + asm volatile("vpsraw $4, %ymm8, %ymm6"); + asm volatile("vpand %ymm7, %ymm0, %ymm3"); + asm volatile("vpand %ymm7, %ymm8, %ymm14"); + asm volatile("vpand %ymm7, %ymm2, %ymm2"); + asm volatile("vpand %ymm7, %ymm6, %ymm6"); + asm volatile("vpshufb %ymm14, %ymm4, %ymm12"); + asm volatile("vpshufb %ymm3, %ymm4, %ymm4"); + asm volatile("vpshufb %ymm6, %ymm1, %ymm13"); + asm volatile("vpshufb %ymm2, %ymm1, %ymm1"); + asm volatile("vpxor %ymm4, %ymm1, %ymm1"); + asm volatile("vpxor %ymm12, %ymm13, %ymm13"); + + /* + * 1 = pbmul[px[0]] + * 13 = pbmul[px[32]] + */ + asm volatile("vpxor %ymm5, %ymm1, %ymm1"); + asm volatile("vpxor %ymm15, %ymm13, %ymm13"); + + /* + * 1 = db = DQ + * 13 = db[32] = DQ[32] + */ + asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0])); + asm volatile("vmovdqa %%ymm13,%0" : "=m" (dq[32])); + asm volatile("vpxor %ymm1, %ymm0, %ymm0"); + asm volatile("vpxor %ymm13, %ymm8, %ymm8"); + + asm volatile("vmovdqa %%ymm0, %0" : "=m" (dp[0])); + asm volatile("vmovdqa %%ymm8, %0" : "=m" (dp[32])); + + bytes -= 64; + p += 64; + q += 64; + dp += 64; + dq += 64; +#else + asm volatile("vmovdqa %0, %%ymm1" : : "m" (*q)); + asm volatile("vmovdqa %0, %%ymm0" : : "m" (*p)); + asm volatile("vpxor %0, %%ymm1, %%ymm1" : : "m" (*dq)); + asm volatile("vpxor %0, %%ymm0, %%ymm0" : : "m" (*dp)); + + /* 1 = dq ^ q; 0 = dp ^ p */ + + asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (qmul[0])); + asm volatile("vbroadcasti128 %0, %%ymm5" : : "m" (qmul[16])); + + /* + * 1 = dq ^ q + * 3 = dq ^ p >> 4 + */ + asm volatile("vpsraw $4, %ymm1, %ymm3"); + asm volatile("vpand %ymm7, %ymm1, %ymm1"); + asm volatile("vpand %ymm7, %ymm3, %ymm3"); + asm volatile("vpshufb %ymm1, %ymm4, %ymm4"); + asm volatile("vpshufb %ymm3, %ymm5, %ymm5"); + asm volatile("vpxor %ymm4, %ymm5, %ymm5"); + + /* 5 = qx */ + + asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (pbmul[0])); + asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (pbmul[16])); + + asm volatile("vpsraw $4, %ymm0, %ymm2"); + asm volatile("vpand %ymm7, %ymm0, %ymm3"); + asm volatile("vpand %ymm7, %ymm2, %ymm2"); + asm volatile("vpshufb %ymm3, %ymm4, %ymm4"); + asm volatile("vpshufb %ymm2, %ymm1, %ymm1"); + asm volatile("vpxor %ymm4, %ymm1, %ymm1"); + + /* 1 = pbmul[px] */ + asm volatile("vpxor %ymm5, %ymm1, %ymm1"); + /* 1 = db = DQ */ + asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0])); + + asm volatile("vpxor %ymm1, %ymm0, %ymm0"); + asm volatile("vmovdqa %%ymm0, %0" : "=m" (dp[0])); + + bytes -= 32; + p += 32; + q += 32; + dp += 32; + dq += 32; +#endif + } + + kernel_fpu_end(); +} + +static void raid6_datap_recov_avx2(int disks, size_t bytes, int faila, + void **ptrs) +{ + u8 *p, *q, *dq; + const u8 *qmul; /* Q multiplier table */ + const u8 x0f = 0x0f; + + p = (u8 *)ptrs[disks-2]; + q = (u8 *)ptrs[disks-1]; + + /* Compute syndrome with zero for the missing data page + Use the dead data page as temporary storage for delta q */ + dq = (u8 *)ptrs[faila]; + ptrs[faila] = (void *)raid6_empty_zero_page; + ptrs[disks-1] = dq; + + raid6_call.gen_syndrome(disks, bytes, ptrs); + + /* Restore pointer table */ + ptrs[faila] = dq; + ptrs[disks-1] = q; + + /* Now, pick the proper data tables */ + qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila]]]; + + kernel_fpu_begin(); + + asm volatile("vpbroadcastb %0, %%ymm7" : : "m" (x0f)); + + while (bytes) { +#ifdef CONFIG_X86_64 + asm volatile("vmovdqa %0, %%ymm3" : : "m" (dq[0])); + asm volatile("vmovdqa %0, %%ymm8" : : "m" (dq[32])); + asm volatile("vpxor %0, %%ymm3, %%ymm3" : : "m" (q[0])); + asm volatile("vpxor %0, %%ymm8, %%ymm8" : : "m" (q[32])); + + /* + * 3 = q[0] ^ dq[0] + * 8 = q[32] ^ dq[32] + */ + asm volatile("vbroadcasti128 %0, %%ymm0" : : "m" (qmul[0])); + asm volatile("vmovapd %ymm0, %ymm13"); + asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (qmul[16])); + asm volatile("vmovapd %ymm1, %ymm14"); + + asm volatile("vpsraw $4, %ymm3, %ymm6"); + asm volatile("vpsraw $4, %ymm8, %ymm12"); + asm volatile("vpand %ymm7, %ymm3, %ymm3"); + asm volatile("vpand %ymm7, %ymm8, %ymm8"); + asm volatile("vpand %ymm7, %ymm6, %ymm6"); + asm volatile("vpand %ymm7, %ymm12, %ymm12"); + asm volatile("vpshufb %ymm3, %ymm0, %ymm0"); + asm volatile("vpshufb %ymm8, %ymm13, %ymm13"); + asm volatile("vpshufb %ymm6, %ymm1, %ymm1"); + asm volatile("vpshufb %ymm12, %ymm14, %ymm14"); + asm volatile("vpxor %ymm0, %ymm1, %ymm1"); + asm volatile("vpxor %ymm13, %ymm14, %ymm14"); + + /* + * 1 = qmul[q[0] ^ dq[0]] + * 14 = qmul[q[32] ^ dq[32]] + */ + asm volatile("vmovdqa %0, %%ymm2" : : "m" (p[0])); + asm volatile("vmovdqa %0, %%ymm12" : : "m" (p[32])); + asm volatile("vpxor %ymm1, %ymm2, %ymm2"); + asm volatile("vpxor %ymm14, %ymm12, %ymm12"); + + /* + * 2 = p[0] ^ qmul[q[0] ^ dq[0]] + * 12 = p[32] ^ qmul[q[32] ^ dq[32]] + */ + + asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0])); + asm volatile("vmovdqa %%ymm14, %0" : "=m" (dq[32])); + asm volatile("vmovdqa %%ymm2, %0" : "=m" (p[0])); + asm volatile("vmovdqa %%ymm12,%0" : "=m" (p[32])); + + bytes -= 64; + p += 64; + q += 64; + dq += 64; +#else + asm volatile("vmovdqa %0, %%ymm3" : : "m" (dq[0])); + asm volatile("vpxor %0, %%ymm3, %%ymm3" : : "m" (q[0])); + + /* 3 = q ^ dq */ + + asm volatile("vbroadcasti128 %0, %%ymm0" : : "m" (qmul[0])); + asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (qmul[16])); + + asm volatile("vpsraw $4, %ymm3, %ymm6"); + asm volatile("vpand %ymm7, %ymm3, %ymm3"); + asm volatile("vpand %ymm7, %ymm6, %ymm6"); + asm volatile("vpshufb %ymm3, %ymm0, %ymm0"); + asm volatile("vpshufb %ymm6, %ymm1, %ymm1"); + asm volatile("vpxor %ymm0, %ymm1, %ymm1"); + + /* 1 = qmul[q ^ dq] */ + + asm volatile("vmovdqa %0, %%ymm2" : : "m" (p[0])); + asm volatile("vpxor %ymm1, %ymm2, %ymm2"); + + /* 2 = p ^ qmul[q ^ dq] */ + + asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0])); + asm volatile("vmovdqa %%ymm2, %0" : "=m" (p[0])); + + bytes -= 32; + p += 32; + q += 32; + dq += 32; +#endif + } + + kernel_fpu_end(); +} + +const struct raid6_recov_calls raid6_recov_avx2 = { + .data2 = raid6_2data_recov_avx2, + .datap = raid6_datap_recov_avx2, + .valid = raid6_has_avx2, +#ifdef CONFIG_X86_64 + .name = "avx2x2", +#else + .name = "avx2x1", +#endif + .priority = 2, +}; + +#else +#warning "your version of binutils lacks AVX2 support" +#endif + +#endif diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile index c76151d..d919c98 100644 --- a/lib/raid6/test/Makefile +++ b/lib/raid6/test/Makefile @@ -23,7 +23,7 @@ RANLIB = ranlib all: raid6.a raid6test raid6.a: int1.o int2.o int4.o int8.o int16.o int32.o mmx.o sse1.o sse2.o \ - altivec1.o altivec2.o altivec4.o altivec8.o recov.o recov_ssse3.o algos.o \ + altivec1.o altivec2.o altivec4.o altivec8.o recov.o recov_ssse3.o recov_avx2.o algos.o \ tables.o rm -f $@ $(AR) cq $@ $^ diff --git a/lib/raid6/x86.h b/lib/raid6/x86.h index d55d632..b759548 100644 --- a/lib/raid6/x86.h +++ b/lib/raid6/x86.h @@ -45,19 +45,23 @@ static inline void kernel_fpu_end(void) #define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */ #define X86_FEATURE_SSSE3 (4*32+ 9) /* Supplemental SSE-3 */ #define X86_FEATURE_AVX (4*32+28) /* Advanced Vector Extensions */ +#define X86_FEATURE_AVX2 (9*32+ 5) /* AVX2 instructions */ #define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */ /* Should work well enough on modern CPUs for testing */ static inline int boot_cpu_has(int flag) { - u32 eax = (flag & 0x20) ? 0x80000001 : 1; - u32 ecx, edx; + u32 eax, ebx, ecx, edx; + + eax = (flag & 0x100) ? 7 : + (flag & 0x20) ? 0x80000001 : 1; + ecx = 0; asm volatile("cpuid" - : "+a" (eax), "=d" (edx), "=c" (ecx) - : : "ebx"); + : "+a" (eax), "=b" (ebx), "=d" (edx), "+c" (ecx)); - return ((flag & 0x80 ? ecx : edx) >> (flag & 31)) & 1; + return ((flag & 0x100 ? ebx : + (flag & 0x80) ? ecx : edx) >> (flag & 31)) & 1; } #endif /* ndef __KERNEL__ */ -- cgit v0.10.2 From 2ba364504f2c31665007330dec23e89e44f5864e Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Oct 2012 09:46:39 +0100 Subject: UAPI: (Scripted) Disintegrate arch/blackfin/include/asm Signed-off-by: David Howells Acked-by: Arnd Bergmann Acked-by: Thomas Gleixner Acked-by: Michael Kerrisk Acked-by: Paul E. McKenney Acked-by: Dave Jones diff --git a/arch/blackfin/include/asm/Kbuild b/arch/blackfin/include/asm/Kbuild index 5a0625a..7ce56f5 100644 --- a/arch/blackfin/include/asm/Kbuild +++ b/arch/blackfin/include/asm/Kbuild @@ -1,4 +1,3 @@ -include include/asm-generic/Kbuild.asm generic-y += auxvec.h generic-y += bitsperlong.h @@ -43,7 +42,3 @@ generic-y += ucontext.h generic-y += unaligned.h generic-y += user.h generic-y += xor.h - -header-y += bfin_sport.h -header-y += cachectl.h -header-y += fixed_code.h diff --git a/arch/blackfin/include/asm/bfin_sport.h b/arch/blackfin/include/asm/bfin_sport.h index f8907ea..50b9dfd 100644 --- a/arch/blackfin/include/asm/bfin_sport.h +++ b/arch/blackfin/include/asm/bfin_sport.h @@ -5,65 +5,12 @@ * * Licensed under the GPL-2 or later. */ - #ifndef __BFIN_SPORT_H__ #define __BFIN_SPORT_H__ -/* Sport mode: it can be set to TDM, i2s or others */ -#define NORM_MODE 0x0 -#define TDM_MODE 0x1 -#define I2S_MODE 0x2 -#define NDSO_MODE 0x3 - -/* Data format, normal, a-law or u-law */ -#define NORM_FORMAT 0x0 -#define ALAW_FORMAT 0x2 -#define ULAW_FORMAT 0x3 - -/* Function driver which use sport must initialize the structure */ -struct sport_config { - /* TDM (multichannels), I2S or other mode */ - unsigned int mode:3; - unsigned int polled; /* use poll instead of irq when set */ - - /* if TDM mode is selected, channels must be set */ - int channels; /* Must be in 8 units */ - unsigned int frame_delay:4; /* Delay between frame sync pulse and first bit */ - - /* I2S mode */ - unsigned int right_first:1; /* Right stereo channel first */ - - /* In mormal mode, the following item need to be set */ - unsigned int lsb_first:1; /* order of transmit or receive data */ - unsigned int fsync:1; /* Frame sync required */ - unsigned int data_indep:1; /* data independent frame sync generated */ - unsigned int act_low:1; /* Active low TFS */ - unsigned int late_fsync:1; /* Late frame sync */ - unsigned int tckfe:1; - unsigned int sec_en:1; /* Secondary side enabled */ - - /* Choose clock source */ - unsigned int int_clk:1; /* Internal or external clock */ - - /* If external clock is used, the following fields are ignored */ - int serial_clk; - int fsync_clk; - - unsigned int data_format:2; /* Normal, u-law or a-law */ - - int word_len; /* How length of the word in bits, 3-32 bits */ - int dma_enabled; -}; - -/* Userspace interface */ -#define SPORT_IOC_MAGIC 'P' -#define SPORT_IOC_CONFIG _IOWR('P', 0x01, struct sport_config) -#define SPORT_IOC_GET_SYSTEMCLOCK _IOR('P', 0x02, unsigned long) -#define SPORT_IOC_SET_BAUDRATE _IOW('P', 0x03, unsigned long) - -#ifdef __KERNEL__ #include +#include /* * All Blackfin system MMRs are padded to 32bits even if the register @@ -122,76 +69,3 @@ struct bfin_snd_platform_data { }) #endif - -/* SPORT_TCR1 Masks */ -#define TSPEN 0x0001 /* TX enable */ -#define ITCLK 0x0002 /* Internal TX Clock Select */ -#define TDTYPE 0x000C /* TX Data Formatting Select */ -#define DTYPE_NORM 0x0000 /* Data Format Normal */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define TLSBIT 0x0010 /* TX Bit Order */ -#define ITFS 0x0200 /* Internal TX Frame Sync Select */ -#define TFSR 0x0400 /* TX Frame Sync Required Select */ -#define DITFS 0x0800 /* Data Independent TX Frame Sync Select */ -#define LTFS 0x1000 /* Low TX Frame Sync Select */ -#define LATFS 0x2000 /* Late TX Frame Sync Select */ -#define TCKFE 0x4000 /* TX Clock Falling Edge Select */ - -/* SPORT_TCR2 Masks */ -#define SLEN 0x001F /* SPORT TX Word Length (2 - 31) */ -#define DP_SLEN(x) BFIN_DEPOSIT(SLEN, x) -#define EX_SLEN(x) BFIN_EXTRACT(SLEN, x) -#define TXSE 0x0100 /* TX Secondary Enable */ -#define TSFSE 0x0200 /* TX Stereo Frame Sync Enable */ -#define TRFST 0x0400 /* TX Right-First Data Order */ - -/* SPORT_RCR1 Masks */ -#define RSPEN 0x0001 /* RX enable */ -#define IRCLK 0x0002 /* Internal RX Clock Select */ -#define RDTYPE 0x000C /* RX Data Formatting Select */ -/* DTYPE_* defined above */ -#define RLSBIT 0x0010 /* RX Bit Order */ -#define IRFS 0x0200 /* Internal RX Frame Sync Select */ -#define RFSR 0x0400 /* RX Frame Sync Required Select */ -#define LRFS 0x1000 /* Low RX Frame Sync Select */ -#define LARFS 0x2000 /* Late RX Frame Sync Select */ -#define RCKFE 0x4000 /* RX Clock Falling Edge Select */ - -/* SPORT_RCR2 Masks */ -/* SLEN defined above */ -#define RXSE 0x0100 /* RX Secondary Enable */ -#define RSFSE 0x0200 /* RX Stereo Frame Sync Enable */ -#define RRFST 0x0400 /* Right-First Data Order */ - -/* SPORT_STAT Masks */ -#define RXNE 0x0001 /* RX FIFO Not Empty Status */ -#define RUVF 0x0002 /* RX Underflow Status */ -#define ROVF 0x0004 /* RX Overflow Status */ -#define TXF 0x0008 /* TX FIFO Full Status */ -#define TUVF 0x0010 /* TX Underflow Status */ -#define TOVF 0x0020 /* TX Overflow Status */ -#define TXHRE 0x0040 /* TX Hold Register Empty */ - -/* SPORT_MCMC1 Masks */ -#define SP_WOFF 0x03FF /* Multichannel Window Offset Field */ -#define DP_SP_WOFF(x) BFIN_DEPOSIT(SP_WOFF, x) -#define EX_SP_WOFF(x) BFIN_EXTRACT(SP_WOFF, x) -#define SP_WSIZE 0xF000 /* Multichannel Window Size Field */ -#define DP_SP_WSIZE(x) BFIN_DEPOSIT(SP_WSIZE, x) -#define EX_SP_WSIZE(x) BFIN_EXTRACT(SP_WSIZE, x) - -/* SPORT_MCMC2 Masks */ -#define MCCRM 0x0003 /* Multichannel Clock Recovery Mode */ -#define REC_BYPASS 0x0000 /* Bypass Mode (No Clock Recovery) */ -#define REC_2FROM4 0x0002 /* Recover 2 MHz Clock from 4 MHz Clock */ -#define REC_8FROM16 0x0003 /* Recover 8 MHz Clock from 16 MHz Clock */ -#define MCDTXPE 0x0004 /* Multichannel DMA Transmit Packing */ -#define MCDRXPE 0x0008 /* Multichannel DMA Receive Packing */ -#define MCMEN 0x0010 /* Multichannel Frame Mode Enable */ -#define FSDR 0x0080 /* Multichannel Frame Sync to Data Relationship */ -#define MFD 0xF000 /* Multichannel Frame Delay */ -#define DP_MFD(x) BFIN_DEPOSIT(MFD, x) -#define EX_MFD(x) BFIN_EXTRACT(MFD, x) - -#endif diff --git a/arch/blackfin/include/asm/byteorder.h b/arch/blackfin/include/asm/byteorder.h deleted file mode 100644 index 9558416..0000000 --- a/arch/blackfin/include/asm/byteorder.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/blackfin/include/asm/cachectl.h b/arch/blackfin/include/asm/cachectl.h deleted file mode 100644 index 03255df..0000000 --- a/arch/blackfin/include/asm/cachectl.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * based on the mips/cachectl.h - * - * Copyright 2010 Analog Devices Inc. - * Copyright (C) 1994, 1995, 1996 by Ralf Baechle - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _ASM_CACHECTL -#define _ASM_CACHECTL - -/* - * Options for cacheflush system call - */ -#define ICACHE (1<<0) /* flush instruction cache */ -#define DCACHE (1<<1) /* writeback and flush data cache */ -#define BCACHE (ICACHE|DCACHE) /* flush both caches */ - -#endif /* _ASM_CACHECTL */ diff --git a/arch/blackfin/include/asm/fcntl.h b/arch/blackfin/include/asm/fcntl.h deleted file mode 100644 index 251c911..0000000 --- a/arch/blackfin/include/asm/fcntl.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2004-2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _BFIN_FCNTL_H -#define _BFIN_FCNTL_H - -#define O_DIRECTORY 040000 /* must be a directory */ -#define O_NOFOLLOW 0100000 /* don't follow links */ -#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ -#define O_LARGEFILE 0400000 - -#include - -#endif diff --git a/arch/blackfin/include/asm/fixed_code.h b/arch/blackfin/include/asm/fixed_code.h index 5395088..bc330f0 100644 --- a/arch/blackfin/include/asm/fixed_code.h +++ b/arch/blackfin/include/asm/fixed_code.h @@ -6,11 +6,11 @@ * * Licensed under the GPL-2 or later. */ - #ifndef __BFIN_ASM_FIXED_CODE_H__ #define __BFIN_ASM_FIXED_CODE_H__ -#ifdef __KERNEL__ +#include + #ifndef __ASSEMBLY__ #include #include @@ -28,29 +28,3 @@ extern void safe_user_instruction(void); extern void sigreturn_stub(void); #endif #endif - -#ifndef CONFIG_PHY_RAM_BASE_ADDRESS -#define CONFIG_PHY_RAM_BASE_ADDRESS 0x0 -#endif - -#define FIXED_CODE_START (CONFIG_PHY_RAM_BASE_ADDRESS + 0x400) - -#define SIGRETURN_STUB (CONFIG_PHY_RAM_BASE_ADDRESS + 0x400) - -#define ATOMIC_SEQS_START (CONFIG_PHY_RAM_BASE_ADDRESS + 0x410) - -#define ATOMIC_XCHG32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x410) -#define ATOMIC_CAS32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x420) -#define ATOMIC_ADD32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x430) -#define ATOMIC_SUB32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x440) -#define ATOMIC_IOR32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x450) -#define ATOMIC_AND32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x460) -#define ATOMIC_XOR32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x470) - -#define ATOMIC_SEQS_END (CONFIG_PHY_RAM_BASE_ADDRESS + 0x480) - -#define SAFE_USER_INSTRUCTION (CONFIG_PHY_RAM_BASE_ADDRESS + 0x480) - -#define FIXED_CODE_END (CONFIG_PHY_RAM_BASE_ADDRESS + 0x490) - -#endif diff --git a/arch/blackfin/include/asm/ioctls.h b/arch/blackfin/include/asm/ioctls.h deleted file mode 100644 index eca8d75..0000000 --- a/arch/blackfin/include/asm/ioctls.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ARCH_BFIN_IOCTLS_H__ -#define __ARCH_BFIN_IOCTLS_H__ - -#define FIOQSIZE 0x545E -#include - -#endif diff --git a/arch/blackfin/include/asm/kvm_para.h b/arch/blackfin/include/asm/kvm_para.h deleted file mode 100644 index 14fab8f..0000000 --- a/arch/blackfin/include/asm/kvm_para.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/blackfin/include/asm/poll.h b/arch/blackfin/include/asm/poll.h deleted file mode 100644 index 072d896..0000000 --- a/arch/blackfin/include/asm/poll.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2004-2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - * - */ - -#ifndef __BFIN_POLL_H -#define __BFIN_POLL_H - -#define POLLWRNORM 4 /* POLLOUT */ -#define POLLWRBAND 256 - -#include - -#endif diff --git a/arch/blackfin/include/asm/posix_types.h b/arch/blackfin/include/asm/posix_types.h deleted file mode 100644 index 1bd3436..0000000 --- a/arch/blackfin/include/asm/posix_types.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2004-2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef __ARCH_BFIN_POSIX_TYPES_H -#define __ARCH_BFIN_POSIX_TYPES_H - -typedef unsigned short __kernel_mode_t; -#define __kernel_mode_t __kernel_mode_t - -typedef unsigned int __kernel_ipc_pid_t; -#define __kernel_ipc_pid_t __kernel_ipc_pid_t - -typedef unsigned long __kernel_size_t; -typedef long __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -#define __kernel_size_t __kernel_size_t - -typedef unsigned short __kernel_old_uid_t; -typedef unsigned short __kernel_old_gid_t; -#define __kernel_old_uid_t __kernel_old_uid_t - -typedef unsigned short __kernel_old_dev_t; -#define __kernel_old_dev_t __kernel_old_dev_t - -#include - -#endif diff --git a/arch/blackfin/include/asm/ptrace.h b/arch/blackfin/include/asm/ptrace.h index 10d8641..14ea933 100644 --- a/arch/blackfin/include/asm/ptrace.h +++ b/arch/blackfin/include/asm/ptrace.h @@ -3,102 +3,13 @@ * * Licensed under the GPL-2 or later. */ - #ifndef _BFIN_PTRACE_H #define _BFIN_PTRACE_H -/* - * GCC defines register number like this: - * ----------------------------- - * 0 - 7 are data registers R0-R7 - * 8 - 15 are address registers P0-P7 - * 16 - 31 dsp registers I/B/L0 -- I/B/L3 & M0--M3 - * 32 - 33 A registers A0 & A1 - * 34 - status register - * ----------------------------- - * - * We follows above, except: - * 32-33 --- Low 32-bit of A0&1 - * 34-35 --- High 8-bit of A0&1 - */ +#include #ifndef __ASSEMBLY__ -struct task_struct; - -/* this struct defines the way the registers are stored on the - stack during a system call. */ - -struct pt_regs { - long orig_pc; - long ipend; - long seqstat; - long rete; - long retn; - long retx; - long pc; /* PC == RETI */ - long rets; - long reserved; /* Used as scratch during system calls */ - long astat; - long lb1; - long lb0; - long lt1; - long lt0; - long lc1; - long lc0; - long a1w; - long a1x; - long a0w; - long a0x; - long b3; - long b2; - long b1; - long b0; - long l3; - long l2; - long l1; - long l0; - long m3; - long m2; - long m1; - long m0; - long i3; - long i2; - long i1; - long i0; - long usp; - long fp; - long p5; - long p4; - long p3; - long p2; - long p1; - long p0; - long r7; - long r6; - long r5; - long r4; - long r3; - long r2; - long r1; - long r0; - long orig_r0; - long orig_p0; - long syscfg; -}; - -/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ -#define PTRACE_GETREGS 12 -#define PTRACE_SETREGS 13 /* ptrace signal */ - -#define PTRACE_GETFDPIC 31 /* get the ELF fdpic loadmap address */ -#define PTRACE_GETFDPIC_EXEC 0 /* [addr] request the executable loadmap */ -#define PTRACE_GETFDPIC_INTERP 1 /* [addr] request the interpreter loadmap */ - -#define PS_S (0x0002) - -#ifdef __KERNEL__ - /* user_mode returns true if only one bit is set in IPEND, other than the master interrupt enable. */ #define user_mode(regs) (!(((regs)->ipend & ~0x10) & (((regs)->ipend & ~0x10) - 1))) @@ -126,75 +37,5 @@ extern int is_user_addr_valid(struct task_struct *child, #include -#endif /* __KERNEL__ */ - #endif /* __ASSEMBLY__ */ - -/* - * Offsets used by 'ptrace' system call interface. - */ - -#define PT_R0 204 -#define PT_R1 200 -#define PT_R2 196 -#define PT_R3 192 -#define PT_R4 188 -#define PT_R5 184 -#define PT_R6 180 -#define PT_R7 176 -#define PT_P0 172 -#define PT_P1 168 -#define PT_P2 164 -#define PT_P3 160 -#define PT_P4 156 -#define PT_P5 152 -#define PT_FP 148 -#define PT_USP 144 -#define PT_I0 140 -#define PT_I1 136 -#define PT_I2 132 -#define PT_I3 128 -#define PT_M0 124 -#define PT_M1 120 -#define PT_M2 116 -#define PT_M3 112 -#define PT_L0 108 -#define PT_L1 104 -#define PT_L2 100 -#define PT_L3 96 -#define PT_B0 92 -#define PT_B1 88 -#define PT_B2 84 -#define PT_B3 80 -#define PT_A0X 76 -#define PT_A0W 72 -#define PT_A1X 68 -#define PT_A1W 64 -#define PT_LC0 60 -#define PT_LC1 56 -#define PT_LT0 52 -#define PT_LT1 48 -#define PT_LB0 44 -#define PT_LB1 40 -#define PT_ASTAT 36 -#define PT_RESERVED 32 -#define PT_RETS 28 -#define PT_PC 24 -#define PT_RETX 20 -#define PT_RETN 16 -#define PT_RETE 12 -#define PT_SEQSTAT 8 -#define PT_IPEND 4 - -#define PT_ORIG_R0 208 -#define PT_ORIG_P0 212 -#define PT_SYSCFG 216 -#define PT_TEXT_ADDR 220 -#define PT_TEXT_END_ADDR 224 -#define PT_DATA_ADDR 228 -#define PT_FDPIC_EXEC 232 -#define PT_FDPIC_INTERP 236 - -#define PT_LAST_PSEUDO PT_FDPIC_INTERP - #endif /* _BFIN_PTRACE_H */ diff --git a/arch/blackfin/include/asm/sigcontext.h b/arch/blackfin/include/asm/sigcontext.h deleted file mode 100644 index 906bdc1..0000000 --- a/arch/blackfin/include/asm/sigcontext.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2004-2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _ASM_BLACKFIN_SIGCONTEXT_H -#define _ASM_BLACKFIN_SIGCONTEXT_H - -/* Add new entries at the end of the structure only. */ -struct sigcontext { - unsigned long sc_r0; - unsigned long sc_r1; - unsigned long sc_r2; - unsigned long sc_r3; - unsigned long sc_r4; - unsigned long sc_r5; - unsigned long sc_r6; - unsigned long sc_r7; - unsigned long sc_p0; - unsigned long sc_p1; - unsigned long sc_p2; - unsigned long sc_p3; - unsigned long sc_p4; - unsigned long sc_p5; - unsigned long sc_usp; - unsigned long sc_a0w; - unsigned long sc_a1w; - unsigned long sc_a0x; - unsigned long sc_a1x; - unsigned long sc_astat; - unsigned long sc_rets; - unsigned long sc_pc; - unsigned long sc_retx; - unsigned long sc_fp; - unsigned long sc_i0; - unsigned long sc_i1; - unsigned long sc_i2; - unsigned long sc_i3; - unsigned long sc_m0; - unsigned long sc_m1; - unsigned long sc_m2; - unsigned long sc_m3; - unsigned long sc_l0; - unsigned long sc_l1; - unsigned long sc_l2; - unsigned long sc_l3; - unsigned long sc_b0; - unsigned long sc_b1; - unsigned long sc_b2; - unsigned long sc_b3; - unsigned long sc_lc0; - unsigned long sc_lc1; - unsigned long sc_lt0; - unsigned long sc_lt1; - unsigned long sc_lb0; - unsigned long sc_lb1; - unsigned long sc_seqstat; -}; - -#endif diff --git a/arch/blackfin/include/asm/siginfo.h b/arch/blackfin/include/asm/siginfo.h deleted file mode 100644 index 3e81306..0000000 --- a/arch/blackfin/include/asm/siginfo.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2004-2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _BFIN_SIGINFO_H -#define _BFIN_SIGINFO_H - -#include -#include - -#define UID16_SIGINFO_COMPAT_NEEDED - -#define si_uid16 _sifields._kill._uid - -#define ILL_ILLPARAOP (__SI_FAULT|2) /* illegal opcode combine ********** */ -#define ILL_ILLEXCPT (__SI_FAULT|4) /* unrecoverable exception ********** */ -#define ILL_CPLB_VI (__SI_FAULT|9) /* D/I CPLB protect violation ******** */ -#define ILL_CPLB_MISS (__SI_FAULT|10) /* D/I CPLB miss ******** */ -#define ILL_CPLB_MULHIT (__SI_FAULT|11) /* D/I CPLB multiple hit ******** */ - -/* - * SIGBUS si_codes - */ -#define BUS_OPFETCH (__SI_FAULT|4) /* error from instruction fetch ******** */ - -/* - * SIGTRAP si_codes - */ -#define TRAP_STEP (__SI_FAULT|1) /* single-step breakpoint************* */ -#define TRAP_TRACEFLOW (__SI_FAULT|2) /* trace buffer overflow ************* */ -#define TRAP_WATCHPT (__SI_FAULT|3) /* watchpoint match ************* */ -#define TRAP_ILLTRAP (__SI_FAULT|4) /* illegal trap ************* */ - -/* - * SIGSEGV si_codes - */ -#define SEGV_STACKFLOW (__SI_FAULT|3) /* stack overflow */ - -#endif diff --git a/arch/blackfin/include/asm/signal.h b/arch/blackfin/include/asm/signal.h deleted file mode 100644 index 77a3bf3..0000000 --- a/arch/blackfin/include/asm/signal.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _BLACKFIN_SIGNAL_H -#define _BLACKFIN_SIGNAL_H - -#define SA_RESTORER 0x04000000 -#include - -#endif diff --git a/arch/blackfin/include/asm/stat.h b/arch/blackfin/include/asm/stat.h deleted file mode 100644 index 2e27665..0000000 --- a/arch/blackfin/include/asm/stat.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2004-2006 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#ifndef _BFIN_STAT_H -#define _BFIN_STAT_H - -struct stat { - unsigned short st_dev; - unsigned short __pad1; - unsigned long st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - unsigned short st_rdev; - unsigned short __pad2; - unsigned long st_size; - unsigned long st_blksize; - unsigned long st_blocks; - unsigned long st_atime; - unsigned long __unused1; - unsigned long st_mtime; - unsigned long __unused2; - unsigned long st_ctime; - unsigned long __unused3; - unsigned long __unused4; - unsigned long __unused5; -}; - -/* This matches struct stat64 in glibc2.1, hence the absolutely - * insane amounts of padding around dev_t's. - */ -struct stat64 { - unsigned long long st_dev; - unsigned char __pad1[4]; - -#define STAT64_HAS_BROKEN_ST_INO 1 - unsigned long __st_ino; - - unsigned int st_mode; - unsigned int st_nlink; - - unsigned long st_uid; - unsigned long st_gid; - - unsigned long long st_rdev; - unsigned char __pad2[4]; - - long long st_size; - unsigned long st_blksize; - - long long st_blocks; /* Number 512-byte blocks allocated. */ - - unsigned long st_atime; - unsigned long st_atime_nsec; - - unsigned long st_mtime; - unsigned long st_mtime_nsec; - - unsigned long st_ctime; - unsigned long st_ctime_nsec; - - unsigned long long st_ino; -}; - -#endif /* _BFIN_STAT_H */ diff --git a/arch/blackfin/include/asm/swab.h b/arch/blackfin/include/asm/swab.h deleted file mode 100644 index 89de650..0000000 --- a/arch/blackfin/include/asm/swab.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#ifndef _BLACKFIN_SWAB_H -#define _BLACKFIN_SWAB_H - -#include -#include - -#ifdef __GNUC__ - -static __inline__ __attribute_const__ __u32 __arch_swahb32(__u32 xx) -{ - __u32 tmp; - __asm__("%1 = %0 >> 8 (V);\n\t" - "%0 = %0 << 8 (V);\n\t" - "%0 = %0 | %1;\n\t" - : "+d"(xx), "=&d"(tmp)); - return xx; -} -#define __arch_swahb32 __arch_swahb32 - -static __inline__ __attribute_const__ __u32 __arch_swahw32(__u32 xx) -{ - __u32 rv; - __asm__("%0 = PACK(%1.L, %1.H);\n\t": "=d"(rv): "d"(xx)); - return rv; -} -#define __arch_swahw32 __arch_swahw32 - -static __inline__ __attribute_const__ __u32 __arch_swab32(__u32 xx) -{ - return __arch_swahb32(__arch_swahw32(xx)); -} -#define __arch_swab32 __arch_swab32 - -static __inline__ __attribute_const__ __u16 __arch_swab16(__u16 xx) -{ - __u32 xw = xx; - __asm__("%0 <<= 8;\n %0.L = %0.L + %0.H (NS);\n": "+d"(xw)); - return (__u16)xw; -} -#define __arch_swab16 __arch_swab16 - -#endif /* __GNUC__ */ - -#endif /* _BLACKFIN_SWAB_H */ diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h index 5b2a074..a5aa9bd 100644 --- a/arch/blackfin/include/asm/unistd.h +++ b/arch/blackfin/include/asm/unistd.h @@ -3,437 +3,11 @@ * * Licensed under the GPL-2 or later. */ - #ifndef __ASM_BFIN_UNISTD_H #define __ASM_BFIN_UNISTD_H -/* - * This file contains the system call numbers. - */ -#define __NR_restart_syscall 0 -#define __NR_exit 1 - /* 2 __NR_fork not supported on nommu */ -#define __NR_read 3 -#define __NR_write 4 -#define __NR_open 5 -#define __NR_close 6 - /* 7 __NR_waitpid obsolete */ -#define __NR_creat 8 -#define __NR_link 9 -#define __NR_unlink 10 -#define __NR_execve 11 -#define __NR_chdir 12 -#define __NR_time 13 -#define __NR_mknod 14 -#define __NR_chmod 15 -#define __NR_chown 16 - /* 17 __NR_break obsolete */ - /* 18 __NR_oldstat obsolete */ -#define __NR_lseek 19 -#define __NR_getpid 20 -#define __NR_mount 21 - /* 22 __NR_umount obsolete */ -#define __NR_setuid 23 -#define __NR_getuid 24 -#define __NR_stime 25 -#define __NR_ptrace 26 -#define __NR_alarm 27 - /* 28 __NR_oldfstat obsolete */ -#define __NR_pause 29 - /* 30 __NR_utime obsolete */ - /* 31 __NR_stty obsolete */ - /* 32 __NR_gtty obsolete */ -#define __NR_access 33 -#define __NR_nice 34 - /* 35 __NR_ftime obsolete */ -#define __NR_sync 36 -#define __NR_kill 37 -#define __NR_rename 38 -#define __NR_mkdir 39 -#define __NR_rmdir 40 -#define __NR_dup 41 -#define __NR_pipe 42 -#define __NR_times 43 - /* 44 __NR_prof obsolete */ -#define __NR_brk 45 -#define __NR_setgid 46 -#define __NR_getgid 47 - /* 48 __NR_signal obsolete */ -#define __NR_geteuid 49 -#define __NR_getegid 50 -#define __NR_acct 51 -#define __NR_umount2 52 - /* 53 __NR_lock obsolete */ -#define __NR_ioctl 54 -#define __NR_fcntl 55 - /* 56 __NR_mpx obsolete */ -#define __NR_setpgid 57 - /* 58 __NR_ulimit obsolete */ - /* 59 __NR_oldolduname obsolete */ -#define __NR_umask 60 -#define __NR_chroot 61 -#define __NR_ustat 62 -#define __NR_dup2 63 -#define __NR_getppid 64 -#define __NR_getpgrp 65 -#define __NR_setsid 66 - /* 67 __NR_sigaction obsolete */ -#define __NR_sgetmask 68 -#define __NR_ssetmask 69 -#define __NR_setreuid 70 -#define __NR_setregid 71 - /* 72 __NR_sigsuspend obsolete */ - /* 73 __NR_sigpending obsolete */ -#define __NR_sethostname 74 -#define __NR_setrlimit 75 - /* 76 __NR_old_getrlimit obsolete */ -#define __NR_getrusage 77 -#define __NR_gettimeofday 78 -#define __NR_settimeofday 79 -#define __NR_getgroups 80 -#define __NR_setgroups 81 - /* 82 __NR_select obsolete */ -#define __NR_symlink 83 - /* 84 __NR_oldlstat obsolete */ -#define __NR_readlink 85 - /* 86 __NR_uselib obsolete */ - /* 87 __NR_swapon obsolete */ -#define __NR_reboot 88 - /* 89 __NR_readdir obsolete */ - /* 90 __NR_mmap obsolete */ -#define __NR_munmap 91 -#define __NR_truncate 92 -#define __NR_ftruncate 93 -#define __NR_fchmod 94 -#define __NR_fchown 95 -#define __NR_getpriority 96 -#define __NR_setpriority 97 - /* 98 __NR_profil obsolete */ -#define __NR_statfs 99 -#define __NR_fstatfs 100 - /* 101 __NR_ioperm */ - /* 102 __NR_socketcall obsolete */ -#define __NR_syslog 103 -#define __NR_setitimer 104 -#define __NR_getitimer 105 -#define __NR_stat 106 -#define __NR_lstat 107 -#define __NR_fstat 108 - /* 109 __NR_olduname obsolete */ - /* 110 __NR_iopl obsolete */ -#define __NR_vhangup 111 - /* 112 __NR_idle obsolete */ - /* 113 __NR_vm86old */ -#define __NR_wait4 114 - /* 115 __NR_swapoff obsolete */ -#define __NR_sysinfo 116 - /* 117 __NR_ipc oboslete */ -#define __NR_fsync 118 - /* 119 __NR_sigreturn obsolete */ -#define __NR_clone 120 -#define __NR_setdomainname 121 -#define __NR_uname 122 - /* 123 __NR_modify_ldt obsolete */ -#define __NR_adjtimex 124 -#define __NR_mprotect 125 - /* 126 __NR_sigprocmask obsolete */ - /* 127 __NR_create_module obsolete */ -#define __NR_init_module 128 -#define __NR_delete_module 129 - /* 130 __NR_get_kernel_syms obsolete */ -#define __NR_quotactl 131 -#define __NR_getpgid 132 -#define __NR_fchdir 133 -#define __NR_bdflush 134 - /* 135 was sysfs */ -#define __NR_personality 136 - /* 137 __NR_afs_syscall */ -#define __NR_setfsuid 138 -#define __NR_setfsgid 139 -#define __NR__llseek 140 -#define __NR_getdents 141 - /* 142 __NR__newselect obsolete */ -#define __NR_flock 143 - /* 144 __NR_msync obsolete */ -#define __NR_readv 145 -#define __NR_writev 146 -#define __NR_getsid 147 -#define __NR_fdatasync 148 -#define __NR__sysctl 149 - /* 150 __NR_mlock */ - /* 151 __NR_munlock */ - /* 152 __NR_mlockall */ - /* 153 __NR_munlockall */ -#define __NR_sched_setparam 154 -#define __NR_sched_getparam 155 -#define __NR_sched_setscheduler 156 -#define __NR_sched_getscheduler 157 -#define __NR_sched_yield 158 -#define __NR_sched_get_priority_max 159 -#define __NR_sched_get_priority_min 160 -#define __NR_sched_rr_get_interval 161 -#define __NR_nanosleep 162 -#define __NR_mremap 163 -#define __NR_setresuid 164 -#define __NR_getresuid 165 - /* 166 __NR_vm86 */ - /* 167 __NR_query_module */ - /* 168 __NR_poll */ -#define __NR_nfsservctl 169 -#define __NR_setresgid 170 -#define __NR_getresgid 171 -#define __NR_prctl 172 -#define __NR_rt_sigreturn 173 -#define __NR_rt_sigaction 174 -#define __NR_rt_sigprocmask 175 -#define __NR_rt_sigpending 176 -#define __NR_rt_sigtimedwait 177 -#define __NR_rt_sigqueueinfo 178 -#define __NR_rt_sigsuspend 179 -#define __NR_pread 180 -#define __NR_pwrite 181 -#define __NR_lchown 182 -#define __NR_getcwd 183 -#define __NR_capget 184 -#define __NR_capset 185 -#define __NR_sigaltstack 186 -#define __NR_sendfile 187 - /* 188 __NR_getpmsg */ - /* 189 __NR_putpmsg */ -#define __NR_vfork 190 -#define __NR_getrlimit 191 -#define __NR_mmap2 192 -#define __NR_truncate64 193 -#define __NR_ftruncate64 194 -#define __NR_stat64 195 -#define __NR_lstat64 196 -#define __NR_fstat64 197 -#define __NR_chown32 198 -#define __NR_getuid32 199 -#define __NR_getgid32 200 -#define __NR_geteuid32 201 -#define __NR_getegid32 202 -#define __NR_setreuid32 203 -#define __NR_setregid32 204 -#define __NR_getgroups32 205 -#define __NR_setgroups32 206 -#define __NR_fchown32 207 -#define __NR_setresuid32 208 -#define __NR_getresuid32 209 -#define __NR_setresgid32 210 -#define __NR_getresgid32 211 -#define __NR_lchown32 212 -#define __NR_setuid32 213 -#define __NR_setgid32 214 -#define __NR_setfsuid32 215 -#define __NR_setfsgid32 216 -#define __NR_pivot_root 217 - /* 218 __NR_mincore */ - /* 219 __NR_madvise */ -#define __NR_getdents64 220 -#define __NR_fcntl64 221 - /* 222 reserved for TUX */ - /* 223 reserved for TUX */ -#define __NR_gettid 224 -#define __NR_readahead 225 -#define __NR_setxattr 226 -#define __NR_lsetxattr 227 -#define __NR_fsetxattr 228 -#define __NR_getxattr 229 -#define __NR_lgetxattr 230 -#define __NR_fgetxattr 231 -#define __NR_listxattr 232 -#define __NR_llistxattr 233 -#define __NR_flistxattr 234 -#define __NR_removexattr 235 -#define __NR_lremovexattr 236 -#define __NR_fremovexattr 237 -#define __NR_tkill 238 -#define __NR_sendfile64 239 -#define __NR_futex 240 -#define __NR_sched_setaffinity 241 -#define __NR_sched_getaffinity 242 - /* 243 __NR_set_thread_area */ - /* 244 __NR_get_thread_area */ -#define __NR_io_setup 245 -#define __NR_io_destroy 246 -#define __NR_io_getevents 247 -#define __NR_io_submit 248 -#define __NR_io_cancel 249 - /* 250 __NR_alloc_hugepages */ - /* 251 __NR_free_hugepages */ -#define __NR_exit_group 252 -#define __NR_lookup_dcookie 253 -#define __NR_bfin_spinlock 254 - -#define __NR_epoll_create 255 -#define __NR_epoll_ctl 256 -#define __NR_epoll_wait 257 - /* 258 __NR_remap_file_pages */ -#define __NR_set_tid_address 259 -#define __NR_timer_create 260 -#define __NR_timer_settime 261 -#define __NR_timer_gettime 262 -#define __NR_timer_getoverrun 263 -#define __NR_timer_delete 264 -#define __NR_clock_settime 265 -#define __NR_clock_gettime 266 -#define __NR_clock_getres 267 -#define __NR_clock_nanosleep 268 -#define __NR_statfs64 269 -#define __NR_fstatfs64 270 -#define __NR_tgkill 271 -#define __NR_utimes 272 -#define __NR_fadvise64_64 273 - /* 274 __NR_vserver */ - /* 275 __NR_mbind */ - /* 276 __NR_get_mempolicy */ - /* 277 __NR_set_mempolicy */ -#define __NR_mq_open 278 -#define __NR_mq_unlink 279 -#define __NR_mq_timedsend 280 -#define __NR_mq_timedreceive 281 -#define __NR_mq_notify 282 -#define __NR_mq_getsetattr 283 -#define __NR_kexec_load 284 -#define __NR_waitid 285 -#define __NR_add_key 286 -#define __NR_request_key 287 -#define __NR_keyctl 288 -#define __NR_ioprio_set 289 -#define __NR_ioprio_get 290 -#define __NR_inotify_init 291 -#define __NR_inotify_add_watch 292 -#define __NR_inotify_rm_watch 293 - /* 294 __NR_migrate_pages */ -#define __NR_openat 295 -#define __NR_mkdirat 296 -#define __NR_mknodat 297 -#define __NR_fchownat 298 -#define __NR_futimesat 299 -#define __NR_fstatat64 300 -#define __NR_unlinkat 301 -#define __NR_renameat 302 -#define __NR_linkat 303 -#define __NR_symlinkat 304 -#define __NR_readlinkat 305 -#define __NR_fchmodat 306 -#define __NR_faccessat 307 -#define __NR_pselect6 308 -#define __NR_ppoll 309 -#define __NR_unshare 310 - -/* Blackfin private syscalls */ -#define __NR_sram_alloc 311 -#define __NR_sram_free 312 -#define __NR_dma_memcpy 313 - -/* socket syscalls */ -#define __NR_accept 314 -#define __NR_bind 315 -#define __NR_connect 316 -#define __NR_getpeername 317 -#define __NR_getsockname 318 -#define __NR_getsockopt 319 -#define __NR_listen 320 -#define __NR_recv 321 -#define __NR_recvfrom 322 -#define __NR_recvmsg 323 -#define __NR_send 324 -#define __NR_sendmsg 325 -#define __NR_sendto 326 -#define __NR_setsockopt 327 -#define __NR_shutdown 328 -#define __NR_socket 329 -#define __NR_socketpair 330 - -/* sysv ipc syscalls */ -#define __NR_semctl 331 -#define __NR_semget 332 -#define __NR_semop 333 -#define __NR_msgctl 334 -#define __NR_msgget 335 -#define __NR_msgrcv 336 -#define __NR_msgsnd 337 -#define __NR_shmat 338 -#define __NR_shmctl 339 -#define __NR_shmdt 340 -#define __NR_shmget 341 -#define __NR_splice 342 -#define __NR_sync_file_range 343 -#define __NR_tee 344 -#define __NR_vmsplice 345 +#include -#define __NR_epoll_pwait 346 -#define __NR_utimensat 347 -#define __NR_signalfd 348 -#define __NR_timerfd_create 349 -#define __NR_eventfd 350 -#define __NR_pread64 351 -#define __NR_pwrite64 352 -#define __NR_fadvise64 353 -#define __NR_set_robust_list 354 -#define __NR_get_robust_list 355 -#define __NR_fallocate 356 -#define __NR_semtimedop 357 -#define __NR_timerfd_settime 358 -#define __NR_timerfd_gettime 359 -#define __NR_signalfd4 360 -#define __NR_eventfd2 361 -#define __NR_epoll_create1 362 -#define __NR_dup3 363 -#define __NR_pipe2 364 -#define __NR_inotify_init1 365 -#define __NR_preadv 366 -#define __NR_pwritev 367 -#define __NR_rt_tgsigqueueinfo 368 -#define __NR_perf_event_open 369 -#define __NR_recvmmsg 370 -#define __NR_fanotify_init 371 -#define __NR_fanotify_mark 372 -#define __NR_prlimit64 373 -#define __NR_cacheflush 374 -#define __NR_name_to_handle_at 375 -#define __NR_open_by_handle_at 376 -#define __NR_clock_adjtime 377 -#define __NR_syncfs 378 -#define __NR_setns 379 -#define __NR_sendmmsg 380 -#define __NR_process_vm_readv 381 -#define __NR_process_vm_writev 382 - -#define __NR_syscall 383 -#define NR_syscalls __NR_syscall - -/* Old optional stuff no one actually uses */ -#define __IGNORE_sysfs -#define __IGNORE_uselib - -/* Implement the newer interfaces */ -#define __IGNORE_mmap -#define __IGNORE_poll -#define __IGNORE_select -#define __IGNORE_utime - -/* Not relevant on no-mmu */ -#define __IGNORE_swapon -#define __IGNORE_swapoff -#define __IGNORE_msync -#define __IGNORE_mlock -#define __IGNORE_munlock -#define __IGNORE_mlockall -#define __IGNORE_munlockall -#define __IGNORE_mincore -#define __IGNORE_madvise -#define __IGNORE_remap_file_pages -#define __IGNORE_mbind -#define __IGNORE_get_mempolicy -#define __IGNORE_set_mempolicy -#define __IGNORE_migrate_pages -#define __IGNORE_move_pages -#define __IGNORE_getcpu - -#ifdef __KERNEL__ #define __ARCH_WANT_STAT64 #define __ARCH_WANT_SYS_ALARM #define __ARCH_WANT_SYS_GETHOSTNAME @@ -455,6 +29,4 @@ */ #define cond_syscall(x) asm(".weak\t_" #x "\n\t.set\t_" #x ",_sys_ni_syscall"); -#endif /* __KERNEL__ */ - #endif /* __ASM_BFIN_UNISTD_H */ diff --git a/arch/blackfin/include/uapi/asm/Kbuild b/arch/blackfin/include/uapi/asm/Kbuild index baebb3d..0bd28f7 100644 --- a/arch/blackfin/include/uapi/asm/Kbuild +++ b/arch/blackfin/include/uapi/asm/Kbuild @@ -1,3 +1,19 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm +header-y += bfin_sport.h +header-y += byteorder.h +header-y += cachectl.h +header-y += fcntl.h +header-y += fixed_code.h +header-y += ioctls.h +header-y += kvm_para.h +header-y += poll.h +header-y += posix_types.h +header-y += ptrace.h +header-y += sigcontext.h +header-y += siginfo.h +header-y += signal.h +header-y += stat.h +header-y += swab.h +header-y += unistd.h diff --git a/arch/blackfin/include/uapi/asm/bfin_sport.h b/arch/blackfin/include/uapi/asm/bfin_sport.h new file mode 100644 index 0000000..c086de8 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/bfin_sport.h @@ -0,0 +1,136 @@ +/* + * bfin_sport.h - interface to Blackfin SPORTs + * + * Copyright 2004-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _UAPI__BFIN_SPORT_H__ +#define _UAPI__BFIN_SPORT_H__ + +/* Sport mode: it can be set to TDM, i2s or others */ +#define NORM_MODE 0x0 +#define TDM_MODE 0x1 +#define I2S_MODE 0x2 +#define NDSO_MODE 0x3 + +/* Data format, normal, a-law or u-law */ +#define NORM_FORMAT 0x0 +#define ALAW_FORMAT 0x2 +#define ULAW_FORMAT 0x3 + +/* Function driver which use sport must initialize the structure */ +struct sport_config { + /* TDM (multichannels), I2S or other mode */ + unsigned int mode:3; + unsigned int polled; /* use poll instead of irq when set */ + + /* if TDM mode is selected, channels must be set */ + int channels; /* Must be in 8 units */ + unsigned int frame_delay:4; /* Delay between frame sync pulse and first bit */ + + /* I2S mode */ + unsigned int right_first:1; /* Right stereo channel first */ + + /* In mormal mode, the following item need to be set */ + unsigned int lsb_first:1; /* order of transmit or receive data */ + unsigned int fsync:1; /* Frame sync required */ + unsigned int data_indep:1; /* data independent frame sync generated */ + unsigned int act_low:1; /* Active low TFS */ + unsigned int late_fsync:1; /* Late frame sync */ + unsigned int tckfe:1; + unsigned int sec_en:1; /* Secondary side enabled */ + + /* Choose clock source */ + unsigned int int_clk:1; /* Internal or external clock */ + + /* If external clock is used, the following fields are ignored */ + int serial_clk; + int fsync_clk; + + unsigned int data_format:2; /* Normal, u-law or a-law */ + + int word_len; /* How length of the word in bits, 3-32 bits */ + int dma_enabled; +}; + +/* Userspace interface */ +#define SPORT_IOC_MAGIC 'P' +#define SPORT_IOC_CONFIG _IOWR('P', 0x01, struct sport_config) +#define SPORT_IOC_GET_SYSTEMCLOCK _IOR('P', 0x02, unsigned long) +#define SPORT_IOC_SET_BAUDRATE _IOW('P', 0x03, unsigned long) + + +/* SPORT_TCR1 Masks */ +#define TSPEN 0x0001 /* TX enable */ +#define ITCLK 0x0002 /* Internal TX Clock Select */ +#define TDTYPE 0x000C /* TX Data Formatting Select */ +#define DTYPE_NORM 0x0000 /* Data Format Normal */ +#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ +#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ +#define TLSBIT 0x0010 /* TX Bit Order */ +#define ITFS 0x0200 /* Internal TX Frame Sync Select */ +#define TFSR 0x0400 /* TX Frame Sync Required Select */ +#define DITFS 0x0800 /* Data Independent TX Frame Sync Select */ +#define LTFS 0x1000 /* Low TX Frame Sync Select */ +#define LATFS 0x2000 /* Late TX Frame Sync Select */ +#define TCKFE 0x4000 /* TX Clock Falling Edge Select */ + +/* SPORT_TCR2 Masks */ +#define SLEN 0x001F /* SPORT TX Word Length (2 - 31) */ +#define DP_SLEN(x) BFIN_DEPOSIT(SLEN, x) +#define EX_SLEN(x) BFIN_EXTRACT(SLEN, x) +#define TXSE 0x0100 /* TX Secondary Enable */ +#define TSFSE 0x0200 /* TX Stereo Frame Sync Enable */ +#define TRFST 0x0400 /* TX Right-First Data Order */ + +/* SPORT_RCR1 Masks */ +#define RSPEN 0x0001 /* RX enable */ +#define IRCLK 0x0002 /* Internal RX Clock Select */ +#define RDTYPE 0x000C /* RX Data Formatting Select */ +/* DTYPE_* defined above */ +#define RLSBIT 0x0010 /* RX Bit Order */ +#define IRFS 0x0200 /* Internal RX Frame Sync Select */ +#define RFSR 0x0400 /* RX Frame Sync Required Select */ +#define LRFS 0x1000 /* Low RX Frame Sync Select */ +#define LARFS 0x2000 /* Late RX Frame Sync Select */ +#define RCKFE 0x4000 /* RX Clock Falling Edge Select */ + +/* SPORT_RCR2 Masks */ +/* SLEN defined above */ +#define RXSE 0x0100 /* RX Secondary Enable */ +#define RSFSE 0x0200 /* RX Stereo Frame Sync Enable */ +#define RRFST 0x0400 /* Right-First Data Order */ + +/* SPORT_STAT Masks */ +#define RXNE 0x0001 /* RX FIFO Not Empty Status */ +#define RUVF 0x0002 /* RX Underflow Status */ +#define ROVF 0x0004 /* RX Overflow Status */ +#define TXF 0x0008 /* TX FIFO Full Status */ +#define TUVF 0x0010 /* TX Underflow Status */ +#define TOVF 0x0020 /* TX Overflow Status */ +#define TXHRE 0x0040 /* TX Hold Register Empty */ + +/* SPORT_MCMC1 Masks */ +#define SP_WOFF 0x03FF /* Multichannel Window Offset Field */ +#define DP_SP_WOFF(x) BFIN_DEPOSIT(SP_WOFF, x) +#define EX_SP_WOFF(x) BFIN_EXTRACT(SP_WOFF, x) +#define SP_WSIZE 0xF000 /* Multichannel Window Size Field */ +#define DP_SP_WSIZE(x) BFIN_DEPOSIT(SP_WSIZE, x) +#define EX_SP_WSIZE(x) BFIN_EXTRACT(SP_WSIZE, x) + +/* SPORT_MCMC2 Masks */ +#define MCCRM 0x0003 /* Multichannel Clock Recovery Mode */ +#define REC_BYPASS 0x0000 /* Bypass Mode (No Clock Recovery) */ +#define REC_2FROM4 0x0002 /* Recover 2 MHz Clock from 4 MHz Clock */ +#define REC_8FROM16 0x0003 /* Recover 8 MHz Clock from 16 MHz Clock */ +#define MCDTXPE 0x0004 /* Multichannel DMA Transmit Packing */ +#define MCDRXPE 0x0008 /* Multichannel DMA Receive Packing */ +#define MCMEN 0x0010 /* Multichannel Frame Mode Enable */ +#define FSDR 0x0080 /* Multichannel Frame Sync to Data Relationship */ +#define MFD 0xF000 /* Multichannel Frame Delay */ +#define DP_MFD(x) BFIN_DEPOSIT(MFD, x) +#define EX_MFD(x) BFIN_EXTRACT(MFD, x) + +#endif /* _UAPI__BFIN_SPORT_H__ */ diff --git a/arch/blackfin/include/uapi/asm/byteorder.h b/arch/blackfin/include/uapi/asm/byteorder.h new file mode 100644 index 0000000..9558416 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/byteorder.h @@ -0,0 +1 @@ +#include diff --git a/arch/blackfin/include/uapi/asm/cachectl.h b/arch/blackfin/include/uapi/asm/cachectl.h new file mode 100644 index 0000000..03255df --- /dev/null +++ b/arch/blackfin/include/uapi/asm/cachectl.h @@ -0,0 +1,20 @@ +/* + * based on the mips/cachectl.h + * + * Copyright 2010 Analog Devices Inc. + * Copyright (C) 1994, 1995, 1996 by Ralf Baechle + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _ASM_CACHECTL +#define _ASM_CACHECTL + +/* + * Options for cacheflush system call + */ +#define ICACHE (1<<0) /* flush instruction cache */ +#define DCACHE (1<<1) /* writeback and flush data cache */ +#define BCACHE (ICACHE|DCACHE) /* flush both caches */ + +#endif /* _ASM_CACHECTL */ diff --git a/arch/blackfin/include/uapi/asm/fcntl.h b/arch/blackfin/include/uapi/asm/fcntl.h new file mode 100644 index 0000000..251c911 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/fcntl.h @@ -0,0 +1,17 @@ +/* + * Copyright 2004-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _BFIN_FCNTL_H +#define _BFIN_FCNTL_H + +#define O_DIRECTORY 040000 /* must be a directory */ +#define O_NOFOLLOW 0100000 /* don't follow links */ +#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ +#define O_LARGEFILE 0400000 + +#include + +#endif diff --git a/arch/blackfin/include/uapi/asm/fixed_code.h b/arch/blackfin/include/uapi/asm/fixed_code.h new file mode 100644 index 0000000..3bef1dc --- /dev/null +++ b/arch/blackfin/include/uapi/asm/fixed_code.h @@ -0,0 +1,38 @@ +/* + * This file defines the fixed addresses where userspace programs + * can find atomic code sequences. + * + * Copyright 2007-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _UAPI__BFIN_ASM_FIXED_CODE_H__ +#define _UAPI__BFIN_ASM_FIXED_CODE_H__ + + +#ifndef CONFIG_PHY_RAM_BASE_ADDRESS +#define CONFIG_PHY_RAM_BASE_ADDRESS 0x0 +#endif + +#define FIXED_CODE_START (CONFIG_PHY_RAM_BASE_ADDRESS + 0x400) + +#define SIGRETURN_STUB (CONFIG_PHY_RAM_BASE_ADDRESS + 0x400) + +#define ATOMIC_SEQS_START (CONFIG_PHY_RAM_BASE_ADDRESS + 0x410) + +#define ATOMIC_XCHG32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x410) +#define ATOMIC_CAS32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x420) +#define ATOMIC_ADD32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x430) +#define ATOMIC_SUB32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x440) +#define ATOMIC_IOR32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x450) +#define ATOMIC_AND32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x460) +#define ATOMIC_XOR32 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x470) + +#define ATOMIC_SEQS_END (CONFIG_PHY_RAM_BASE_ADDRESS + 0x480) + +#define SAFE_USER_INSTRUCTION (CONFIG_PHY_RAM_BASE_ADDRESS + 0x480) + +#define FIXED_CODE_END (CONFIG_PHY_RAM_BASE_ADDRESS + 0x490) + +#endif /* _UAPI__BFIN_ASM_FIXED_CODE_H__ */ diff --git a/arch/blackfin/include/uapi/asm/ioctls.h b/arch/blackfin/include/uapi/asm/ioctls.h new file mode 100644 index 0000000..eca8d75 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/ioctls.h @@ -0,0 +1,7 @@ +#ifndef __ARCH_BFIN_IOCTLS_H__ +#define __ARCH_BFIN_IOCTLS_H__ + +#define FIOQSIZE 0x545E +#include + +#endif diff --git a/arch/blackfin/include/uapi/asm/kvm_para.h b/arch/blackfin/include/uapi/asm/kvm_para.h new file mode 100644 index 0000000..14fab8f --- /dev/null +++ b/arch/blackfin/include/uapi/asm/kvm_para.h @@ -0,0 +1 @@ +#include diff --git a/arch/blackfin/include/uapi/asm/poll.h b/arch/blackfin/include/uapi/asm/poll.h new file mode 100644 index 0000000..072d896 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/poll.h @@ -0,0 +1,16 @@ +/* + * Copyright 2004-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + * + */ + +#ifndef __BFIN_POLL_H +#define __BFIN_POLL_H + +#define POLLWRNORM 4 /* POLLOUT */ +#define POLLWRBAND 256 + +#include + +#endif diff --git a/arch/blackfin/include/uapi/asm/posix_types.h b/arch/blackfin/include/uapi/asm/posix_types.h new file mode 100644 index 0000000..1bd3436 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/posix_types.h @@ -0,0 +1,30 @@ +/* + * Copyright 2004-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __ARCH_BFIN_POSIX_TYPES_H +#define __ARCH_BFIN_POSIX_TYPES_H + +typedef unsigned short __kernel_mode_t; +#define __kernel_mode_t __kernel_mode_t + +typedef unsigned int __kernel_ipc_pid_t; +#define __kernel_ipc_pid_t __kernel_ipc_pid_t + +typedef unsigned long __kernel_size_t; +typedef long __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +#define __kernel_size_t __kernel_size_t + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +#define __kernel_old_uid_t __kernel_old_uid_t + +typedef unsigned short __kernel_old_dev_t; +#define __kernel_old_dev_t __kernel_old_dev_t + +#include + +#endif diff --git a/arch/blackfin/include/uapi/asm/ptrace.h b/arch/blackfin/include/uapi/asm/ptrace.h new file mode 100644 index 0000000..fd48bd0 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/ptrace.h @@ -0,0 +1,170 @@ +/* + * Copyright 2004-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _UAPI_BFIN_PTRACE_H +#define _UAPI_BFIN_PTRACE_H + +/* + * GCC defines register number like this: + * ----------------------------- + * 0 - 7 are data registers R0-R7 + * 8 - 15 are address registers P0-P7 + * 16 - 31 dsp registers I/B/L0 -- I/B/L3 & M0--M3 + * 32 - 33 A registers A0 & A1 + * 34 - status register + * ----------------------------- + * + * We follows above, except: + * 32-33 --- Low 32-bit of A0&1 + * 34-35 --- High 8-bit of A0&1 + */ + +#ifndef __ASSEMBLY__ + +struct task_struct; + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct pt_regs { + long orig_pc; + long ipend; + long seqstat; + long rete; + long retn; + long retx; + long pc; /* PC == RETI */ + long rets; + long reserved; /* Used as scratch during system calls */ + long astat; + long lb1; + long lb0; + long lt1; + long lt0; + long lc1; + long lc0; + long a1w; + long a1x; + long a0w; + long a0x; + long b3; + long b2; + long b1; + long b0; + long l3; + long l2; + long l1; + long l0; + long m3; + long m2; + long m1; + long m0; + long i3; + long i2; + long i1; + long i0; + long usp; + long fp; + long p5; + long p4; + long p3; + long p2; + long p1; + long p0; + long r7; + long r6; + long r5; + long r4; + long r3; + long r2; + long r1; + long r0; + long orig_r0; + long orig_p0; + long syscfg; +}; + +/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 /* ptrace signal */ + +#define PTRACE_GETFDPIC 31 /* get the ELF fdpic loadmap address */ +#define PTRACE_GETFDPIC_EXEC 0 /* [addr] request the executable loadmap */ +#define PTRACE_GETFDPIC_INTERP 1 /* [addr] request the interpreter loadmap */ + +#define PS_S (0x0002) + + +#endif /* __ASSEMBLY__ */ + +/* + * Offsets used by 'ptrace' system call interface. + */ + +#define PT_R0 204 +#define PT_R1 200 +#define PT_R2 196 +#define PT_R3 192 +#define PT_R4 188 +#define PT_R5 184 +#define PT_R6 180 +#define PT_R7 176 +#define PT_P0 172 +#define PT_P1 168 +#define PT_P2 164 +#define PT_P3 160 +#define PT_P4 156 +#define PT_P5 152 +#define PT_FP 148 +#define PT_USP 144 +#define PT_I0 140 +#define PT_I1 136 +#define PT_I2 132 +#define PT_I3 128 +#define PT_M0 124 +#define PT_M1 120 +#define PT_M2 116 +#define PT_M3 112 +#define PT_L0 108 +#define PT_L1 104 +#define PT_L2 100 +#define PT_L3 96 +#define PT_B0 92 +#define PT_B1 88 +#define PT_B2 84 +#define PT_B3 80 +#define PT_A0X 76 +#define PT_A0W 72 +#define PT_A1X 68 +#define PT_A1W 64 +#define PT_LC0 60 +#define PT_LC1 56 +#define PT_LT0 52 +#define PT_LT1 48 +#define PT_LB0 44 +#define PT_LB1 40 +#define PT_ASTAT 36 +#define PT_RESERVED 32 +#define PT_RETS 28 +#define PT_PC 24 +#define PT_RETX 20 +#define PT_RETN 16 +#define PT_RETE 12 +#define PT_SEQSTAT 8 +#define PT_IPEND 4 + +#define PT_ORIG_R0 208 +#define PT_ORIG_P0 212 +#define PT_SYSCFG 216 +#define PT_TEXT_ADDR 220 +#define PT_TEXT_END_ADDR 224 +#define PT_DATA_ADDR 228 +#define PT_FDPIC_EXEC 232 +#define PT_FDPIC_INTERP 236 + +#define PT_LAST_PSEUDO PT_FDPIC_INTERP + +#endif /* _UAPI_BFIN_PTRACE_H */ diff --git a/arch/blackfin/include/uapi/asm/sigcontext.h b/arch/blackfin/include/uapi/asm/sigcontext.h new file mode 100644 index 0000000..906bdc1 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/sigcontext.h @@ -0,0 +1,61 @@ +/* + * Copyright 2004-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _ASM_BLACKFIN_SIGCONTEXT_H +#define _ASM_BLACKFIN_SIGCONTEXT_H + +/* Add new entries at the end of the structure only. */ +struct sigcontext { + unsigned long sc_r0; + unsigned long sc_r1; + unsigned long sc_r2; + unsigned long sc_r3; + unsigned long sc_r4; + unsigned long sc_r5; + unsigned long sc_r6; + unsigned long sc_r7; + unsigned long sc_p0; + unsigned long sc_p1; + unsigned long sc_p2; + unsigned long sc_p3; + unsigned long sc_p4; + unsigned long sc_p5; + unsigned long sc_usp; + unsigned long sc_a0w; + unsigned long sc_a1w; + unsigned long sc_a0x; + unsigned long sc_a1x; + unsigned long sc_astat; + unsigned long sc_rets; + unsigned long sc_pc; + unsigned long sc_retx; + unsigned long sc_fp; + unsigned long sc_i0; + unsigned long sc_i1; + unsigned long sc_i2; + unsigned long sc_i3; + unsigned long sc_m0; + unsigned long sc_m1; + unsigned long sc_m2; + unsigned long sc_m3; + unsigned long sc_l0; + unsigned long sc_l1; + unsigned long sc_l2; + unsigned long sc_l3; + unsigned long sc_b0; + unsigned long sc_b1; + unsigned long sc_b2; + unsigned long sc_b3; + unsigned long sc_lc0; + unsigned long sc_lc1; + unsigned long sc_lt0; + unsigned long sc_lt1; + unsigned long sc_lb0; + unsigned long sc_lb1; + unsigned long sc_seqstat; +}; + +#endif diff --git a/arch/blackfin/include/uapi/asm/siginfo.h b/arch/blackfin/include/uapi/asm/siginfo.h new file mode 100644 index 0000000..3e81306 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/siginfo.h @@ -0,0 +1,41 @@ +/* + * Copyright 2004-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _BFIN_SIGINFO_H +#define _BFIN_SIGINFO_H + +#include +#include + +#define UID16_SIGINFO_COMPAT_NEEDED + +#define si_uid16 _sifields._kill._uid + +#define ILL_ILLPARAOP (__SI_FAULT|2) /* illegal opcode combine ********** */ +#define ILL_ILLEXCPT (__SI_FAULT|4) /* unrecoverable exception ********** */ +#define ILL_CPLB_VI (__SI_FAULT|9) /* D/I CPLB protect violation ******** */ +#define ILL_CPLB_MISS (__SI_FAULT|10) /* D/I CPLB miss ******** */ +#define ILL_CPLB_MULHIT (__SI_FAULT|11) /* D/I CPLB multiple hit ******** */ + +/* + * SIGBUS si_codes + */ +#define BUS_OPFETCH (__SI_FAULT|4) /* error from instruction fetch ******** */ + +/* + * SIGTRAP si_codes + */ +#define TRAP_STEP (__SI_FAULT|1) /* single-step breakpoint************* */ +#define TRAP_TRACEFLOW (__SI_FAULT|2) /* trace buffer overflow ************* */ +#define TRAP_WATCHPT (__SI_FAULT|3) /* watchpoint match ************* */ +#define TRAP_ILLTRAP (__SI_FAULT|4) /* illegal trap ************* */ + +/* + * SIGSEGV si_codes + */ +#define SEGV_STACKFLOW (__SI_FAULT|3) /* stack overflow */ + +#endif diff --git a/arch/blackfin/include/uapi/asm/signal.h b/arch/blackfin/include/uapi/asm/signal.h new file mode 100644 index 0000000..77a3bf3 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/signal.h @@ -0,0 +1,7 @@ +#ifndef _BLACKFIN_SIGNAL_H +#define _BLACKFIN_SIGNAL_H + +#define SA_RESTORER 0x04000000 +#include + +#endif diff --git a/arch/blackfin/include/uapi/asm/stat.h b/arch/blackfin/include/uapi/asm/stat.h new file mode 100644 index 0000000..2e27665 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/stat.h @@ -0,0 +1,69 @@ +/* + * Copyright 2004-2006 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#ifndef _BFIN_STAT_H +#define _BFIN_STAT_H + +struct stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long __unused1; + unsigned long st_mtime; + unsigned long __unused2; + unsigned long st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct stat64 { + unsigned long long st_dev; + unsigned char __pad1[4]; + +#define STAT64_HAS_BROKEN_ST_INO 1 + unsigned long __st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + unsigned long long st_rdev; + unsigned char __pad2[4]; + + long long st_size; + unsigned long st_blksize; + + long long st_blocks; /* Number 512-byte blocks allocated. */ + + unsigned long st_atime; + unsigned long st_atime_nsec; + + unsigned long st_mtime; + unsigned long st_mtime_nsec; + + unsigned long st_ctime; + unsigned long st_ctime_nsec; + + unsigned long long st_ino; +}; + +#endif /* _BFIN_STAT_H */ diff --git a/arch/blackfin/include/uapi/asm/swab.h b/arch/blackfin/include/uapi/asm/swab.h new file mode 100644 index 0000000..89de650 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/swab.h @@ -0,0 +1,50 @@ +/* + * Copyright 2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _BLACKFIN_SWAB_H +#define _BLACKFIN_SWAB_H + +#include +#include + +#ifdef __GNUC__ + +static __inline__ __attribute_const__ __u32 __arch_swahb32(__u32 xx) +{ + __u32 tmp; + __asm__("%1 = %0 >> 8 (V);\n\t" + "%0 = %0 << 8 (V);\n\t" + "%0 = %0 | %1;\n\t" + : "+d"(xx), "=&d"(tmp)); + return xx; +} +#define __arch_swahb32 __arch_swahb32 + +static __inline__ __attribute_const__ __u32 __arch_swahw32(__u32 xx) +{ + __u32 rv; + __asm__("%0 = PACK(%1.L, %1.H);\n\t": "=d"(rv): "d"(xx)); + return rv; +} +#define __arch_swahw32 __arch_swahw32 + +static __inline__ __attribute_const__ __u32 __arch_swab32(__u32 xx) +{ + return __arch_swahb32(__arch_swahw32(xx)); +} +#define __arch_swab32 __arch_swab32 + +static __inline__ __attribute_const__ __u16 __arch_swab16(__u16 xx) +{ + __u32 xw = xx; + __asm__("%0 <<= 8;\n %0.L = %0.L + %0.H (NS);\n": "+d"(xw)); + return (__u16)xw; +} +#define __arch_swab16 __arch_swab16 + +#endif /* __GNUC__ */ + +#endif /* _BLACKFIN_SWAB_H */ diff --git a/arch/blackfin/include/uapi/asm/unistd.h b/arch/blackfin/include/uapi/asm/unistd.h new file mode 100644 index 0000000..a451164 --- /dev/null +++ b/arch/blackfin/include/uapi/asm/unistd.h @@ -0,0 +1,437 @@ +/* + * Copyright 2004-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _UAPI__ASM_BFIN_UNISTD_H +#define _UAPI__ASM_BFIN_UNISTD_H +/* + * This file contains the system call numbers. + */ +#define __NR_restart_syscall 0 +#define __NR_exit 1 + /* 2 __NR_fork not supported on nommu */ +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 + /* 7 __NR_waitpid obsolete */ +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 + /* 17 __NR_break obsolete */ + /* 18 __NR_oldstat obsolete */ +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 + /* 22 __NR_umount obsolete */ +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 + /* 28 __NR_oldfstat obsolete */ +#define __NR_pause 29 + /* 30 __NR_utime obsolete */ + /* 31 __NR_stty obsolete */ + /* 32 __NR_gtty obsolete */ +#define __NR_access 33 +#define __NR_nice 34 + /* 35 __NR_ftime obsolete */ +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 + /* 44 __NR_prof obsolete */ +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 + /* 48 __NR_signal obsolete */ +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 + /* 53 __NR_lock obsolete */ +#define __NR_ioctl 54 +#define __NR_fcntl 55 + /* 56 __NR_mpx obsolete */ +#define __NR_setpgid 57 + /* 58 __NR_ulimit obsolete */ + /* 59 __NR_oldolduname obsolete */ +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 + /* 67 __NR_sigaction obsolete */ +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 + /* 72 __NR_sigsuspend obsolete */ + /* 73 __NR_sigpending obsolete */ +#define __NR_sethostname 74 +#define __NR_setrlimit 75 + /* 76 __NR_old_getrlimit obsolete */ +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 + /* 82 __NR_select obsolete */ +#define __NR_symlink 83 + /* 84 __NR_oldlstat obsolete */ +#define __NR_readlink 85 + /* 86 __NR_uselib obsolete */ + /* 87 __NR_swapon obsolete */ +#define __NR_reboot 88 + /* 89 __NR_readdir obsolete */ + /* 90 __NR_mmap obsolete */ +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 + /* 98 __NR_profil obsolete */ +#define __NR_statfs 99 +#define __NR_fstatfs 100 + /* 101 __NR_ioperm */ + /* 102 __NR_socketcall obsolete */ +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 + /* 109 __NR_olduname obsolete */ + /* 110 __NR_iopl obsolete */ +#define __NR_vhangup 111 + /* 112 __NR_idle obsolete */ + /* 113 __NR_vm86old */ +#define __NR_wait4 114 + /* 115 __NR_swapoff obsolete */ +#define __NR_sysinfo 116 + /* 117 __NR_ipc oboslete */ +#define __NR_fsync 118 + /* 119 __NR_sigreturn obsolete */ +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 + /* 123 __NR_modify_ldt obsolete */ +#define __NR_adjtimex 124 +#define __NR_mprotect 125 + /* 126 __NR_sigprocmask obsolete */ + /* 127 __NR_create_module obsolete */ +#define __NR_init_module 128 +#define __NR_delete_module 129 + /* 130 __NR_get_kernel_syms obsolete */ +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 + /* 135 was sysfs */ +#define __NR_personality 136 + /* 137 __NR_afs_syscall */ +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 + /* 142 __NR__newselect obsolete */ +#define __NR_flock 143 + /* 144 __NR_msync obsolete */ +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 + /* 150 __NR_mlock */ + /* 151 __NR_munlock */ + /* 152 __NR_mlockall */ + /* 153 __NR_munlockall */ +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 + /* 166 __NR_vm86 */ + /* 167 __NR_query_module */ + /* 168 __NR_poll */ +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread 180 +#define __NR_pwrite 181 +#define __NR_lchown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 + /* 188 __NR_getpmsg */ + /* 189 __NR_putpmsg */ +#define __NR_vfork 190 +#define __NR_getrlimit 191 +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_chown32 198 +#define __NR_getuid32 199 +#define __NR_getgid32 200 +#define __NR_geteuid32 201 +#define __NR_getegid32 202 +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#define __NR_lchown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#define __NR_pivot_root 217 + /* 218 __NR_mincore */ + /* 219 __NR_madvise */ +#define __NR_getdents64 220 +#define __NR_fcntl64 221 + /* 222 reserved for TUX */ + /* 223 reserved for TUX */ +#define __NR_gettid 224 +#define __NR_readahead 225 +#define __NR_setxattr 226 +#define __NR_lsetxattr 227 +#define __NR_fsetxattr 228 +#define __NR_getxattr 229 +#define __NR_lgetxattr 230 +#define __NR_fgetxattr 231 +#define __NR_listxattr 232 +#define __NR_llistxattr 233 +#define __NR_flistxattr 234 +#define __NR_removexattr 235 +#define __NR_lremovexattr 236 +#define __NR_fremovexattr 237 +#define __NR_tkill 238 +#define __NR_sendfile64 239 +#define __NR_futex 240 +#define __NR_sched_setaffinity 241 +#define __NR_sched_getaffinity 242 + /* 243 __NR_set_thread_area */ + /* 244 __NR_get_thread_area */ +#define __NR_io_setup 245 +#define __NR_io_destroy 246 +#define __NR_io_getevents 247 +#define __NR_io_submit 248 +#define __NR_io_cancel 249 + /* 250 __NR_alloc_hugepages */ + /* 251 __NR_free_hugepages */ +#define __NR_exit_group 252 +#define __NR_lookup_dcookie 253 +#define __NR_bfin_spinlock 254 + +#define __NR_epoll_create 255 +#define __NR_epoll_ctl 256 +#define __NR_epoll_wait 257 + /* 258 __NR_remap_file_pages */ +#define __NR_set_tid_address 259 +#define __NR_timer_create 260 +#define __NR_timer_settime 261 +#define __NR_timer_gettime 262 +#define __NR_timer_getoverrun 263 +#define __NR_timer_delete 264 +#define __NR_clock_settime 265 +#define __NR_clock_gettime 266 +#define __NR_clock_getres 267 +#define __NR_clock_nanosleep 268 +#define __NR_statfs64 269 +#define __NR_fstatfs64 270 +#define __NR_tgkill 271 +#define __NR_utimes 272 +#define __NR_fadvise64_64 273 + /* 274 __NR_vserver */ + /* 275 __NR_mbind */ + /* 276 __NR_get_mempolicy */ + /* 277 __NR_set_mempolicy */ +#define __NR_mq_open 278 +#define __NR_mq_unlink 279 +#define __NR_mq_timedsend 280 +#define __NR_mq_timedreceive 281 +#define __NR_mq_notify 282 +#define __NR_mq_getsetattr 283 +#define __NR_kexec_load 284 +#define __NR_waitid 285 +#define __NR_add_key 286 +#define __NR_request_key 287 +#define __NR_keyctl 288 +#define __NR_ioprio_set 289 +#define __NR_ioprio_get 290 +#define __NR_inotify_init 291 +#define __NR_inotify_add_watch 292 +#define __NR_inotify_rm_watch 293 + /* 294 __NR_migrate_pages */ +#define __NR_openat 295 +#define __NR_mkdirat 296 +#define __NR_mknodat 297 +#define __NR_fchownat 298 +#define __NR_futimesat 299 +#define __NR_fstatat64 300 +#define __NR_unlinkat 301 +#define __NR_renameat 302 +#define __NR_linkat 303 +#define __NR_symlinkat 304 +#define __NR_readlinkat 305 +#define __NR_fchmodat 306 +#define __NR_faccessat 307 +#define __NR_pselect6 308 +#define __NR_ppoll 309 +#define __NR_unshare 310 + +/* Blackfin private syscalls */ +#define __NR_sram_alloc 311 +#define __NR_sram_free 312 +#define __NR_dma_memcpy 313 + +/* socket syscalls */ +#define __NR_accept 314 +#define __NR_bind 315 +#define __NR_connect 316 +#define __NR_getpeername 317 +#define __NR_getsockname 318 +#define __NR_getsockopt 319 +#define __NR_listen 320 +#define __NR_recv 321 +#define __NR_recvfrom 322 +#define __NR_recvmsg 323 +#define __NR_send 324 +#define __NR_sendmsg 325 +#define __NR_sendto 326 +#define __NR_setsockopt 327 +#define __NR_shutdown 328 +#define __NR_socket 329 +#define __NR_socketpair 330 + +/* sysv ipc syscalls */ +#define __NR_semctl 331 +#define __NR_semget 332 +#define __NR_semop 333 +#define __NR_msgctl 334 +#define __NR_msgget 335 +#define __NR_msgrcv 336 +#define __NR_msgsnd 337 +#define __NR_shmat 338 +#define __NR_shmctl 339 +#define __NR_shmdt 340 +#define __NR_shmget 341 + +#define __NR_splice 342 +#define __NR_sync_file_range 343 +#define __NR_tee 344 +#define __NR_vmsplice 345 + +#define __NR_epoll_pwait 346 +#define __NR_utimensat 347 +#define __NR_signalfd 348 +#define __NR_timerfd_create 349 +#define __NR_eventfd 350 +#define __NR_pread64 351 +#define __NR_pwrite64 352 +#define __NR_fadvise64 353 +#define __NR_set_robust_list 354 +#define __NR_get_robust_list 355 +#define __NR_fallocate 356 +#define __NR_semtimedop 357 +#define __NR_timerfd_settime 358 +#define __NR_timerfd_gettime 359 +#define __NR_signalfd4 360 +#define __NR_eventfd2 361 +#define __NR_epoll_create1 362 +#define __NR_dup3 363 +#define __NR_pipe2 364 +#define __NR_inotify_init1 365 +#define __NR_preadv 366 +#define __NR_pwritev 367 +#define __NR_rt_tgsigqueueinfo 368 +#define __NR_perf_event_open 369 +#define __NR_recvmmsg 370 +#define __NR_fanotify_init 371 +#define __NR_fanotify_mark 372 +#define __NR_prlimit64 373 +#define __NR_cacheflush 374 +#define __NR_name_to_handle_at 375 +#define __NR_open_by_handle_at 376 +#define __NR_clock_adjtime 377 +#define __NR_syncfs 378 +#define __NR_setns 379 +#define __NR_sendmmsg 380 +#define __NR_process_vm_readv 381 +#define __NR_process_vm_writev 382 + +#define __NR_syscall 383 +#define NR_syscalls __NR_syscall + +/* Old optional stuff no one actually uses */ +#define __IGNORE_sysfs +#define __IGNORE_uselib + +/* Implement the newer interfaces */ +#define __IGNORE_mmap +#define __IGNORE_poll +#define __IGNORE_select +#define __IGNORE_utime + +/* Not relevant on no-mmu */ +#define __IGNORE_swapon +#define __IGNORE_swapoff +#define __IGNORE_msync +#define __IGNORE_mlock +#define __IGNORE_munlock +#define __IGNORE_mlockall +#define __IGNORE_munlockall +#define __IGNORE_mincore +#define __IGNORE_madvise +#define __IGNORE_remap_file_pages +#define __IGNORE_mbind +#define __IGNORE_get_mempolicy +#define __IGNORE_set_mempolicy +#define __IGNORE_migrate_pages +#define __IGNORE_move_pages +#define __IGNORE_getcpu + + +#endif /* _UAPI__ASM_BFIN_UNISTD_H */ -- cgit v0.10.2 From e9dfcdbd76b14a24e751d6e0bfb29dc262c69b0c Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 12 Oct 2012 22:26:36 -0400 Subject: blackfin: Use Kbuild infrastructure for kvm_para.h All the headers but kvm_para.h use the Kbuild infrastructure to get to the asm-generic headers. Cc: linux-kbuild@vger.kernel.org Cc: uclinux-dist-devel@blackfin.uclinux.org Cc: Mike Frysinger Signed-off-by: Steven Rostedt Signed-off-by: Bob Liu diff --git a/arch/blackfin/include/asm/Kbuild b/arch/blackfin/include/asm/Kbuild index 7ce56f5..9d1f5b3 100644 --- a/arch/blackfin/include/asm/Kbuild +++ b/arch/blackfin/include/asm/Kbuild @@ -16,6 +16,7 @@ generic-y += ipcbuf.h generic-y += irq_regs.h generic-y += kdebug.h generic-y += kmap_types.h +generic-y += kvm_para.h generic-y += local64.h generic-y += local.h generic-y += mman.h diff --git a/arch/blackfin/include/uapi/asm/kvm_para.h b/arch/blackfin/include/uapi/asm/kvm_para.h deleted file mode 100644 index 14fab8f..0000000 --- a/arch/blackfin/include/uapi/asm/kvm_para.h +++ /dev/null @@ -1 +0,0 @@ -#include -- cgit v0.10.2 From d95dcaa06ba895ec379d80b35c25ddba3a71943a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 17 Oct 2012 16:28:02 +0200 Subject: Blackfin: Annotate strncpy_from_user src parameter with __user The src parameter of strncpy_from_user is supposed to take a string from userspace, so it should be annotated with __user. Doing so fixes the following and similar warnings from sparse: kernel/sys.c:491:51: warning: incorrect type in argument 2 (different address spaces) kernel/sys.c:491:51: expected char const *src kernel/sys.c:491:51: got void [noderef] *arg kernel/sys.c:2061:54: warning: incorrect type in argument 2 (different address spaces) kernel/sys.c:2061:54: expected char const *src kernel/sys.c:2061:54: got char [noderef] * Signed-off-by: Lars-Peter Clausen Signed-off-by: Bob Liu diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h index 5cc1115..3edb4af 100644 --- a/arch/blackfin/include/asm/uaccess.h +++ b/arch/blackfin/include/asm/uaccess.h @@ -216,12 +216,12 @@ copy_to_user(void __user *to, const void *from, unsigned long n) */ static inline long __must_check -strncpy_from_user(char *dst, const char *src, long count) +strncpy_from_user(char *dst, const char __user *src, long count) { char *tmp; if (!access_ok(VERIFY_READ, src, 1)) return -EFAULT; - strncpy(dst, src, count); + strncpy(dst, (const char __force *)src, count); for (tmp = dst; *tmp && count > 0; tmp++, count--) ; return (tmp - dst); } -- cgit v0.10.2 From aff06631da3c8349149fe4214091735b35294151 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 22 Oct 2012 16:09:03 +0200 Subject: Blackfin: Add missing __user annotations to put_user typeof() will not inherit the __user annotation so we have to explicitly specify this for '_p'. This fixes the following and quite a few similar warnings from spatch: kernel/sys.c:884:26: warning: incorrect type in initializer (different address spaces) kernel/sys.c:884:26: expected unsigned int *_p kernel/sys.c:884:26: got unsigned int [noderef] [usertype] *ruidp kernel/sys.c:885:26: warning: incorrect type in initializer (different address spaces) kernel/sys.c:885:26: expected unsigned int *_p kernel/sys.c:885:26: got unsigned int [noderef] [usertype] *euidp kernel/sys.c:886:26: warning: incorrect type in initializer (different address spaces) kernel/sys.c:886:26: expected unsigned int *_p kernel/sys.c:886:26: got unsigned int [noderef] [usertype] *suidp Signed-off-by: Lars-Peter Clausen Signed-off-by: Bob Liu diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h index 3edb4af..90f32c2 100644 --- a/arch/blackfin/include/asm/uaccess.h +++ b/arch/blackfin/include/asm/uaccess.h @@ -89,7 +89,7 @@ struct exception_table_entry { ({ \ int _err = 0; \ typeof(*(p)) _x = (x); \ - typeof(*(p)) *_p = (p); \ + typeof(*(p)) __user *_p = (p); \ if (!access_ok(VERIFY_WRITE, _p, sizeof(*(_p)))) {\ _err = -EFAULT; \ } \ @@ -108,8 +108,8 @@ struct exception_table_entry { long _xl, _xh; \ _xl = ((long *)&_x)[0]; \ _xh = ((long *)&_x)[1]; \ - __put_user_asm(_xl, ((long *)_p)+0, ); \ - __put_user_asm(_xh, ((long *)_p)+1, ); \ + __put_user_asm(_xl, ((long __user *)_p)+0, ); \ + __put_user_asm(_xh, ((long __user *)_p)+1, ); \ } break; \ default: \ _err = __put_user_bad(); \ @@ -136,7 +136,7 @@ static inline int bad_user_access_length(void) * aliasing issues. */ -#define __ptr(x) ((unsigned long *)(x)) +#define __ptr(x) ((unsigned long __force *)(x)) #define __put_user_asm(x,p,bhw) \ __asm__ (#bhw"[%1] = %0;\n\t" \ -- cgit v0.10.2 From 10dc42b5b262f3bb2e4532759e4e1147ebf6a22f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 22 Oct 2012 16:09:04 +0200 Subject: Blackfin: Annotate clear_user 'to' parameter with __user The 'to' parameter of clear_user is supposed to take a userspace pointer, so annotate it with __user. This fixes the following and similar sparse warnings: fs/binfmt_elf_fdpic.c:714:35: warning: incorrect type in argument 1 (different address spaces) fs/binfmt_elf_fdpic.c:714:35: expected void [noderef] *to fs/binfmt_elf_fdpic.c:714:35: got void * fs/binfmt_elf_fdpic.c:1119:29: warning: incorrect type in argument 1 (different address spaces) fs/binfmt_elf_fdpic.c:1119:29: expected void *to fs/binfmt_elf_fdpic.c:1119:29: got void [noderef] * Signed-off-by: Lars-Peter Clausen Signed-off-by: Bob Liu diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h index 90f32c2..ded2d05 100644 --- a/arch/blackfin/include/asm/uaccess.h +++ b/arch/blackfin/include/asm/uaccess.h @@ -256,11 +256,11 @@ static inline long __must_check strlen_user(const char *src) */ static inline unsigned long __must_check -__clear_user(void *to, unsigned long n) +__clear_user(void __user *to, unsigned long n) { if (!access_ok(VERIFY_WRITE, to, n)) return n; - memset(to, 0, n); + memset((void __force *)to, 0, n); return 0; } -- cgit v0.10.2 From 2a7e0775d0b0dfc083f97c72dc885f6dab8dd27b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 22 Oct 2012 16:09:05 +0200 Subject: Blackfin: Annotate strnlen_user and strlen_user 'src' parameter with __user The 'src' parameter of strnlen_user and strlen_user is supposed to take a userspace pointer, so annotate it with __user. This fixes the following and similar sparse warnings: fs/binfmt_elf_fdpic.c:671:36: warning: incorrect type in argument 1 (different address spaces) fs/binfmt_elf_fdpic.c:671:36: expected char const *src fs/binfmt_elf_fdpic.c:671:36: got char [noderef] *[assigned] p fs/binfmt_elf_fdpic.c:683:36: warning: incorrect type in argument 1 (different address spaces) fs/binfmt_elf_fdpic.c:683:36: expected char const *src fs/binfmt_elf_fdpic.c:683:36: got char [noderef] *[assigned] p Signed-off-by: Lars-Peter Clausen Signed-off-by: Bob Liu diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h index ded2d05..3ee7b42 100644 --- a/arch/blackfin/include/asm/uaccess.h +++ b/arch/blackfin/include/asm/uaccess.h @@ -237,18 +237,18 @@ strncpy_from_user(char *dst, const char __user *src, long count) * On exception, returns 0. * If the string is too long, returns a value greater than n. */ -static inline long __must_check strnlen_user(const char *src, long n) +static inline long __must_check strnlen_user(const char __user *src, long n) { if (!access_ok(VERIFY_READ, src, 1)) return 0; - return strnlen(src, n) + 1; + return strnlen((const char __force *)src, n) + 1; } -static inline long __must_check strlen_user(const char *src) +static inline long __must_check strlen_user(const char __user *src) { if (!access_ok(VERIFY_READ, src, 1)) return 0; - return strlen(src) + 1; + return strlen((const char __force *)src) + 1; } /* -- cgit v0.10.2 From 594fa5c96d6432c292c6baebc56a6500de6b7bc2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 22 Oct 2012 16:09:06 +0200 Subject: Blackfin: twi: Add missing __iomem annotation Add a missing __iomem to the bfin_twi_iface struct's regs_base field. This fixes the following sparse warnings: Fixes the following sparse warnings: drivers/i2c/busses/i2c-bfin-twi.c:641:26: warning: incorrect type in assignment (different address spaces) drivers/i2c/busses/i2c-bfin-twi.c:641:26: expected struct bfin_twi_regs *regs_base drivers/i2c/busses/i2c-bfin-twi.c:641:26: got void [noderef] * drivers/i2c/busses/i2c-bfin-twi.c:715:22: warning: incorrect type in argument 1 (different address spaces) drivers/i2c/busses/i2c-bfin-twi.c:715:22: expected void [noderef] *addr drivers/i2c/busses/i2c-bfin-twi.c:715:22: got struct bfin_twi_regs *regs_base drivers/i2c/busses/i2c-bfin-twi.c:732:22: warning: incorrect type in argument 1 (different address spaces) drivers/i2c/busses/i2c-bfin-twi.c:732:22: expected void [noderef] *addr drivers/i2c/busses/i2c-bfin-twi.c:732:22: got struct bfin_twi_regs *regs_base Signed-off-by: Lars-Peter Clausen Signed-off-by: Bob Liu diff --git a/arch/blackfin/include/asm/bfin_twi.h b/arch/blackfin/include/asm/bfin_twi.h index f4a0727..90c3c00 100644 --- a/arch/blackfin/include/asm/bfin_twi.h +++ b/arch/blackfin/include/asm/bfin_twi.h @@ -61,7 +61,7 @@ struct bfin_twi_iface { int cur_msg; u16 saved_clkdiv; u16 saved_control; - struct bfin_twi_regs *regs_base; + struct bfin_twi_regs __iomem *regs_base; }; #define DEFINE_TWI_REG(reg_name, reg) \ -- cgit v0.10.2 From d69367b1fb63be6f47da974bb3a97fb7c06c6062 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 26 Oct 2012 16:31:02 +0200 Subject: Blackfin: remove unnecessary prototype for kobjsize() The prototype for kobjsize() is already defined in linux/mm.h which is included where kobjsize() is used. Signed-off-by: Tobias Klauser Signed-off-by: Mike Frysinger Signed-off-by: Bob Liu diff --git a/arch/blackfin/include/asm/pgtable.h b/arch/blackfin/include/asm/pgtable.h index dcca3e6..b866392 100644 --- a/arch/blackfin/include/asm/pgtable.h +++ b/arch/blackfin/include/asm/pgtable.h @@ -83,8 +83,6 @@ PTE_BIT_FUNC(mkyoung, |= _PAGE_ACCESSED); #define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) extern char empty_zero_page[]; -extern unsigned int kobjsize(const void *objp); - #define swapper_pg_dir ((pgd_t *) 0) /* * No page table caches to initialise. -- cgit v0.10.2 From 00e9584c765043d6f4385244f03eed0e7fe18287 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 26 Oct 2012 16:31:03 +0200 Subject: Blackfin: remove unused is_in_rom() The function is not used anywhere in the whole tree (anymore), so remove it. Signed-off-by: Tobias Klauser Signed-off-by: Mike Frysinger Signed-off-by: Bob Liu diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h index 3ee7b42..461bb54 100644 --- a/arch/blackfin/include/asm/uaccess.h +++ b/arch/blackfin/include/asm/uaccess.h @@ -34,23 +34,6 @@ static inline void set_fs(mm_segment_t fs) #define access_ok(type, addr, size) _access_ok((unsigned long)(addr), (size)) -static inline int is_in_rom(unsigned long addr) -{ - /* - * What we are really trying to do is determine if addr is - * in an allocated kernel memory region. If not then assume - * we cannot free it or otherwise de-allocate it. Ideally - * we could restrict this to really being in a ROM or flash, - * but that would need to be done on a board by board basis, - * not globally. - */ - if ((addr < _ramstart) || (addr >= _ramend)) - return (1); - - /* Default case, not in ROM */ - return (0); -} - /* * The fs value determines whether argument validity checking should be * performed or not. If get_fs() == USER_DS, checking is performed, with -- cgit v0.10.2 From 4452fec6af8d5ed1dc3ac37f31d7da1bd62733b8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 10 Oct 2012 19:40:19 +0100 Subject: Blackfin: dpmc: use module_platform_driver macro This patch removes some code duplication by using module_platform_driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mike Frysinger Signed-off-by: Bob Liu diff --git a/arch/blackfin/mach-common/dpmc.c b/arch/blackfin/mach-common/dpmc.c index f5685a4..978bb40 100644 --- a/arch/blackfin/mach-common/dpmc.c +++ b/arch/blackfin/mach-common/dpmc.c @@ -157,24 +157,7 @@ struct platform_driver bfin_dpmc_device_driver = { .name = DRIVER_NAME, } }; - -/** - * bfin_dpmc_init - Init driver - */ -static int __init bfin_dpmc_init(void) -{ - return platform_driver_register(&bfin_dpmc_device_driver); -} -module_init(bfin_dpmc_init); - -/** - * bfin_dpmc_exit - break down driver - */ -static void __exit bfin_dpmc_exit(void) -{ - platform_driver_unregister(&bfin_dpmc_device_driver); -} -module_exit(bfin_dpmc_exit); +module_platform_driver(bfin_dpmc_device_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("cpu power management driver for Blackfin"); -- cgit v0.10.2 From f1a1d52508bd29c68a7f77412c0a9cf5e1b51154 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Mon, 29 Oct 2012 13:50:05 +0800 Subject: blackfin: anomaly: add anomaly 16000030 for bf5xx Drivers common to both bf5xx and bf60x chip families may use this anomaly id. So add it to bf5xx header files also. Signed-off-by: Sonic Zhang Signed-off-by: Bob Liu diff --git a/arch/blackfin/mach-bf518/include/mach/anomaly.h b/arch/blackfin/mach-bf518/include/mach/anomaly.h index 845e6bc..46cb882 100644 --- a/arch/blackfin/mach-bf518/include/mach/anomaly.h +++ b/arch/blackfin/mach-bf518/include/mach/anomaly.h @@ -165,5 +165,6 @@ #define ANOMALY_05000474 (0) #define ANOMALY_05000475 (0) #define ANOMALY_05000480 (0) +#define ANOMALY_16000030 (0) #endif diff --git a/arch/blackfin/mach-bf527/include/mach/anomaly.h b/arch/blackfin/mach-bf527/include/mach/anomaly.h index aa14110..2f9cc33 100644 --- a/arch/blackfin/mach-bf527/include/mach/anomaly.h +++ b/arch/blackfin/mach-bf527/include/mach/anomaly.h @@ -285,5 +285,6 @@ #define ANOMALY_05000448 (0) #define ANOMALY_05000474 (0) #define ANOMALY_05000480 (0) +#define ANOMALY_16000030 (0) #endif diff --git a/arch/blackfin/mach-bf533/include/mach/anomaly.h b/arch/blackfin/mach-bf533/include/mach/anomaly.h index 3a8f73a..0e754ef 100644 --- a/arch/blackfin/mach-bf533/include/mach/anomaly.h +++ b/arch/blackfin/mach-bf533/include/mach/anomaly.h @@ -378,5 +378,6 @@ #define ANOMALY_05000474 (0) #define ANOMALY_05000480 (0) #define ANOMALY_05000485 (0) +#define ANOMALY_16000030 (0) #endif diff --git a/arch/blackfin/mach-bf537/include/mach/anomaly.h b/arch/blackfin/mach-bf537/include/mach/anomaly.h index df92126..2bc70c5 100644 --- a/arch/blackfin/mach-bf537/include/mach/anomaly.h +++ b/arch/blackfin/mach-bf537/include/mach/anomaly.h @@ -236,5 +236,6 @@ #define ANOMALY_05000467 (0) #define ANOMALY_05000474 (0) #define ANOMALY_05000485 (0) +#define ANOMALY_16000030 (0) #endif diff --git a/arch/blackfin/mach-bf538/include/mach/anomaly.h b/arch/blackfin/mach-bf538/include/mach/anomaly.h index 318d922..eaac269 100644 --- a/arch/blackfin/mach-bf538/include/mach/anomaly.h +++ b/arch/blackfin/mach-bf538/include/mach/anomaly.h @@ -210,5 +210,6 @@ #define ANOMALY_05000474 (0) #define ANOMALY_05000480 (0) #define ANOMALY_05000485 (0) +#define ANOMALY_16000030 (0) #endif diff --git a/arch/blackfin/mach-bf548/include/mach/anomaly.h b/arch/blackfin/mach-bf548/include/mach/anomaly.h index 5b711d8..098fad6 100644 --- a/arch/blackfin/mach-bf548/include/mach/anomaly.h +++ b/arch/blackfin/mach-bf548/include/mach/anomaly.h @@ -296,5 +296,6 @@ #define ANOMALY_05000440 (0) #define ANOMALY_05000475 (0) #define ANOMALY_05000480 (0) +#define ANOMALY_16000030 (0) #endif diff --git a/arch/blackfin/mach-bf561/include/mach/anomaly.h b/arch/blackfin/mach-bf561/include/mach/anomaly.h index 72476ff..038249c 100644 --- a/arch/blackfin/mach-bf561/include/mach/anomaly.h +++ b/arch/blackfin/mach-bf561/include/mach/anomaly.h @@ -348,5 +348,6 @@ #define ANOMALY_05000474 (0) #define ANOMALY_05000480 (0) #define ANOMALY_05000485 (0) +#define ANOMALY_16000030 (0) #endif -- cgit v0.10.2 From 1439d030b9032261f1111a2dd16b9a8ca11112ef Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 1 Nov 2012 17:07:09 +0800 Subject: blackfin: kgdb: call generic_exec_single() directly Current generic API smp_call_function_single() is changed to avoid raise IPI and call function in IPI handler on the same core which is necessary to support KGDB switch master core in SMP case, so call generic_exec_single() directly instead of smp_call_function_single(). Signed-off-by: Sonic Zhang Signed-off-by: Bob Liu diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c index 9b80b15..b882ce2 100644 --- a/arch/blackfin/kernel/kgdb.c +++ b/arch/blackfin/kernel/kgdb.c @@ -329,6 +329,9 @@ static void bfin_disable_hw_debug(struct pt_regs *regs) } #ifdef CONFIG_SMP +extern void generic_exec_single(int cpu, struct call_single_data *data, int wait); +static struct call_single_data kgdb_smp_ipi_data[NR_CPUS]; + void kgdb_passive_cpu_callback(void *info) { kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs()); @@ -336,12 +339,18 @@ void kgdb_passive_cpu_callback(void *info) void kgdb_roundup_cpus(unsigned long flags) { - smp_call_function(kgdb_passive_cpu_callback, NULL, 0); + unsigned int cpu; + + for (cpu = cpumask_first(cpu_online_mask); cpu < nr_cpu_ids; + cpu = cpumask_next(cpu, cpu_online_mask)) { + kgdb_smp_ipi_data[cpu].func = kgdb_passive_cpu_callback; + generic_exec_single(cpu, &kgdb_smp_ipi_data[cpu], 0); + } } void kgdb_roundup_cpu(int cpu, unsigned long flags) { - smp_call_function_single(cpu, kgdb_passive_cpu_callback, NULL, 0); + generic_exec_single(cpu, &kgdb_smp_ipi_data[cpu], 0); } #endif -- cgit v0.10.2 From 2c935842bdb46f5f557426feb4d2bdfdad1aa5f9 Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Fri, 30 Nov 2012 13:10:39 -0800 Subject: lib/raid6: Add AVX2 optimized gen_syndrome functions Add AVX2 optimized gen_syndrom functions, which is simply based on sse2.c written by hpa. Signed-off-by: Yuanhan Liu Reviewed-by: H. Peter Anvin Signed-off-by: Jim Kukunas Signed-off-by: NeilBrown diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h index 3156347..8dfaa2c 100644 --- a/include/linux/raid/pq.h +++ b/include/linux/raid/pq.h @@ -98,6 +98,9 @@ extern const struct raid6_calls raid6_altivec1; extern const struct raid6_calls raid6_altivec2; extern const struct raid6_calls raid6_altivec4; extern const struct raid6_calls raid6_altivec8; +extern const struct raid6_calls raid6_avx2x1; +extern const struct raid6_calls raid6_avx2x2; +extern const struct raid6_calls raid6_avx2x4; struct raid6_recov_calls { void (*data2)(int, size_t, int, int, void **); diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile index 8c2e22b..3430711 100644 --- a/lib/raid6/Makefile +++ b/lib/raid6/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_RAID6_PQ) += raid6_pq.o raid6_pq-y += algos.o recov.o recov_ssse3.o recov_avx2.o tables.o int1.o int2.o int4.o \ int8.o int16.o int32.o altivec1.o altivec2.o altivec4.o \ - altivec8.o mmx.o sse1.o sse2.o + altivec8.o mmx.o sse1.o sse2.o avx2.o hostprogs-y += mktables quiet_cmd_unroll = UNROLL $@ diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c index 8b7f55c..6d7316f 100644 --- a/lib/raid6/algos.c +++ b/lib/raid6/algos.c @@ -45,11 +45,20 @@ const struct raid6_calls * const raid6_algos[] = { &raid6_sse1x2, &raid6_sse2x1, &raid6_sse2x2, +#ifdef CONFIG_AS_AVX2 + &raid6_avx2x1, + &raid6_avx2x2, +#endif #endif #if defined(__x86_64__) && !defined(__arch_um__) &raid6_sse2x1, &raid6_sse2x2, &raid6_sse2x4, +#ifdef CONFIG_AS_AVX2 + &raid6_avx2x1, + &raid6_avx2x2, + &raid6_avx2x4, +#endif #endif #ifdef CONFIG_ALTIVEC &raid6_altivec1, diff --git a/lib/raid6/avx2.c b/lib/raid6/avx2.c new file mode 100644 index 0000000..bc3b1dd --- /dev/null +++ b/lib/raid6/avx2.c @@ -0,0 +1,251 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 2012 Intel Corporation + * Author: Yuanhan Liu + * + * Based on sse2.c: Copyright 2002 H. Peter Anvin - All Rights Reserved + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * AVX2 implementation of RAID-6 syndrome functions + * + */ + +#ifdef CONFIG_AS_AVX2 + +#include +#include "x86.h" + +static const struct raid6_avx2_constants { + u64 x1d[4]; +} raid6_avx2_constants __aligned(32) = { + { 0x1d1d1d1d1d1d1d1dULL, 0x1d1d1d1d1d1d1d1dULL, + 0x1d1d1d1d1d1d1d1dULL, 0x1d1d1d1d1d1d1d1dULL,}, +}; + +static int raid6_have_avx2(void) +{ + return boot_cpu_has(X86_FEATURE_AVX2) && boot_cpu_has(X86_FEATURE_AVX); +} + +/* + * Plain AVX2 implementation + */ +static void raid6_avx21_gen_syndrome(int disks, size_t bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + u8 *p, *q; + int d, z, z0; + + z0 = disks - 3; /* Highest data disk */ + p = dptr[z0+1]; /* XOR parity */ + q = dptr[z0+2]; /* RS syndrome */ + + kernel_fpu_begin(); + + asm volatile("vmovdqa %0,%%ymm0" : : "m" (raid6_avx2_constants.x1d[0])); + asm volatile("vpxor %ymm3,%ymm3,%ymm3"); /* Zero temp */ + + for (d = 0; d < bytes; d += 32) { + asm volatile("prefetchnta %0" : : "m" (dptr[z0][d])); + asm volatile("vmovdqa %0,%%ymm2" : : "m" (dptr[z0][d]));/* P[0] */ + asm volatile("prefetchnta %0" : : "m" (dptr[z0-1][d])); + asm volatile("vmovdqa %ymm2,%ymm4");/* Q[0] */ + asm volatile("vmovdqa %0,%%ymm6" : : "m" (dptr[z0-1][d])); + for (z = z0-2; z >= 0; z--) { + asm volatile("prefetchnta %0" : : "m" (dptr[z][d])); + asm volatile("vpcmpgtb %ymm4,%ymm3,%ymm5"); + asm volatile("vpaddb %ymm4,%ymm4,%ymm4"); + asm volatile("vpand %ymm0,%ymm5,%ymm5"); + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); + asm volatile("vpxor %ymm6,%ymm2,%ymm2"); + asm volatile("vpxor %ymm6,%ymm4,%ymm4"); + asm volatile("vmovdqa %0,%%ymm6" : : "m" (dptr[z][d])); + } + asm volatile("vpcmpgtb %ymm4,%ymm3,%ymm5"); + asm volatile("vpaddb %ymm4,%ymm4,%ymm4"); + asm volatile("vpand %ymm0,%ymm5,%ymm5"); + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); + asm volatile("vpxor %ymm6,%ymm2,%ymm2"); + asm volatile("vpxor %ymm6,%ymm4,%ymm4"); + + asm volatile("vmovntdq %%ymm2,%0" : "=m" (p[d])); + asm volatile("vpxor %ymm2,%ymm2,%ymm2"); + asm volatile("vmovntdq %%ymm4,%0" : "=m" (q[d])); + asm volatile("vpxor %ymm4,%ymm4,%ymm4"); + } + + asm volatile("sfence" : : : "memory"); + kernel_fpu_end(); +} + +const struct raid6_calls raid6_avx2x1 = { + raid6_avx21_gen_syndrome, + raid6_have_avx2, + "avx2x1", + 1 /* Has cache hints */ +}; + +/* + * Unrolled-by-2 AVX2 implementation + */ +static void raid6_avx22_gen_syndrome(int disks, size_t bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + u8 *p, *q; + int d, z, z0; + + z0 = disks - 3; /* Highest data disk */ + p = dptr[z0+1]; /* XOR parity */ + q = dptr[z0+2]; /* RS syndrome */ + + kernel_fpu_begin(); + + asm volatile("vmovdqa %0,%%ymm0" : : "m" (raid6_avx2_constants.x1d[0])); + asm volatile("vpxor %ymm1,%ymm1,%ymm1"); /* Zero temp */ + + /* We uniformly assume a single prefetch covers at least 32 bytes */ + for (d = 0; d < bytes; d += 64) { + asm volatile("prefetchnta %0" : : "m" (dptr[z0][d])); + asm volatile("prefetchnta %0" : : "m" (dptr[z0][d+32])); + asm volatile("vmovdqa %0,%%ymm2" : : "m" (dptr[z0][d]));/* P[0] */ + asm volatile("vmovdqa %0,%%ymm3" : : "m" (dptr[z0][d+32]));/* P[1] */ + asm volatile("vmovdqa %ymm2,%ymm4"); /* Q[0] */ + asm volatile("vmovdqa %ymm3,%ymm6"); /* Q[1] */ + for (z = z0-1; z >= 0; z--) { + asm volatile("prefetchnta %0" : : "m" (dptr[z][d])); + asm volatile("prefetchnta %0" : : "m" (dptr[z][d+32])); + asm volatile("vpcmpgtb %ymm4,%ymm1,%ymm5"); + asm volatile("vpcmpgtb %ymm6,%ymm1,%ymm7"); + asm volatile("vpaddb %ymm4,%ymm4,%ymm4"); + asm volatile("vpaddb %ymm6,%ymm6,%ymm6"); + asm volatile("vpand %ymm0,%ymm5,%ymm5"); + asm volatile("vpand %ymm0,%ymm7,%ymm7"); + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); + asm volatile("vpxor %ymm7,%ymm6,%ymm6"); + asm volatile("vmovdqa %0,%%ymm5" : : "m" (dptr[z][d])); + asm volatile("vmovdqa %0,%%ymm7" : : "m" (dptr[z][d+32])); + asm volatile("vpxor %ymm5,%ymm2,%ymm2"); + asm volatile("vpxor %ymm7,%ymm3,%ymm3"); + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); + asm volatile("vpxor %ymm7,%ymm6,%ymm6"); + } + asm volatile("vmovntdq %%ymm2,%0" : "=m" (p[d])); + asm volatile("vmovntdq %%ymm3,%0" : "=m" (p[d+32])); + asm volatile("vmovntdq %%ymm4,%0" : "=m" (q[d])); + asm volatile("vmovntdq %%ymm6,%0" : "=m" (q[d+32])); + } + + asm volatile("sfence" : : : "memory"); + kernel_fpu_end(); +} + +const struct raid6_calls raid6_avx2x2 = { + raid6_avx22_gen_syndrome, + raid6_have_avx2, + "avx2x2", + 1 /* Has cache hints */ +}; + +#ifdef CONFIG_X86_64 + +/* + * Unrolled-by-4 AVX2 implementation + */ +static void raid6_avx24_gen_syndrome(int disks, size_t bytes, void **ptrs) +{ + u8 **dptr = (u8 **)ptrs; + u8 *p, *q; + int d, z, z0; + + z0 = disks - 3; /* Highest data disk */ + p = dptr[z0+1]; /* XOR parity */ + q = dptr[z0+2]; /* RS syndrome */ + + kernel_fpu_begin(); + + asm volatile("vmovdqa %0,%%ymm0" : : "m" (raid6_avx2_constants.x1d[0])); + asm volatile("vpxor %ymm1,%ymm1,%ymm1"); /* Zero temp */ + asm volatile("vpxor %ymm2,%ymm2,%ymm2"); /* P[0] */ + asm volatile("vpxor %ymm3,%ymm3,%ymm3"); /* P[1] */ + asm volatile("vpxor %ymm4,%ymm4,%ymm4"); /* Q[0] */ + asm volatile("vpxor %ymm6,%ymm6,%ymm6"); /* Q[1] */ + asm volatile("vpxor %ymm10,%ymm10,%ymm10"); /* P[2] */ + asm volatile("vpxor %ymm11,%ymm11,%ymm11"); /* P[3] */ + asm volatile("vpxor %ymm12,%ymm12,%ymm12"); /* Q[2] */ + asm volatile("vpxor %ymm14,%ymm14,%ymm14"); /* Q[3] */ + + for (d = 0; d < bytes; d += 128) { + for (z = z0; z >= 0; z--) { + asm volatile("prefetchnta %0" : : "m" (dptr[z][d])); + asm volatile("prefetchnta %0" : : "m" (dptr[z][d+32])); + asm volatile("prefetchnta %0" : : "m" (dptr[z][d+64])); + asm volatile("prefetchnta %0" : : "m" (dptr[z][d+96])); + asm volatile("vpcmpgtb %ymm4,%ymm1,%ymm5"); + asm volatile("vpcmpgtb %ymm6,%ymm1,%ymm7"); + asm volatile("vpcmpgtb %ymm12,%ymm1,%ymm13"); + asm volatile("vpcmpgtb %ymm14,%ymm1,%ymm15"); + asm volatile("vpaddb %ymm4,%ymm4,%ymm4"); + asm volatile("vpaddb %ymm6,%ymm6,%ymm6"); + asm volatile("vpaddb %ymm12,%ymm12,%ymm12"); + asm volatile("vpaddb %ymm14,%ymm14,%ymm14"); + asm volatile("vpand %ymm0,%ymm5,%ymm5"); + asm volatile("vpand %ymm0,%ymm7,%ymm7"); + asm volatile("vpand %ymm0,%ymm13,%ymm13"); + asm volatile("vpand %ymm0,%ymm15,%ymm15"); + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); + asm volatile("vpxor %ymm7,%ymm6,%ymm6"); + asm volatile("vpxor %ymm13,%ymm12,%ymm12"); + asm volatile("vpxor %ymm15,%ymm14,%ymm14"); + asm volatile("vmovdqa %0,%%ymm5" : : "m" (dptr[z][d])); + asm volatile("vmovdqa %0,%%ymm7" : : "m" (dptr[z][d+32])); + asm volatile("vmovdqa %0,%%ymm13" : : "m" (dptr[z][d+64])); + asm volatile("vmovdqa %0,%%ymm15" : : "m" (dptr[z][d+96])); + asm volatile("vpxor %ymm5,%ymm2,%ymm2"); + asm volatile("vpxor %ymm7,%ymm3,%ymm3"); + asm volatile("vpxor %ymm13,%ymm10,%ymm10"); + asm volatile("vpxor %ymm15,%ymm11,%ymm11"); + asm volatile("vpxor %ymm5,%ymm4,%ymm4"); + asm volatile("vpxor %ymm7,%ymm6,%ymm6"); + asm volatile("vpxor %ymm13,%ymm12,%ymm12"); + asm volatile("vpxor %ymm15,%ymm14,%ymm14"); + } + asm volatile("vmovntdq %%ymm2,%0" : "=m" (p[d])); + asm volatile("vpxor %ymm2,%ymm2,%ymm2"); + asm volatile("vmovntdq %%ymm3,%0" : "=m" (p[d+32])); + asm volatile("vpxor %ymm3,%ymm3,%ymm3"); + asm volatile("vmovntdq %%ymm10,%0" : "=m" (p[d+64])); + asm volatile("vpxor %ymm10,%ymm10,%ymm10"); + asm volatile("vmovntdq %%ymm11,%0" : "=m" (p[d+96])); + asm volatile("vpxor %ymm11,%ymm11,%ymm11"); + asm volatile("vmovntdq %%ymm4,%0" : "=m" (q[d])); + asm volatile("vpxor %ymm4,%ymm4,%ymm4"); + asm volatile("vmovntdq %%ymm6,%0" : "=m" (q[d+32])); + asm volatile("vpxor %ymm6,%ymm6,%ymm6"); + asm volatile("vmovntdq %%ymm12,%0" : "=m" (q[d+64])); + asm volatile("vpxor %ymm12,%ymm12,%ymm12"); + asm volatile("vmovntdq %%ymm14,%0" : "=m" (q[d+96])); + asm volatile("vpxor %ymm14,%ymm14,%ymm14"); + } + + asm volatile("sfence" : : : "memory"); + kernel_fpu_end(); +} + +const struct raid6_calls raid6_avx2x4 = { + raid6_avx24_gen_syndrome, + raid6_have_avx2, + "avx2x4", + 1 /* Has cache hints */ +}; +#endif + +#endif /* CONFIG_AS_AVX2 */ diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile index d919c98..754cbac 100644 --- a/lib/raid6/test/Makefile +++ b/lib/raid6/test/Makefile @@ -11,6 +11,16 @@ AWK = awk -f AR = ar RANLIB = ranlib +ARCH := $(shell uname -m 2>/dev/null | sed -e /s/i.86/i386/) +ifeq ($(ARCH),i386) + CFLAGS += -DCONFIG_X86_32 +endif +ifeq ($(ARCH),x86_64) + CFLAGS += -DCONFIG_X86_64 +endif +CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1"| gcc -c -x assembler - &&\ + rm ./-.o && echo -DCONFIG_AS_AVX2=1) + .c.o: $(CC) $(CFLAGS) -c -o $@ $< @@ -22,7 +32,7 @@ RANLIB = ranlib all: raid6.a raid6test -raid6.a: int1.o int2.o int4.o int8.o int16.o int32.o mmx.o sse1.o sse2.o \ +raid6.a: int1.o int2.o int4.o int8.o int16.o int32.o mmx.o sse1.o sse2.o avx2.o \ altivec1.o altivec2.o altivec4.o altivec8.o recov.o recov_ssse3.o recov_avx2.o algos.o \ tables.o rm -f $@ -- cgit v0.10.2 From 4f8c55c5ad491dbc7b52ce08bb702ca39ce944cf Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Fri, 30 Nov 2012 13:10:40 -0800 Subject: lib/raid6: build proper files on corresponding arch sse and avx2 stuff only exist on x86 arch, and we don't need to build altivec on x86. And we can do that at lib/raid6/Makefile. Proposed-by: H. Peter Anvin Signed-off-by: Yuanhan Liu Reviewed-by: H. Peter Anvin Signed-off-by: Jim Kukunas Signed-off-by: NeilBrown diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile index 3430711..9f7c184 100644 --- a/lib/raid6/Makefile +++ b/lib/raid6/Makefile @@ -1,8 +1,11 @@ obj-$(CONFIG_RAID6_PQ) += raid6_pq.o -raid6_pq-y += algos.o recov.o recov_ssse3.o recov_avx2.o tables.o int1.o int2.o int4.o \ - int8.o int16.o int32.o altivec1.o altivec2.o altivec4.o \ - altivec8.o mmx.o sse1.o sse2.o avx2.o +raid6_pq-y += algos.o recov.o tables.o int1.o int2.o int4.o \ + int8.o int16.o int32.o + +raid6_pq-$(CONFIG_X86) += recov_ssse3.o recov_avx2.o mmx.o sse1.o sse2.o avx2.o +raid6_pq-$(CONFIG_ALTIVEC) += altivec1.o altivec2.o altivec4.o altivec8.o + hostprogs-y += mktables quiet_cmd_unroll = UNROLL $@ diff --git a/lib/raid6/altivec.uc b/lib/raid6/altivec.uc index b71012b..7cc12b5 100644 --- a/lib/raid6/altivec.uc +++ b/lib/raid6/altivec.uc @@ -24,13 +24,10 @@ #include -#ifdef CONFIG_ALTIVEC - #include #ifdef __KERNEL__ # include # include -#endif /* * This is the C data type to use. We use a vector of diff --git a/lib/raid6/mmx.c b/lib/raid6/mmx.c index 279347f..590c71c 100644 --- a/lib/raid6/mmx.c +++ b/lib/raid6/mmx.c @@ -16,7 +16,7 @@ * MMX implementation of RAID-6 syndrome functions */ -#if defined(__i386__) && !defined(__arch_um__) +#ifdef CONFIG_X86_32 #include #include "x86.h" diff --git a/lib/raid6/recov_avx2.c b/lib/raid6/recov_avx2.c index 43a9bab..e1eea43 100644 --- a/lib/raid6/recov_avx2.c +++ b/lib/raid6/recov_avx2.c @@ -8,8 +8,6 @@ * of the License. */ -#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__) - #if CONFIG_AS_AVX2 #include @@ -323,5 +321,3 @@ const struct raid6_recov_calls raid6_recov_avx2 = { #else #warning "your version of binutils lacks AVX2 support" #endif - -#endif diff --git a/lib/raid6/recov_ssse3.c b/lib/raid6/recov_ssse3.c index ecb710c..a916832 100644 --- a/lib/raid6/recov_ssse3.c +++ b/lib/raid6/recov_ssse3.c @@ -7,8 +7,6 @@ * of the License. */ -#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__) - #include #include "x86.h" @@ -332,5 +330,3 @@ const struct raid6_recov_calls raid6_recov_ssse3 = { #endif .priority = 1, }; - -#endif diff --git a/lib/raid6/sse1.c b/lib/raid6/sse1.c index 10dd9194..f762971 100644 --- a/lib/raid6/sse1.c +++ b/lib/raid6/sse1.c @@ -21,7 +21,7 @@ * worthwhile as a separate implementation. */ -#if defined(__i386__) && !defined(__arch_um__) +#ifdef CONFIG_X86_32 #include #include "x86.h" diff --git a/lib/raid6/sse2.c b/lib/raid6/sse2.c index bc2d57d..85b82c8 100644 --- a/lib/raid6/sse2.c +++ b/lib/raid6/sse2.c @@ -17,8 +17,6 @@ * */ -#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__) - #include #include "x86.h" @@ -159,9 +157,7 @@ const struct raid6_calls raid6_sse2x2 = { 1 /* Has cache hints */ }; -#endif - -#if defined(__x86_64__) && !defined(__arch_um__) +#ifdef CONFIG_X86_64 /* * Unrolled-by-4 SSE2 implementation @@ -259,4 +255,4 @@ const struct raid6_calls raid6_sse2x4 = { 1 /* Has cache hints */ }; -#endif +#endif /* CONFIG_X86_64 */ diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile index 754cbac..087332d 100644 --- a/lib/raid6/test/Makefile +++ b/lib/raid6/test/Makefile @@ -10,16 +10,31 @@ LD = ld AWK = awk -f AR = ar RANLIB = ranlib +OBJS = int1.o int2.o int4.o int8.o int16.o int32.o recov.o algos.o tables.o ARCH := $(shell uname -m 2>/dev/null | sed -e /s/i.86/i386/) ifeq ($(ARCH),i386) CFLAGS += -DCONFIG_X86_32 + IS_X86 = yes endif ifeq ($(ARCH),x86_64) CFLAGS += -DCONFIG_X86_64 + IS_X86 = yes +endif + +ifeq ($(IS_X86),yes) + OBJS += mmx.o sse1.o sse2.o avx2.o recov_ssse3.o recov_avx2.o + CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1" | \ + gcc -c -x assembler - >&/dev/null && \ + rm ./-.o && echo -DCONFIG_AS_AVX2=1) +else + HAS_ALTIVEC := $(shell echo -e '\#include \nvector int a;' |\ + gcc -c -x c - >&/dev/null && \ + rm ./-.o && echo yes) + ifeq ($(HAS_ALTIVEC),yes) + OBJS += altivec1.o altivec2.o altivec4.o altivec8.o + endif endif -CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1"| gcc -c -x assembler - &&\ - rm ./-.o && echo -DCONFIG_AS_AVX2=1) .c.o: $(CC) $(CFLAGS) -c -o $@ $< @@ -32,9 +47,7 @@ CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1"| gcc -c -x assembler - &&\ all: raid6.a raid6test -raid6.a: int1.o int2.o int4.o int8.o int16.o int32.o mmx.o sse1.o sse2.o avx2.o \ - altivec1.o altivec2.o altivec4.o altivec8.o recov.o recov_ssse3.o recov_avx2.o algos.o \ - tables.o +raid6.a: $(OBJS) rm -f $@ $(AR) cq $@ $^ $(RANLIB) $@ -- cgit v0.10.2 From 0a19caabf01ac138bf3668786939e50ea4d9c8ac Mon Sep 17 00:00:00 2001 From: majianpeng Date: Mon, 19 Nov 2012 19:57:34 +0800 Subject: md: Use ->curr_resync as last completed request when cleanly aborting resync. If a resync is aborted cleanly, ->curr_resync is a reliable record of where we got up to. If there was an error it is less reliable but we always know that ->curr_resync_completed is safe. So add a flag MD_RECOVERY_ERROR to differentiate between these cases and set recovery_cp accordingly. Signed-off-by: Jianpeng Ma Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index 6aefa44..30ba223 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7180,6 +7180,7 @@ void md_done_sync(struct mddev *mddev, int blocks, int ok) wake_up(&mddev->recovery_wait); if (!ok) { set_bit(MD_RECOVERY_INTR, &mddev->recovery); + set_bit(MD_RECOVERY_ERROR, &mddev->recovery); md_wakeup_thread(mddev->thread); // stop recovery, signal do_sync .... } @@ -7574,8 +7575,13 @@ void md_do_sync(struct md_thread *thread) printk(KERN_INFO "md: checkpointing %s of %s.\n", desc, mdname(mddev)); - mddev->recovery_cp = - mddev->curr_resync_completed; + if (test_bit(MD_RECOVERY_ERROR, + &mddev->recovery)) + mddev->recovery_cp = + mddev->curr_resync_completed; + else + mddev->recovery_cp = + mddev->curr_resync; } } else mddev->recovery_cp = MaxSector; diff --git a/drivers/md/md.h b/drivers/md/md.h index af443ab..c29e62e 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -307,6 +307,7 @@ struct mddev { * REQUEST: user-space has requested a sync (used with SYNC) * CHECK: user-space request for check-only, no repair * RESHAPE: A reshape is happening + * ERROR: sync-action interrupted because io-error * * If neither SYNC or RESHAPE are set, then it is a recovery. */ @@ -320,6 +321,7 @@ struct mddev { #define MD_RECOVERY_CHECK 7 #define MD_RECOVERY_RESHAPE 8 #define MD_RECOVERY_FROZEN 9 +#define MD_RECOVERY_ERROR 10 unsigned long recovery; /* If a RAID personality determines that recovery (of a particular -- cgit v0.10.2 From 749586b7d34df910118bff2c248d08877d772e81 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 20 Nov 2012 14:11:15 +1100 Subject: md/raid5: use async_tx_quiesce() instead of open-coding it. handle_stripe_expansion contains: if (tx) { async_tx_ack(tx); dma_wait_for_async_tx(tx); } which is very similar to the body of async_tx_quiesce(), except that the later handles an error from dma_wait_for_async_tx() (admittedly by panicing, but that decision belongs in the dma code, not the md code). So just us async_tx_quiesce(). Acked-by: Dan Williams Reported-by: Bartlomiej Zolnierkiewicz Signed-off-by: NeilBrown diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a450268..2cf23f2 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3224,10 +3224,7 @@ static void handle_stripe_expansion(struct r5conf *conf, struct stripe_head *sh) } /* done submitting copies, wait for them to complete */ - if (tx) { - async_tx_ack(tx); - dma_wait_for_async_tx(tx); - } + async_tx_quiesce(&tx); } /* -- cgit v0.10.2 From 1604c1e760119ab3fe9f71679ebaeb058d3d8ae1 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Mon, 10 Dec 2012 14:28:13 -0800 Subject: usb: dwc3: debugfs: fix regdump offset As with dwc_readl/writel, the global registers are specified as offsets starting from the beginning of the xHCI address space, but the memory region pointed to by dwc->regs already maps to the start of the global addresses. Fix by offsetting each of the regs relative to DWC3_GLOBALS_REGS_START. Signed-off-by: Jack Pham Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 92604b4..5945aad 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -56,7 +56,7 @@ #define dump_register(nm) \ { \ .name = __stringify(nm), \ - .offset = DWC3_ ##nm, \ + .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \ } static const struct debugfs_reg32 dwc3_regs[] = { -- cgit v0.10.2 From 584829459bd4421f0f57d11a6ceeef096ec81d08 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Dec 2012 22:43:45 -0800 Subject: usb: renesas_usbhs: gadget: remove usbhsg_uep_init() Current driver always initialized uep->pipe to NULL on usbhsg_try_start(). But it breaks relationship with usb_ep_ops :: enable/disable functions when suspend/resume. This patch solved this issue by initializing uep->pipe on probe() Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index dd41f61..c6942d7 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -545,15 +545,6 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep) return 0; } -static void usbhsg_uep_init(struct usbhsg_gpriv *gpriv) -{ - int i; - struct usbhsg_uep *uep; - - usbhsg_for_each_uep_with_dcp(uep, gpriv, i) - uep->pipe = NULL; -} - /* * * usb_ep_ops @@ -761,7 +752,6 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) usbhs_pipe_init(priv, usbhsg_dma_map_ctrl); usbhs_fifo_init(priv); - usbhsg_uep_init(gpriv); /* dcp init */ dcp->pipe = usbhs_dcp_malloc(priv); @@ -998,6 +988,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) */ usbhsg_for_each_uep_with_dcp(uep, gpriv, i) { uep->gpriv = gpriv; + uep->pipe = NULL; snprintf(uep->ep_name, EP_NAME_SIZE, "ep%d", i); uep->ep.name = uep->ep_name; -- cgit v0.10.2 From b33d74db39aae32e7d57265e25c94a488c42e37b Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Tue, 4 Dec 2012 14:26:11 +0100 Subject: USB: fix fsl_otg config dependency USB_GADGET_FSL_USB2 has been changed to USB_FSL_USB2 by commit 193ab2a6070039e7ee2b9b9bebea754a7c52fd1b (usb: gadget: allow multiple gadgets to be built). But old USB_GADGET_FSL_USB2 is still listed as dependency for fsl_otg driver, so the driver cannot be selected in the configuration currently. Fix it. Signed-off-by: Anatolij Gustschin Signed-off-by: Felipe Balbi diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 6223062..37962c9 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig @@ -110,7 +110,7 @@ config AB8500_USB config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" - depends on USB_EHCI_FSL && USB_GADGET_FSL_USB2 && USB_SUSPEND + depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND select USB_OTG select USB_OTG_UTILS help -- cgit v0.10.2 From e887786a466f36720fde5d4a1bc3c7dacd400bd1 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Tue, 27 Nov 2012 22:06:02 -0500 Subject: usb: gadget: mv_udc: fix the clk APIs the clock common driver changes, and arch-mmp will make use of the common clock driver instead of its own. So for enable clock. first prepare the clock then enable the clock. for disable clock first disable the clock then unprepare the clock Signed-off-by: Chao Xie Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 379aac7..6e8b127 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1012,7 +1012,7 @@ static void udc_clock_enable(struct mv_udc *udc) unsigned int i; for (i = 0; i < udc->clknum; i++) - clk_enable(udc->clk[i]); + clk_prepare_enable(udc->clk[i]); } static void udc_clock_disable(struct mv_udc *udc) @@ -1020,7 +1020,7 @@ static void udc_clock_disable(struct mv_udc *udc) unsigned int i; for (i = 0; i < udc->clknum; i++) - clk_disable(udc->clk[i]); + clk_disable_unprepare(udc->clk[i]); } static void udc_stop(struct mv_udc *udc) -- cgit v0.10.2 From c1a96ebd315f82fa0f47adce264adb126cf72764 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Tue, 27 Nov 2012 22:06:05 -0500 Subject: usb: host: ehci-mv: fix clk APIs the clock common driver changes, and arch-mmp will make use of the common clock driver instead of its own. So for enable clock. first prepare the clock then enable the clock. for disable clock first disable the clock then unprepare the clock Signed-off-by: Chao Xie Acked-by: Alan Stern Signed-off-by: Felipe Balbi diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index f7bfc0b..6c56297 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -43,7 +43,7 @@ static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) unsigned int i; for (i = 0; i < ehci_mv->clknum; i++) - clk_enable(ehci_mv->clk[i]); + clk_prepare_enable(ehci_mv->clk[i]); } static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) @@ -51,7 +51,7 @@ static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) unsigned int i; for (i = 0; i < ehci_mv->clknum; i++) - clk_disable(ehci_mv->clk[i]); + clk_disable_unprepare(ehci_mv->clk[i]); } static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) -- cgit v0.10.2 From 69f5165ebef1d90bd58e9ce5db018218ea4d089c Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 22 Nov 2012 13:55:16 +0530 Subject: usb: gadget: s3c-hsotg: Fix invalid free of devm_ allocated data Since hsotg object is allocated using devm_kzalloc() API, there is no need to free this explicitly. But we need to keep the release API to prevent warnings. Signed-off-by: Tushar Behera Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 141971d..439c3f9 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -3477,12 +3477,11 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) /** * s3c_hsotg_release - release callback for hsotg device * @dev: Device to for which release is called + * + * Nothing to do as the resource is allocated using devm_ API. */ static void s3c_hsotg_release(struct device *dev) { - struct s3c_hsotg *hsotg = dev_get_drvdata(dev); - - kfree(hsotg); } /** -- cgit v0.10.2 From d9fa298f215e050dbb28a6f75fe76459ebd2e7f0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Dec 2012 22:44:07 -0800 Subject: usb: renesas_usbhs: gadget: usbhsg_ep_disable() care pipe settings Current usbhsg_ep_disable() didn't care uep->pipe and pipe->mod_private variable which is used on usbhsg_ep_enable(). It breaks renesas_usbhs gadget when resume. This patch fixes it. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index c6942d7..f2985cd 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -601,7 +601,12 @@ static int usbhsg_ep_disable(struct usb_ep *ep) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); - return usbhsg_pipe_disable(uep); + usbhsg_pipe_disable(uep); + + uep->pipe->mod_private = NULL; + uep->pipe = NULL; + + return 0; } static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, @@ -753,7 +758,7 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) usbhsg_dma_map_ctrl); usbhs_fifo_init(priv); - /* dcp init */ + /* dcp init instead of usbhsg_ep_enable() */ dcp->pipe = usbhs_dcp_malloc(priv); dcp->pipe->mod_private = dcp; usbhs_pipe_config_update(dcp->pipe, 0, 0, 64); @@ -815,7 +820,7 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) usbhs_sys_set_test_mode(priv, 0); usbhs_sys_function_ctrl(priv, 0); - usbhsg_pipe_disable(dcp); + usbhsg_ep_disable(&dcp->ep); dev_dbg(dev, "stop gadget\n"); -- cgit v0.10.2 From e0b64ce6fe0a9d4ce8cf97fea7fe5ec7125dea30 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 9 Dec 2012 21:06:37 -0800 Subject: usb: renesas_usbhs: mod_host: fixup usbhsh_ureq_free() timing usbhsh_ureq_free() free ureq which includes ubshs_pkt. But current driver used usbhs_pkt after freed ureq. This patch fixup this bug. Special thanks to Chen Reported-by: Chen Gang Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 3d3cd6c..b868154 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -661,9 +661,10 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) status = -ESHUTDOWN; urb->actual_length = pkt->actual; - usbhsh_ureq_free(hpriv, ureq); usbhsh_endpoint_sequence_save(hpriv, urb, pkt); + usbhsh_ureq_free(hpriv, ureq); + usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep)); usb_hcd_unlink_urb_from_ep(hcd, urb); -- cgit v0.10.2 From e3f1dbd21ddfaa22649b93212d5ac4b052c1e4a7 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Tue, 27 Nov 2012 22:06:04 -0500 Subject: usb: otg: mv_otg: fix the clk APIs the clock common driver changes, and arch-mmp will make use of the common clock driver instead of its own. So for enable clock. first prepare the clock then enable the clock. for disable clock first disable the clock then unprepare the clock Signed-off-by: Chao Xie Signed-off-by: Felipe Balbi diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c index 1dd5750..eace975 100644 --- a/drivers/usb/otg/mv_otg.c +++ b/drivers/usb/otg/mv_otg.c @@ -240,7 +240,7 @@ static void otg_clock_enable(struct mv_otg *mvotg) unsigned int i; for (i = 0; i < mvotg->clknum; i++) - clk_enable(mvotg->clk[i]); + clk_prepare_enable(mvotg->clk[i]); } static void otg_clock_disable(struct mv_otg *mvotg) @@ -248,7 +248,7 @@ static void otg_clock_disable(struct mv_otg *mvotg) unsigned int i; for (i = 0; i < mvotg->clknum; i++) - clk_disable(mvotg->clk[i]); + clk_disable_unprepare(mvotg->clk[i]); } static int mv_otg_enable_internal(struct mv_otg *mvotg) -- cgit v0.10.2 From 1d16638e3b9cc195bac18a8fcbca748f33c1bc24 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 20 Nov 2012 13:23:15 +0100 Subject: usb: gadget: dummy: fix enumeration with g_multi If we do have endpoints named like "ep-a" then bEndpointAddress is counted internally by the gadget framework. If we do have endpoints named like "ep-1" then bEndpointAddress is assigned from the digit after "ep-". If we do have both, then it is likely that after we used up the "generic" endpoints we will use the digits and thus assign one bEndpointAddress to multiple endpoints. This theory can be proofed by using the completely enabled g_multi. Without this patch, the mass storage won't enumerate and times out because it shares endpoints with RNDIS. This patch also adds fills up the endpoints list so we have in total endpoints 1 to 15 in + out available while some of them are restricted to certain types like BULK or ISO. Without this change the nokia gadget won't load because the system does not provide enough (BULK) endpoints but it did before ep-a - ep-f were removed. Cc: stable@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Acked-by: Alan Stern Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 95d584d..8cf0c0f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -130,10 +130,7 @@ static const char ep0name[] = "ep0"; static const char *const ep_name[] = { ep0name, /* everyone has ep0 */ - /* act like a net2280: high speed, six configurable endpoints */ - "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", - - /* or like pxa250: fifteen fixed function endpoints */ + /* act like a pxa250: fifteen fixed function endpoints */ "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", @@ -141,6 +138,10 @@ static const char *const ep_name[] = { /* or like sa1100: two fixed function endpoints */ "ep1out-bulk", "ep2in-bulk", + + /* and now some generic EPs so we have enough in multi config */ + "ep3out", "ep4in", "ep5out", "ep6out", "ep7in", "ep8out", "ep9in", + "ep10out", "ep11out", "ep12in", "ep13out", "ep14in", "ep15out", }; #define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) -- cgit v0.10.2 From deeeb9ee1ed5b06864f530c6123976209badd489 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Tue, 27 Nov 2012 20:15:22 +0530 Subject: usb: musb: dsps: header movement build error fix "54db6ee ARM: OMAP2+: Introduce local usb.h" moved control module bit definitions from plat/usb.h (which dsps glue was using) to a local header in mach-omap2. And in parallel, "c68bb4c usb: musb: dsps: control module handling (quirk)" added control module handling capability to dsps glue driver that used those control module bit definitions. Integration of above two changes would cause build error in musb dsps glue driver (they go through different trees upstream) as is seen now in linux-next. Fix it by adding necessary definitions in dsps glue driver. Signed-off-by: Afzal Mohammed Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index e6f2ae8..f7d764d 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -134,6 +134,11 @@ static const resource_size_t dsps_control_module_phys[] = { DSPS_AM33XX_CONTROL_MODULE_PHYS_1, }; +#define USBPHY_CM_PWRDN (1 << 0) +#define USBPHY_OTG_PWRDN (1 << 1) +#define USBPHY_OTGVDET_EN (1 << 19) +#define USBPHY_OTGSESSEND_EN (1 << 20) + /** * musb_dsps_phy_control - phy on/off * @glue: struct dsps_glue * -- cgit v0.10.2 From 25e14c1fcce5c66b0d2d5e35fad35d044dc320ae Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Thu, 15 Nov 2012 04:21:01 -0500 Subject: usb: gadget: amd5536udc: avoid NULL pointer dereference in udc_pci_probe() dev->pdev is NULL before `dev->pdev = pdev'; use pdev instead. Signed-off-by: Xi Wang Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index fc0ec5e..d9f6b93 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3231,7 +3231,7 @@ static int udc_pci_probe( } if (!pdev->irq) { - dev_err(&dev->pdev->dev, "irq not set\n"); + dev_err(&pdev->dev, "irq not set\n"); kfree(dev); dev = NULL; retval = -ENODEV; @@ -3250,7 +3250,7 @@ static int udc_pci_probe( dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { - dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq); + dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq); kfree(dev); dev = NULL; retval = -EBUSY; -- cgit v0.10.2 From 5dbd693576726bd7d3228ee614060e0817305dde Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 14 Nov 2012 13:47:23 +0800 Subject: usb: gadget: tcm_usb_gadge: fix to return error or 0 in tcm_usbg_drop_nexus() In the error handling case of tcm_usbg_drop_nexus(), the error code is assigned to 'ret', but it is ignored. We'd better return 'ret' instead of always return 0. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 4f7f76f..7cacd6a 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -1794,9 +1794,10 @@ static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg) tpg->tpg_nexus = NULL; kfree(tv_nexus); + ret = 0; out: mutex_unlock(&tpg->tpg_mutex); - return 0; + return ret; } static ssize_t tcm_usbg_tpg_store_nexus( -- cgit v0.10.2 From 484ca3a35b43a5127f0ef8e8c816f1b2ab6ce323 Mon Sep 17 00:00:00 2001 From: Haipeng YU Date: Wed, 14 Nov 2012 15:40:01 +0100 Subject: usb: gadget: u_serial: fix switch off blocked When a device is switched off by software, gserial_cleanup will be called, and switch off will be blocked in this function because wake_up_interruptible() in gs_close() can not wake_up the wait_event() in gserial_cleanup(), it should be changed to wake_up() to match the wait_event(). Signed-off-by: Haipeng YU Signed-off-by: Linus Walleij Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index d0f9548..598dcc1 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -887,7 +887,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", port->port_num, tty, file); - wake_up_interruptible(&port->port.close_wait); + wake_up(&port->port.close_wait); exit: spin_unlock_irq(&port->port_lock); } -- cgit v0.10.2 From 2ac788f705e5118dd45204e7a5bc8d5bb6873835 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 14 Nov 2012 18:49:50 +0300 Subject: usb: musb: core: print new line in the driver banner again Commit 5c8a86e10a7c164f44537fabdc169fd8b4e7a440 (usb: musb: drop unneeded musb_debug trickery) erroneously removed '\n' from the driver's banner. Concatenate all the banner substrings while adding it back... Signed-off-by: Sergei Shtylyov Cc: stable@vger.kernel.org # 3.0+ Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 57cc9c6..766dbda 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2298,10 +2298,7 @@ static int __init musb_init(void) if (usb_disabled()) return 0; - pr_info("%s: version " MUSB_VERSION ", " - "?dma?" - ", " - "otg (peripheral+host)", + pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n", musb_driver_name); return platform_driver_register(&musb_driver); } -- cgit v0.10.2 From 6f2a6a52560ad8d85710aabd92b7a3239b3a6b07 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 5 Dec 2012 21:46:02 +0100 Subject: mtd: nand: gpmi: reset BCH earlier, too, to avoid NAND startup problems It could happen (1 out of 100 times) that NAND did not start up correctly after warm rebooting, so the kernel could not find the UBI or DMA timed out due to a stalled BCH. When resetting BCH together with GPMI, the issue could not be observed anymore (after 10000+ reboots). We probably need the consistent state already before sending any command to NAND, even when no ECC is needed. I chose to keep the extra reset for BCH when changing the flash layout to be on the safe side. Signed-off-by: Wolfram Sang Acked-by: Huang Shijie Cc: stable@vger.kernel.org Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 1585c5b..d84699c 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -165,6 +165,15 @@ int gpmi_init(struct gpmi_nand_data *this) if (ret) goto err_out; + /* + * Reset BCH here, too. We got failures otherwise :( + * See later BCH reset for explanation of MX23 handling + */ + ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this)); + if (ret) + goto err_out; + + /* Choose NAND mode. */ writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); -- cgit v0.10.2 From 031da73fca29ebba3eea5a512746e01d52e542cd Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 12 Dec 2012 19:32:15 +1100 Subject: mtd: block2mtd: throttle writes by calling balance_dirty_pages_ratelimited. If you create a block2mtd device that is larger than main memory, and write to all of it, then lots of pages will be dirtied but they will never be flushed out as nothing calls any variant of balance_dirty_pages. It would be nice to call set_page_dirty_balance(), but that isn't exported, so just call balance_dirty_pages_ratelimited() directly. Signed-off-by: NeilBrown Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 8debac9..e081bfe 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -62,6 +62,7 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) memset(page_address(page), 0xff, PAGE_SIZE); set_page_dirty(page); unlock_page(page); + balance_dirty_pages_ratelimited(mapping); break; } @@ -152,6 +153,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, memcpy(page_address(page) + offset, buf, cpylen); set_page_dirty(page); unlock_page(page); + balance_dirty_pages_ratelimited(mapping); } page_cache_release(page); -- cgit v0.10.2 From 8204536207e99b3bbbd13d936aaa3b18449b9c00 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Mon, 10 Dec 2012 19:12:39 +0000 Subject: mtd: nand/gpio: use io{read,write}*_rep accessors The {read,write}s{b,w,l} operations are not defined by all architectures and are being removed from the asm-generic/io.h interface. This patch replaces the usage of these string functions in the mtd gpio accessors with io{read,write}{8,16,32}_rep calls instead. Signed-off-by: Matthew Leach Signed-off-by: Will Deacon Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 7aec569..e789e3f 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -90,14 +90,14 @@ static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; - writesb(this->IO_ADDR_W, buf, len); + iowrite8_rep(this->IO_ADDR_W, buf, len); } static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; - readsb(this->IO_ADDR_R, buf, len); + ioread8_rep(this->IO_ADDR_R, buf, len); } static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf, @@ -106,7 +106,7 @@ static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf, struct nand_chip *this = mtd->priv; if (IS_ALIGNED((unsigned long)buf, 2)) { - writesw(this->IO_ADDR_W, buf, len>>1); + iowrite16_rep(this->IO_ADDR_W, buf, len>>1); } else { int i; unsigned short *ptr = (unsigned short *)buf; @@ -121,7 +121,7 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len) struct nand_chip *this = mtd->priv; if (IS_ALIGNED((unsigned long)buf, 2)) { - readsw(this->IO_ADDR_R, buf, len>>1); + ioread16_rep(this->IO_ADDR_R, buf, len>>1); } else { int i; unsigned short *ptr = (unsigned short *)buf; -- cgit v0.10.2 From d4d4f1bf6a343b25220fdcdf559fd593dd3e25a7 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 14 Nov 2012 21:54:20 -0800 Subject: mtd: nand: typo in nand_id_has_period() comments The simple example provided in the comments for nand_id_has_period() actually has a period of 3, not 2. Silly mistake... Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 0ac49ca..8323ac9 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2923,7 +2923,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, * * Check if an ID string is repeated within a given sequence of bytes at * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a - * period of 2). This is a helper function for nand_id_len(). Returns non-zero + * period of 3). This is a helper function for nand_id_len(). Returns non-zero * if the repetition has a period of @period; otherwise, returns zero. */ static int nand_id_has_period(u8 *id_data, int arrlen, int period) -- cgit v0.10.2 From 8ae5865ec77c22462c736846a0679947a6953548 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Dec 2012 14:33:42 +0100 Subject: ALSA: hda - Fix pin configuration of HP Pavilion dv7 Fix the quirk entry for HP Pavilion dv7 in order to make the bass speaker working. Reported-and-tested-by: Tomas Pospisek Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index df13c0f..a86547c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1725,7 +1725,7 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), + "HP Pavilion dv7", STAC_HP_DV7_4000), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, -- cgit v0.10.2 From cfc84c9f73ab8a6933bd4f36efac1196cddad581 Mon Sep 17 00:00:00 2001 From: Cyril Roelandt Date: Tue, 20 Nov 2012 10:23:07 -0600 Subject: ceph: fix dentry reference leak in ceph_encode_fh(). dput() was not called in the error path. Signed-off-by: Cyril Roelandt Reviewed-by: Alex Elder diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 8628870..f350be3 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -56,13 +56,15 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len, struct ceph_nfs_confh *cfh = (void *)rawfh; int connected_handle_length = sizeof(*cfh)/4; int handle_length = sizeof(*fh)/4; - struct dentry *dentry = d_find_alias(inode); + struct dentry *dentry; struct dentry *parent; /* don't re-export snaps */ if (ceph_snap(inode) != CEPH_NOSNAP) return -EINVAL; + dentry = d_find_alias(inode); + /* if we found an alias, generate a connectable fh */ if (*max_len >= connected_handle_length && dentry) { dout("encode_fh %p connectable\n", dentry); -- cgit v0.10.2 From 83aff95eb9d60aff5497e9f44a2ae906b86d8e88 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 28 Nov 2012 12:28:24 -0800 Subject: libceph: remove 'osdtimeout' option This would reset a connection with any OSD that had an outstanding request that was taking more than N seconds. The idea was that if the OSD was buggy, the client could compensate by resending the request. In reality, this only served to hide server bugs, and we haven't actually seen such a bug in quite a while. Moreover, the userspace client code never did this. More importantly, often the request is taking a long time because the OSD is trying to recover, or overloaded, and killing the connection and retrying would only make the situation worse by giving the OSD more work to do. Signed-off-by: Sage Weil Reviewed-by: Alex Elder diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 2f586b0..fcda1c7 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -403,8 +403,6 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) seq_printf(m, ",mount_timeout=%d", opt->mount_timeout); if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl); - if (opt->osd_timeout != CEPH_OSD_TIMEOUT_DEFAULT) - seq_printf(m, ",osdtimeout=%d", opt->osd_timeout); if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) seq_printf(m, ",osdkeepalivetimeout=%d", opt->osd_keepalive_timeout); diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 4262478..317aff8 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -43,7 +43,6 @@ struct ceph_options { struct ceph_entity_addr my_addr; int mount_timeout; int osd_idle_ttl; - int osd_timeout; int osd_keepalive_timeout; /* @@ -63,7 +62,6 @@ struct ceph_options { * defaults */ #define CEPH_MOUNT_TIMEOUT_DEFAULT 60 -#define CEPH_OSD_TIMEOUT_DEFAULT 60 /* seconds */ #define CEPH_OSD_KEEPALIVE_DEFAULT 5 #define CEPH_OSD_IDLE_TTL_DEFAULT 60 diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index a802029..ee71ea2 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -305,7 +305,6 @@ ceph_parse_options(char *options, const char *dev_name, /* start with defaults */ opt->flags = CEPH_OPT_DEFAULT; - opt->osd_timeout = CEPH_OSD_TIMEOUT_DEFAULT; opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT; opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */ opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; /* seconds */ @@ -391,7 +390,7 @@ ceph_parse_options(char *options, const char *dev_name, /* misc */ case Opt_osdtimeout: - opt->osd_timeout = intval; + pr_warning("ignoring deprecated osdtimeout option\n"); break; case Opt_osdkeepalivetimeout: opt->osd_keepalive_timeout = intval; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index ccbdfbb..7ebfe13 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -608,14 +608,6 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc, } } -static void kick_osd_requests(struct ceph_osd_client *osdc, - struct ceph_osd *kickosd) -{ - mutex_lock(&osdc->request_mutex); - __kick_osd_requests(osdc, kickosd); - mutex_unlock(&osdc->request_mutex); -} - /* * If the osd connection drops, we need to resubmit all requests. */ @@ -629,7 +621,9 @@ static void osd_reset(struct ceph_connection *con) dout("osd_reset osd%d\n", osd->o_osd); osdc = osd->o_osdc; down_read(&osdc->map_sem); - kick_osd_requests(osdc, osd); + mutex_lock(&osdc->request_mutex); + __kick_osd_requests(osdc, osd); + mutex_unlock(&osdc->request_mutex); send_queued(osdc); up_read(&osdc->map_sem); } @@ -1091,12 +1085,10 @@ static void handle_timeout(struct work_struct *work) { struct ceph_osd_client *osdc = container_of(work, struct ceph_osd_client, timeout_work.work); - struct ceph_osd_request *req, *last_req = NULL; + struct ceph_osd_request *req; struct ceph_osd *osd; - unsigned long timeout = osdc->client->options->osd_timeout * HZ; unsigned long keepalive = osdc->client->options->osd_keepalive_timeout * HZ; - unsigned long last_stamp = 0; struct list_head slow_osds; dout("timeout\n"); down_read(&osdc->map_sem); @@ -1106,37 +1098,6 @@ static void handle_timeout(struct work_struct *work) mutex_lock(&osdc->request_mutex); /* - * reset osds that appear to be _really_ unresponsive. this - * is a failsafe measure.. we really shouldn't be getting to - * this point if the system is working properly. the monitors - * should mark the osd as failed and we should find out about - * it from an updated osd map. - */ - while (timeout && !list_empty(&osdc->req_lru)) { - req = list_entry(osdc->req_lru.next, struct ceph_osd_request, - r_req_lru_item); - - /* hasn't been long enough since we sent it? */ - if (time_before(jiffies, req->r_stamp + timeout)) - break; - - /* hasn't been long enough since it was acked? */ - if (req->r_request->ack_stamp == 0 || - time_before(jiffies, req->r_request->ack_stamp + timeout)) - break; - - BUG_ON(req == last_req && req->r_stamp == last_stamp); - last_req = req; - last_stamp = req->r_stamp; - - osd = req->r_osd; - BUG_ON(!osd); - pr_warning(" tid %llu timed out on osd%d, will reset osd\n", - req->r_tid, osd->o_osd); - __kick_osd_requests(osdc, osd); - } - - /* * ping osds that are a bit slow. this ensures that if there * is a break in the TCP connection we will notice, and reopen * a connection with that osd (from the fault callback). -- cgit v0.10.2 From d2cc4dde9206aa2c7fb237aa689d3277cc070547 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 29 Nov 2012 08:37:03 -0600 Subject: bdi_register: add __printf verification, fix arg mismatch __printf is useful to verify format and arguments. Signed-off-by: Joe Perches Reviewed-by: Alex Elder diff --git a/fs/ceph/super.c b/fs/ceph/super.c index fcda1c7..1a14400 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -842,7 +842,7 @@ static int ceph_register_bdi(struct super_block *sb, fsc->backing_dev_info.ra_pages = default_backing_dev_info.ra_pages; - err = bdi_register(&fsc->backing_dev_info, NULL, "ceph-%d", + err = bdi_register(&fsc->backing_dev_info, NULL, "ceph-%ld", atomic_long_inc_return(&bdi_seq)); if (!err) sb->s_bdi = &fsc->backing_dev_info; diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 2a9a9ab..12731a1 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -114,6 +114,7 @@ struct backing_dev_info { int bdi_init(struct backing_dev_info *bdi); void bdi_destroy(struct backing_dev_info *bdi); +__printf(3, 4) int bdi_register(struct backing_dev_info *bdi, struct device *parent, const char *fmt, ...); int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev); -- cgit v0.10.2 From 5e62ad30157d0da04cf40c6d1a2f4bc840948b9c Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 19 Nov 2012 10:49:04 +0800 Subject: ceph: Don't update i_max_size when handling non-auth cap The cap from non-auth mds doesn't have a meaningful max_size value. Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 2d0141e..8072aef 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2390,7 +2390,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, &atime); /* max size increase? */ - if (max_size != ci->i_max_size) { + if (ci->i_auth_cap == cap && max_size != ci->i_max_size) { dout("max_size %lld -> %llu\n", ci->i_max_size, max_size); ci->i_max_size = max_size; if (max_size >= ci->i_wanted_max_size) { -- cgit v0.10.2 From ed75ec2cd19b47efcd292b6e23f58e56f4c5bc34 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 19 Nov 2012 10:49:06 +0800 Subject: ceph: Fix infinite loop in __wake_requests __wake_requests() will enter infinite loop if we use it to wake requests in the session->s_waiting list. __wake_requests() deletes requests from the list and __do_request() adds requests back to the list. Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 62d2342..9165eb8 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1876,9 +1876,14 @@ finish: static void __wake_requests(struct ceph_mds_client *mdsc, struct list_head *head) { - struct ceph_mds_request *req, *nreq; + struct ceph_mds_request *req; + LIST_HEAD(tmp_list); + + list_splice_init(head, &tmp_list); - list_for_each_entry_safe(req, nreq, head, r_wait) { + while (!list_empty(&tmp_list)) { + req = list_entry(tmp_list.next, + struct ceph_mds_request, r_wait); list_del_init(&req->r_wait); __do_request(mdsc, req); } -- cgit v0.10.2 From 0685235ffd9dbdb9ccbda587f8a3c83ad1d5a921 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 19 Nov 2012 10:49:07 +0800 Subject: ceph: Don't add dirty inode to dirty list if caps is in migration Add dirty inode to cap_dirty_migrating list instead, this can avoid ceph_flush_dirty_caps() entering infinite loop. Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 8072aef..5efa3f5 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1351,11 +1351,15 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) if (!ci->i_head_snapc) ci->i_head_snapc = ceph_get_snap_context( ci->i_snap_realm->cached_context); - dout(" inode %p now dirty snapc %p\n", &ci->vfs_inode, - ci->i_head_snapc); + dout(" inode %p now dirty snapc %p auth cap %p\n", + &ci->vfs_inode, ci->i_head_snapc, ci->i_auth_cap); BUG_ON(!list_empty(&ci->i_dirty_item)); spin_lock(&mdsc->cap_dirty_lock); - list_add(&ci->i_dirty_item, &mdsc->cap_dirty); + if (ci->i_auth_cap) + list_add(&ci->i_dirty_item, &mdsc->cap_dirty); + else + list_add(&ci->i_dirty_item, + &mdsc->cap_dirty_migrating); spin_unlock(&mdsc->cap_dirty_lock); if (ci->i_flushing_caps == 0) { ihold(inode); -- cgit v0.10.2 From a85f50b6ef93fbbb2ae932ce9b2376509d172796 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 19 Nov 2012 10:49:08 +0800 Subject: ceph: Fix __ceph_do_pending_vmtruncate we should set i_truncate_pending to 0 after page cache is truncated to i_truncate_size Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 4b5762e..81613bc 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1466,7 +1466,7 @@ void __ceph_do_pending_vmtruncate(struct inode *inode) { struct ceph_inode_info *ci = ceph_inode(inode); u64 to; - int wrbuffer_refs, wake = 0; + int wrbuffer_refs, finish = 0; retry: spin_lock(&ci->i_ceph_lock); @@ -1498,15 +1498,18 @@ retry: truncate_inode_pages(inode->i_mapping, to); spin_lock(&ci->i_ceph_lock); - ci->i_truncate_pending--; - if (ci->i_truncate_pending == 0) - wake = 1; + if (to == ci->i_truncate_size) { + ci->i_truncate_pending = 0; + finish = 1; + } spin_unlock(&ci->i_ceph_lock); + if (!finish) + goto retry; if (wrbuffer_refs == 0) ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); - if (wake) - wake_up_all(&ci->i_cap_wq); + + wake_up_all(&ci->i_cap_wq); } -- cgit v0.10.2 From 0e5e1774a92e6fe9c511585de8f078b4c4c68dbb Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 19 Nov 2012 10:49:09 +0800 Subject: ceph: call handle_cap_grant() for cap import message If client sends cap message that requests new max size during exporting caps, the exporting MDS will drop the message quietly. So the client may wait for the reply that updates the max size forever. call handle_cap_grant() for cap import message can avoid this issue. Signed-off-by: Yan, Zheng Signed-off-by: Sage Weil diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 5efa3f5..a1d9bb3 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2751,6 +2751,7 @@ static void handle_cap_import(struct ceph_mds_client *mdsc, /* make sure we re-request max_size, if necessary */ spin_lock(&ci->i_ceph_lock); + ci->i_wanted_max_size = 0; /* reset */ ci->i_requested_max_size = 0; spin_unlock(&ci->i_ceph_lock); } @@ -2846,8 +2847,6 @@ void ceph_handle_caps(struct ceph_mds_session *session, case CEPH_CAP_OP_IMPORT: handle_cap_import(mdsc, inode, h, session, snaptrace, snaptrace_len); - ceph_check_caps(ceph_inode(inode), 0, session); - goto done_unlocked; } /* the rest require a cap */ @@ -2864,6 +2863,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, switch (op) { case CEPH_CAP_OP_REVOKE: case CEPH_CAP_OP_GRANT: + case CEPH_CAP_OP_IMPORT: handle_cap_grant(inode, h, session, cap, msg->middle); goto done_unlocked; -- cgit v0.10.2 From 8884d53dd63b1d9315b343564fcbe1ede004a99e Mon Sep 17 00:00:00 2001 From: David Zafman Date: Mon, 3 Dec 2012 19:14:05 -0800 Subject: libceph: Unlock unprocessed pages in start_read() error path Function start_read() can get an error before processing all pages. It must not only release the remaining pages, but unlock them too. This fixes http://tracker.newdream.net/issues/3370 Signed-off-by: David Zafman Reviewed-by: Alex Elder diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 21a0718..8e8a818 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -267,6 +267,14 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg) kfree(req->r_pages); } +static void ceph_unlock_page_vector(struct page **pages, int num_pages) +{ + int i; + + for (i = 0; i < num_pages; i++) + unlock_page(pages[i]); +} + /* * start an async read(ahead) operation. return nr_pages we submitted * a read for on success, or negative error code. @@ -347,6 +355,7 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) return nr_pages; out_pages: + ceph_unlock_page_vector(pages, nr_pages); ceph_release_page_vector(pages, nr_pages); out: ceph_osdc_put_request(req); -- cgit v0.10.2 From aaea7d2f78d008882524eddff0d78098c8fa9496 Mon Sep 17 00:00:00 2001 From: Yanchuan Nian Date: Thu, 13 Dec 2012 14:37:34 +0800 Subject: nfs: Remove duplicate function declaration in internal.h Remove duplicate function declaration in internal.h Signed-off-by: Yanchuan Nian [Trond: Added nfs_pageio_init_read, which suffered from the same problem] Signed-off-by: Trond Myklebust diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index fb99447..89c1ee4 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -363,9 +363,6 @@ extern int nfs_initiate_read(struct rpc_clnt *clnt, extern void nfs_read_prepare(struct rpc_task *task, void *calldata); extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr); -extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, - struct inode *inode, - const struct nfs_pgio_completion_ops *compl_ops); extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio); extern void nfs_readdata_release(struct nfs_read_data *rdata); @@ -388,9 +385,6 @@ extern struct nfs_write_header *nfs_writehdr_alloc(void); extern void nfs_writehdr_free(struct nfs_pgio_header *hdr); extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr); -extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, - struct inode *inode, int ioflags, - const struct nfs_pgio_completion_ops *compl_ops); extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio); extern void nfs_writedata_release(struct nfs_write_data *wdata); extern void nfs_commit_free(struct nfs_commit_data *p); -- cgit v0.10.2 From 48d7a57693af660666c4afdc54c09b2f9655e260 Mon Sep 17 00:00:00 2001 From: Yanchuan Nian Date: Thu, 13 Dec 2012 14:37:52 +0800 Subject: nfs: Remove unused list nfs4_clientid_list This list was designed to store struct nfs4_client in the client side. But nfs4_client was obsolete and has been removed from the source code. So remove the unused list. Signed-off-by: Yanchuan Nian Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 8dcbd9a..9448c57 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -67,7 +67,6 @@ const nfs4_stateid zero_stateid; static DEFINE_MUTEX(nfs_clid_init_mutex); -static LIST_HEAD(nfs4_clientid_list); int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) { -- cgit v0.10.2 From cb67e161bc947ab467657dda38168c2b2266f5bc Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 12 Dec 2012 17:24:39 -0500 Subject: arch/tile: provide PT_FLAGS_COMPAT value in pt_regs This flag is set for ptrace GETREGS or PEEKUSER for processes that are COMPAT, i.e. 32-bit. This allows things like strace to easily discover what personality to use, for example. Acked-by: Oleg Nesterov Signed-off-by: Chris Metcalf diff --git a/arch/tile/include/uapi/asm/ptrace.h b/arch/tile/include/uapi/asm/ptrace.h index c717d0f..0d22088 100644 --- a/arch/tile/include/uapi/asm/ptrace.h +++ b/arch/tile/include/uapi/asm/ptrace.h @@ -84,5 +84,11 @@ struct pt_regs { #define PTRACE_O_TRACEMIGRATE 0x00010000 #define PTRACE_EVENT_MIGRATE 16 +/* + * Flag bits in pt_regs.flags that are part of the ptrace API. + * We start our numbering higher up to avoid confusion with the + * non-ABI kernel-internal values that use the low 16 bits. + */ +#define PT_FLAGS_COMPAT 0x10000 /* process is an -m32 compat process */ #endif /* _UAPI_ASM_TILE_PTRACE_H */ diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c index e92e405..64ba102 100644 --- a/arch/tile/kernel/ptrace.c +++ b/arch/tile/kernel/ptrace.c @@ -45,6 +45,41 @@ void ptrace_disable(struct task_struct *child) clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); } +/* + * Get registers from task and ready the result for userspace. + * Note that we localize the API issues to getregs() and putregs() at + * some cost in performance, e.g. we need a full pt_regs copy for + * PEEKUSR, and two copies for POKEUSR. But in general we expect + * GETREGS/PUTREGS to be the API of choice anyway. + */ +static char *getregs(struct task_struct *child, struct pt_regs *uregs) +{ + *uregs = *task_pt_regs(child); + + /* Set up flags ABI bits. */ + uregs->flags = 0; +#ifdef CONFIG_COMPAT + if (task_thread_info(child)->status & TS_COMPAT) + uregs->flags |= PT_FLAGS_COMPAT; +#endif + + return (char *)uregs; +} + +/* Put registers back to task. */ +static void putregs(struct task_struct *child, struct pt_regs *uregs) +{ + struct pt_regs *regs = task_pt_regs(child); + + /* Don't allow overwriting the kernel-internal flags word. */ + uregs->flags = regs->flags; + + /* Only allow setting the ICS bit in the ex1 word. */ + uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1)); + + *regs = *uregs; +} + long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { @@ -53,14 +88,13 @@ long arch_ptrace(struct task_struct *child, long request, long ret = -EIO; char *childreg; struct pt_regs copyregs; - int ex1_offset; switch (request) { case PTRACE_PEEKUSR: /* Read register from pt_regs. */ if (addr >= PTREGS_SIZE) break; - childreg = (char *)task_pt_regs(child) + addr; + childreg = getregs(child, ©regs) + addr; #ifdef CONFIG_COMPAT if (is_compat_task()) { if (addr & (sizeof(compat_long_t)-1)) @@ -79,17 +113,7 @@ long arch_ptrace(struct task_struct *child, long request, case PTRACE_POKEUSR: /* Write register in pt_regs. */ if (addr >= PTREGS_SIZE) break; - childreg = (char *)task_pt_regs(child) + addr; - - /* Guard against overwrites of the privilege level. */ - ex1_offset = PTREGS_OFFSET_EX1; -#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN) - if (is_compat_task()) /* point at low word */ - ex1_offset += sizeof(compat_long_t); -#endif - if (addr == ex1_offset) - data = PL_ICS_EX1(USER_PL, EX1_ICS(data)); - + childreg = getregs(child, ©regs) + addr; #ifdef CONFIG_COMPAT if (is_compat_task()) { if (addr & (sizeof(compat_long_t)-1)) @@ -102,11 +126,12 @@ long arch_ptrace(struct task_struct *child, long request, break; *(long *)childreg = data; } + putregs(child, ©regs); ret = 0; break; case PTRACE_GETREGS: /* Get all registers from the child. */ - if (copy_to_user(datap, task_pt_regs(child), + if (copy_to_user(datap, getregs(child, ©regs), sizeof(struct pt_regs)) == 0) { ret = 0; } @@ -115,9 +140,7 @@ long arch_ptrace(struct task_struct *child, long request, case PTRACE_SETREGS: /* Set all registers in the child. */ if (copy_from_user(©regs, datap, sizeof(struct pt_regs)) == 0) { - copyregs.ex1 = - PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1)); - *task_pt_regs(child) = copyregs; + putregs(child, ©regs); ret = 0; } break; -- cgit v0.10.2 From d526e85f60fce9aa2a1432cbd06e3cf20c1644c8 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 14 Dec 2012 10:32:52 +1100 Subject: powerpc+of: Rename and fix OF reconfig notifier error inject module This module used to inject errors in the pSeries specific dynamic reconfiguration notifiers. Those are gone however, replaced by generic notifiers for changes to the device-tree. So let's update the module to deal with these instead and rename it along the way. Signed-off-by: Benjamin Herrenschmidt Acked-by: Akinobu Mita diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 28e9d6c9..c2d89f3 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1192,14 +1192,14 @@ config MEMORY_NOTIFIER_ERROR_INJECT If unsure, say N. -config PSERIES_RECONFIG_NOTIFIER_ERROR_INJECT - tristate "pSeries reconfig notifier error injection module" - depends on PPC_PSERIES && NOTIFIER_ERROR_INJECTION +config OF_RECONFIG_NOTIFIER_ERROR_INJECT + tristate "OF reconfig notifier error injection module" + depends on OF_DYNAMIC && NOTIFIER_ERROR_INJECTION help This option provides the ability to inject artifical errors to - pSeries reconfig notifier chain callbacks. It is controlled + OF reconfig notifier chain callbacks. It is controlled through debugfs interface under - /sys/kernel/debug/notifier-error-inject/pSeries-reconfig/ + /sys/kernel/debug/notifier-error-inject/OF-reconfig/ If the notifier call chain should be failed with some events notified, write the error code to "actions//error". diff --git a/lib/Makefile b/lib/Makefile index 821a162..7c00908 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -94,8 +94,8 @@ obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o obj-$(CONFIG_PM_NOTIFIER_ERROR_INJECT) += pm-notifier-error-inject.o obj-$(CONFIG_MEMORY_NOTIFIER_ERROR_INJECT) += memory-notifier-error-inject.o -obj-$(CONFIG_PSERIES_RECONFIG_NOTIFIER_ERROR_INJECT) += \ - pSeries-reconfig-notifier-error-inject.o +obj-$(CONFIG_OF_RECONFIG_NOTIFIER_ERROR_INJECT) += \ + of-reconfig-notifier-error-inject.o lib-$(CONFIG_GENERIC_BUG) += bug.o diff --git a/lib/of-reconfig-notifier-error-inject.c b/lib/of-reconfig-notifier-error-inject.c new file mode 100644 index 0000000..8dc7986 --- /dev/null +++ b/lib/of-reconfig-notifier-error-inject.c @@ -0,0 +1,51 @@ +#include +#include +#include + +#include "notifier-error-inject.h" + +static int priority; +module_param(priority, int, 0); +MODULE_PARM_DESC(priority, "specify OF reconfig notifier priority"); + +static struct notifier_err_inject reconfig_err_inject = { + .actions = { + { NOTIFIER_ERR_INJECT_ACTION(OF_RECONFIG_ATTACH_NODE) }, + { NOTIFIER_ERR_INJECT_ACTION(OF_RECONFIG_DETACH_NODE) }, + { NOTIFIER_ERR_INJECT_ACTION(OF_RECONFIG_ADD_PROPERTY) }, + { NOTIFIER_ERR_INJECT_ACTION(OF_RECONFIG_REMOVE_PROPERTY) }, + { NOTIFIER_ERR_INJECT_ACTION(OF_RECONFIG_UPDATE_PROPERTY) }, + {} + } +}; + +static struct dentry *dir; + +static int err_inject_init(void) +{ + int err; + + dir = notifier_err_inject_init("OF-reconfig", + notifier_err_inject_dir, &reconfig_err_inject, priority); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + err = of_reconfig_notifier_register(&reconfig_err_inject.nb); + if (err) + debugfs_remove_recursive(dir); + + return err; +} + +static void err_inject_exit(void) +{ + of_reconfig_notifier_unregister(&reconfig_err_inject.nb); + debugfs_remove_recursive(dir); +} + +module_init(err_inject_init); +module_exit(err_inject_exit); + +MODULE_DESCRIPTION("OF reconfig notifier error injection module"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Akinobu Mita "); diff --git a/lib/pSeries-reconfig-notifier-error-inject.c b/lib/pSeries-reconfig-notifier-error-inject.c deleted file mode 100644 index 7f7c98d..0000000 --- a/lib/pSeries-reconfig-notifier-error-inject.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include - -#include - -#include "notifier-error-inject.h" - -static int priority; -module_param(priority, int, 0); -MODULE_PARM_DESC(priority, "specify pSeries reconfig notifier priority"); - -static struct notifier_err_inject reconfig_err_inject = { - .actions = { - { NOTIFIER_ERR_INJECT_ACTION(PSERIES_RECONFIG_ADD) }, - { NOTIFIER_ERR_INJECT_ACTION(PSERIES_RECONFIG_REMOVE) }, - { NOTIFIER_ERR_INJECT_ACTION(PSERIES_DRCONF_MEM_ADD) }, - { NOTIFIER_ERR_INJECT_ACTION(PSERIES_DRCONF_MEM_REMOVE) }, - {} - } -}; - -static struct dentry *dir; - -static int err_inject_init(void) -{ - int err; - - dir = notifier_err_inject_init("pSeries-reconfig", - notifier_err_inject_dir, &reconfig_err_inject, priority); - if (IS_ERR(dir)) - return PTR_ERR(dir); - - err = pSeries_reconfig_notifier_register(&reconfig_err_inject.nb); - if (err) - debugfs_remove_recursive(dir); - - return err; -} - -static void err_inject_exit(void) -{ - pSeries_reconfig_notifier_unregister(&reconfig_err_inject.nb); - debugfs_remove_recursive(dir); -} - -module_init(err_inject_init); -module_exit(err_inject_exit); - -MODULE_DESCRIPTION("pSeries reconfig notifier error injection module"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Akinobu Mita "); -- cgit v0.10.2 From 34e1169d996ab148490c01b65b4ee371cf8ffba2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 16 Oct 2012 07:31:07 +1030 Subject: module: add syscall to load module from fd As part of the effort to create a stronger boundary between root and kernel, Chrome OS wants to be able to enforce that kernel modules are being loaded only from our read-only crypto-hash verified (dm_verity) root filesystem. Since the init_module syscall hands the kernel a module as a memory blob, no reasoning about the origin of the blob can be made. Earlier proposals for appending signatures to kernel modules would not be useful in Chrome OS, since it would involve adding an additional set of keys to our kernel and builds for no good reason: we already trust the contents of our root filesystem. We don't need to verify those kernel modules a second time. Having to do signature checking on module loading would slow us down and be redundant. All we need to know is where a module is coming from so we can say yes/no to loading it. If a file descriptor is used as the source of a kernel module, many more things can be reasoned about. In Chrome OS's case, we could enforce that the module lives on the filesystem we expect it to live on. In the case of IMA (or other LSMs), it would be possible, for example, to examine extended attributes that may contain signatures over the contents of the module. This introduces a new syscall (on x86), similar to init_module, that has only two arguments. The first argument is used as a file descriptor to the module and the second argument is a pointer to the NULL terminated string of module arguments. Signed-off-by: Kees Cook Cc: Andrew Morton Signed-off-by: Rusty Russell (merge fixes) diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl index a47103f..83b3838 100644 --- a/arch/x86/syscalls/syscall_32.tbl +++ b/arch/x86/syscalls/syscall_32.tbl @@ -356,3 +356,4 @@ 347 i386 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv 348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev 349 i386 kcmp sys_kcmp +350 i386 finit_module sys_finit_module diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl index a582bfe..7c58c84 100644 --- a/arch/x86/syscalls/syscall_64.tbl +++ b/arch/x86/syscalls/syscall_64.tbl @@ -319,6 +319,7 @@ 310 64 process_vm_readv sys_process_vm_readv 311 64 process_vm_writev sys_process_vm_writev 312 common kcmp sys_kcmp +313 common finit_module sys_finit_module # # x32-specific system call numbers start at 512 to avoid cache impact diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 727f0cd..32bc035 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -868,4 +868,5 @@ asmlinkage long sys_process_vm_writev(pid_t pid, asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2); +asmlinkage long sys_finit_module(int fd, const char __user *uargs); #endif diff --git a/kernel/module.c b/kernel/module.c index 6e48c3a..6d2c4e4 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -2425,18 +2426,17 @@ static inline void kmemleak_load_module(const struct module *mod, #endif #ifdef CONFIG_MODULE_SIG -static int module_sig_check(struct load_info *info, - const void *mod, unsigned long *_len) +static int module_sig_check(struct load_info *info) { int err = -ENOKEY; - unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; - unsigned long len = *_len; + const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; + const void *mod = info->hdr; - if (len > markerlen && - memcmp(mod + len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { + if (info->len > markerlen && + memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { /* We truncate the module to discard the signature */ - *_len -= markerlen; - err = mod_verify_sig(mod, _len); + info->len -= markerlen; + err = mod_verify_sig(mod, &info->len); } if (!err) { @@ -2454,59 +2454,97 @@ static int module_sig_check(struct load_info *info, return err; } #else /* !CONFIG_MODULE_SIG */ -static int module_sig_check(struct load_info *info, - void *mod, unsigned long *len) +static int module_sig_check(struct load_info *info) { return 0; } #endif /* !CONFIG_MODULE_SIG */ -/* Sets info->hdr, info->len and info->sig_ok. */ -static int copy_and_check(struct load_info *info, - const void __user *umod, unsigned long len, - const char __user *uargs) +/* Sanity checks against invalid binaries, wrong arch, weird elf version. */ +static int elf_header_check(struct load_info *info) { - int err; - Elf_Ehdr *hdr; + if (info->len < sizeof(*(info->hdr))) + return -ENOEXEC; + + if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0 + || info->hdr->e_type != ET_REL + || !elf_check_arch(info->hdr) + || info->hdr->e_shentsize != sizeof(Elf_Shdr)) + return -ENOEXEC; + + if (info->hdr->e_shoff >= info->len + || (info->hdr->e_shnum * sizeof(Elf_Shdr) > + info->len - info->hdr->e_shoff)) + return -ENOEXEC; - if (len < sizeof(*hdr)) + return 0; +} + +/* Sets info->hdr and info->len. */ +static int copy_module_from_user(const void __user *umod, unsigned long len, + struct load_info *info) +{ + info->len = len; + if (info->len < sizeof(*(info->hdr))) return -ENOEXEC; /* Suck in entire file: we'll want most of it. */ - if ((hdr = vmalloc(len)) == NULL) + info->hdr = vmalloc(info->len); + if (!info->hdr) return -ENOMEM; - if (copy_from_user(hdr, umod, len) != 0) { - err = -EFAULT; - goto free_hdr; + if (copy_from_user(info->hdr, umod, info->len) != 0) { + vfree(info->hdr); + return -EFAULT; } - err = module_sig_check(info, hdr, &len); + return 0; +} + +/* Sets info->hdr and info->len. */ +static int copy_module_from_fd(int fd, struct load_info *info) +{ + struct file *file; + int err; + struct kstat stat; + loff_t pos; + ssize_t bytes = 0; + + file = fget(fd); + if (!file) + return -ENOEXEC; + + err = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat); if (err) - goto free_hdr; + goto out; - /* Sanity checks against insmoding binaries or wrong arch, - weird elf version */ - if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0 - || hdr->e_type != ET_REL - || !elf_check_arch(hdr) - || hdr->e_shentsize != sizeof(Elf_Shdr)) { - err = -ENOEXEC; - goto free_hdr; + if (stat.size > INT_MAX) { + err = -EFBIG; + goto out; } - - if (hdr->e_shoff >= len || - hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) { - err = -ENOEXEC; - goto free_hdr; + info->hdr = vmalloc(stat.size); + if (!info->hdr) { + err = -ENOMEM; + goto out; } - info->hdr = hdr; - info->len = len; - return 0; + pos = 0; + while (pos < stat.size) { + bytes = kernel_read(file, pos, (char *)(info->hdr) + pos, + stat.size - pos); + if (bytes < 0) { + vfree(info->hdr); + err = bytes; + goto out; + } + if (bytes == 0) + break; + pos += bytes; + } + info->len = pos; -free_hdr: - vfree(hdr); +out: + fput(file); return err; } @@ -2945,33 +2983,123 @@ static bool finished_loading(const char *name) return ret; } +/* Call module constructors. */ +static void do_mod_ctors(struct module *mod) +{ +#ifdef CONFIG_CONSTRUCTORS + unsigned long i; + + for (i = 0; i < mod->num_ctors; i++) + mod->ctors[i](); +#endif +} + +/* This is where the real work happens */ +static int do_init_module(struct module *mod) +{ + int ret = 0; + + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_COMING, mod); + + /* Set RO and NX regions for core */ + set_section_ro_nx(mod->module_core, + mod->core_text_size, + mod->core_ro_size, + mod->core_size); + + /* Set RO and NX regions for init */ + set_section_ro_nx(mod->module_init, + mod->init_text_size, + mod->init_ro_size, + mod->init_size); + + do_mod_ctors(mod); + /* Start the module */ + if (mod->init != NULL) + ret = do_one_initcall(mod->init); + if (ret < 0) { + /* Init routine failed: abort. Try to protect us from + buggy refcounters. */ + mod->state = MODULE_STATE_GOING; + synchronize_sched(); + module_put(mod); + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_GOING, mod); + free_module(mod); + wake_up_all(&module_wq); + return ret; + } + if (ret > 0) { + printk(KERN_WARNING +"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n" +"%s: loading module anyway...\n", + __func__, mod->name, ret, + __func__); + dump_stack(); + } + + /* Now it's a first class citizen! */ + mod->state = MODULE_STATE_LIVE; + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_LIVE, mod); + + /* We need to finish all async code before the module init sequence is done */ + async_synchronize_full(); + + mutex_lock(&module_mutex); + /* Drop initial reference. */ + module_put(mod); + trim_init_extable(mod); +#ifdef CONFIG_KALLSYMS + mod->num_symtab = mod->core_num_syms; + mod->symtab = mod->core_symtab; + mod->strtab = mod->core_strtab; +#endif + unset_module_init_ro_nx(mod); + module_free(mod, mod->module_init); + mod->module_init = NULL; + mod->init_size = 0; + mod->init_ro_size = 0; + mod->init_text_size = 0; + mutex_unlock(&module_mutex); + wake_up_all(&module_wq); + + return 0; +} + +static int may_init_module(void) +{ + if (!capable(CAP_SYS_MODULE) || modules_disabled) + return -EPERM; + + return 0; +} + /* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */ -static struct module *load_module(void __user *umod, - unsigned long len, - const char __user *uargs) +static int load_module(struct load_info *info, const char __user *uargs) { - struct load_info info = { NULL, }; struct module *mod, *old; long err; - pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n", - umod, len, uargs); + err = module_sig_check(info); + if (err) + goto free_copy; - /* Copy in the blobs from userspace, check they are vaguely sane. */ - err = copy_and_check(&info, umod, len, uargs); + err = elf_header_check(info); if (err) - return ERR_PTR(err); + goto free_copy; /* Figure out module layout, and allocate all the memory. */ - mod = layout_and_allocate(&info); + mod = layout_and_allocate(info); if (IS_ERR(mod)) { err = PTR_ERR(mod); goto free_copy; } #ifdef CONFIG_MODULE_SIG - mod->sig_ok = info.sig_ok; + mod->sig_ok = info->sig_ok; if (!mod->sig_ok) add_taint_module(mod, TAINT_FORCED_MODULE); #endif @@ -2983,25 +3111,25 @@ static struct module *load_module(void __user *umod, /* Now we've got everything in the final locations, we can * find optional sections. */ - find_module_sections(mod, &info); + find_module_sections(mod, info); err = check_module_license_and_versions(mod); if (err) goto free_unload; /* Set up MODINFO_ATTR fields */ - setup_modinfo(mod, &info); + setup_modinfo(mod, info); /* Fix up syms, so that st_value is a pointer to location. */ - err = simplify_symbols(mod, &info); + err = simplify_symbols(mod, info); if (err < 0) goto free_modinfo; - err = apply_relocations(mod, &info); + err = apply_relocations(mod, info); if (err < 0) goto free_modinfo; - err = post_relocation(mod, &info); + err = post_relocation(mod, info); if (err < 0) goto free_modinfo; @@ -3041,14 +3169,14 @@ again: } /* This has to be done once we're sure module name is unique. */ - dynamic_debug_setup(info.debug, info.num_debug); + dynamic_debug_setup(info->debug, info->num_debug); /* Find duplicate symbols */ err = verify_export_symbols(mod); if (err < 0) goto ddebug; - module_bug_finalize(info.hdr, info.sechdrs, mod); + module_bug_finalize(info->hdr, info->sechdrs, mod); list_add_rcu(&mod->list, &modules); mutex_unlock(&module_mutex); @@ -3059,16 +3187,17 @@ again: goto unlink; /* Link in to syfs. */ - err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp); + err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp); if (err < 0) goto unlink; /* Get rid of temporary copy. */ - free_copy(&info); + free_copy(info); /* Done! */ trace_module_load(mod); - return mod; + + return do_init_module(mod); unlink: mutex_lock(&module_mutex); @@ -3077,7 +3206,7 @@ again: module_bug_cleanup(mod); wake_up_all(&module_wq); ddebug: - dynamic_debug_remove(info.debug); + dynamic_debug_remove(info->debug); unlock: mutex_unlock(&module_mutex); synchronize_sched(); @@ -3089,106 +3218,48 @@ again: free_unload: module_unload_free(mod); free_module: - module_deallocate(mod, &info); + module_deallocate(mod, info); free_copy: - free_copy(&info); - return ERR_PTR(err); -} - -/* Call module constructors. */ -static void do_mod_ctors(struct module *mod) -{ -#ifdef CONFIG_CONSTRUCTORS - unsigned long i; - - for (i = 0; i < mod->num_ctors; i++) - mod->ctors[i](); -#endif + free_copy(info); + return err; } -/* This is where the real work happens */ SYSCALL_DEFINE3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs) { - struct module *mod; - int ret = 0; - - /* Must have permission */ - if (!capable(CAP_SYS_MODULE) || modules_disabled) - return -EPERM; + int err; + struct load_info info = { }; - /* Do all the hard work */ - mod = load_module(umod, len, uargs); - if (IS_ERR(mod)) - return PTR_ERR(mod); + err = may_init_module(); + if (err) + return err; - blocking_notifier_call_chain(&module_notify_list, - MODULE_STATE_COMING, mod); + pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n", + umod, len, uargs); - /* Set RO and NX regions for core */ - set_section_ro_nx(mod->module_core, - mod->core_text_size, - mod->core_ro_size, - mod->core_size); + err = copy_module_from_user(umod, len, &info); + if (err) + return err; - /* Set RO and NX regions for init */ - set_section_ro_nx(mod->module_init, - mod->init_text_size, - mod->init_ro_size, - mod->init_size); + return load_module(&info, uargs); +} - do_mod_ctors(mod); - /* Start the module */ - if (mod->init != NULL) - ret = do_one_initcall(mod->init); - if (ret < 0) { - /* Init routine failed: abort. Try to protect us from - buggy refcounters. */ - mod->state = MODULE_STATE_GOING; - synchronize_sched(); - module_put(mod); - blocking_notifier_call_chain(&module_notify_list, - MODULE_STATE_GOING, mod); - free_module(mod); - wake_up_all(&module_wq); - return ret; - } - if (ret > 0) { - printk(KERN_WARNING -"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n" -"%s: loading module anyway...\n", - __func__, mod->name, ret, - __func__); - dump_stack(); - } +SYSCALL_DEFINE2(finit_module, int, fd, const char __user *, uargs) +{ + int err; + struct load_info info = { }; - /* Now it's a first class citizen! */ - mod->state = MODULE_STATE_LIVE; - blocking_notifier_call_chain(&module_notify_list, - MODULE_STATE_LIVE, mod); + err = may_init_module(); + if (err) + return err; - /* We need to finish all async code before the module init sequence is done */ - async_synchronize_full(); + pr_debug("finit_module: fd=%d, uargs=%p\n", fd, uargs); - mutex_lock(&module_mutex); - /* Drop initial reference. */ - module_put(mod); - trim_init_extable(mod); -#ifdef CONFIG_KALLSYMS - mod->num_symtab = mod->core_num_syms; - mod->symtab = mod->core_symtab; - mod->strtab = mod->core_strtab; -#endif - unset_module_init_ro_nx(mod); - module_free(mod, mod->module_init); - mod->module_init = NULL; - mod->init_size = 0; - mod->init_ro_size = 0; - mod->init_text_size = 0; - mutex_unlock(&module_mutex); - wake_up_all(&module_wq); + err = copy_module_from_fd(fd, &info); + if (err) + return err; - return 0; + return load_module(&info, uargs); } static inline int within(unsigned long addr, void *start, unsigned long size) diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index dbff751..395084d 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -25,6 +25,7 @@ cond_syscall(sys_swapoff); cond_syscall(sys_kexec_load); cond_syscall(compat_sys_kexec_load); cond_syscall(sys_init_module); +cond_syscall(sys_finit_module); cond_syscall(sys_delete_module); cond_syscall(sys_socketpair); cond_syscall(sys_bind); -- cgit v0.10.2 From 2f3238aebedb243804f58d62d57244edec4149b2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 22 Oct 2012 18:09:41 +1030 Subject: module: add flags arg to sys_finit_module() Thanks to Michael Kerrisk for keeping us honest. These flags are actually useful for eliminating the only case where kmod has to mangle a module's internals: for overriding module versioning. Signed-off-by: Rusty Russell Acked-by: Lucas De Marchi Acked-by: Kees Cook diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 32bc035..8cf7b50 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -868,5 +868,5 @@ asmlinkage long sys_process_vm_writev(pid_t pid, asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2); -asmlinkage long sys_finit_module(int fd, const char __user *uargs); +asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); #endif diff --git a/include/uapi/linux/module.h b/include/uapi/linux/module.h new file mode 100644 index 0000000..38da425 --- /dev/null +++ b/include/uapi/linux/module.h @@ -0,0 +1,8 @@ +#ifndef _UAPI_LINUX_MODULE_H +#define _UAPI_LINUX_MODULE_H + +/* Flags for sys_finit_module: */ +#define MODULE_INIT_IGNORE_MODVERSIONS 1 +#define MODULE_INIT_IGNORE_VERMAGIC 2 + +#endif /* _UAPI_LINUX_MODULE_H */ diff --git a/kernel/module.c b/kernel/module.c index 6d2c4e4..1395ca3 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -60,6 +60,7 @@ #include #include #include +#include #include "module-internal.h" #define CREATE_TRACE_POINTS @@ -2553,7 +2554,7 @@ static void free_copy(struct load_info *info) vfree(info->hdr); } -static int rewrite_section_headers(struct load_info *info) +static int rewrite_section_headers(struct load_info *info, int flags) { unsigned int i; @@ -2581,7 +2582,10 @@ static int rewrite_section_headers(struct load_info *info) } /* Track but don't keep modinfo and version sections. */ - info->index.vers = find_sec(info, "__versions"); + if (flags & MODULE_INIT_IGNORE_MODVERSIONS) + info->index.vers = 0; /* Pretend no __versions section! */ + else + info->index.vers = find_sec(info, "__versions"); info->index.info = find_sec(info, ".modinfo"); info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC; info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC; @@ -2596,7 +2600,7 @@ static int rewrite_section_headers(struct load_info *info) * Return the temporary module pointer (we'll replace it with the final * one when we move the module sections around). */ -static struct module *setup_load_info(struct load_info *info) +static struct module *setup_load_info(struct load_info *info, int flags) { unsigned int i; int err; @@ -2607,7 +2611,7 @@ static struct module *setup_load_info(struct load_info *info) info->secstrings = (void *)info->hdr + info->sechdrs[info->hdr->e_shstrndx].sh_offset; - err = rewrite_section_headers(info); + err = rewrite_section_headers(info, flags); if (err) return ERR_PTR(err); @@ -2645,11 +2649,14 @@ static struct module *setup_load_info(struct load_info *info) return mod; } -static int check_modinfo(struct module *mod, struct load_info *info) +static int check_modinfo(struct module *mod, struct load_info *info, int flags) { const char *modmagic = get_modinfo(info, "vermagic"); int err; + if (flags & MODULE_INIT_IGNORE_VERMAGIC) + modmagic = NULL; + /* This is allowed: modprobe --force will invalidate it. */ if (!modmagic) { err = try_to_force_load(mod, "bad vermagic"); @@ -2885,18 +2892,18 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr, return 0; } -static struct module *layout_and_allocate(struct load_info *info) +static struct module *layout_and_allocate(struct load_info *info, int flags) { /* Module within temporary copy. */ struct module *mod; Elf_Shdr *pcpusec; int err; - mod = setup_load_info(info); + mod = setup_load_info(info, flags); if (IS_ERR(mod)) return mod; - err = check_modinfo(mod, info); + err = check_modinfo(mod, info, flags); if (err) return ERR_PTR(err); @@ -3078,7 +3085,8 @@ static int may_init_module(void) /* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */ -static int load_module(struct load_info *info, const char __user *uargs) +static int load_module(struct load_info *info, const char __user *uargs, + int flags) { struct module *mod, *old; long err; @@ -3092,7 +3100,7 @@ static int load_module(struct load_info *info, const char __user *uargs) goto free_copy; /* Figure out module layout, and allocate all the memory. */ - mod = layout_and_allocate(info); + mod = layout_and_allocate(info, flags); if (IS_ERR(mod)) { err = PTR_ERR(mod); goto free_copy; @@ -3241,10 +3249,10 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, if (err) return err; - return load_module(&info, uargs); + return load_module(&info, uargs, 0); } -SYSCALL_DEFINE2(finit_module, int, fd, const char __user *, uargs) +SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) { int err; struct load_info info = { }; @@ -3253,13 +3261,17 @@ SYSCALL_DEFINE2(finit_module, int, fd, const char __user *, uargs) if (err) return err; - pr_debug("finit_module: fd=%d, uargs=%p\n", fd, uargs); + pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags); + + if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS + |MODULE_INIT_IGNORE_VERMAGIC)) + return -EINVAL; err = copy_module_from_fd(fd, &info); if (err) return err; - return load_module(&info, uargs); + return load_module(&info, uargs, flags); } static inline int within(unsigned long addr, void *start, unsigned long size) -- cgit v0.10.2 From 2e72d51b4ac32989496870cd8171b3682fea1839 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 16 Oct 2012 07:32:07 +1030 Subject: security: introduce kernel_module_from_file hook Now that kernel module origins can be reasoned about, provide a hook to the LSMs to make policy decisions about the module file. This will let Chrome OS enforce that loadable kernel modules can only come from its read-only hash-verified root filesystem. Other LSMs can, for example, read extended attributes for signatures, etc. Signed-off-by: Kees Cook Acked-by: Serge E. Hallyn Acked-by: Eric Paris Acked-by: Mimi Zohar Acked-by: James Morris Signed-off-by: Rusty Russell diff --git a/include/linux/security.h b/include/linux/security.h index 05e88bd..0f6afc6 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -694,6 +694,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * userspace to load a kernel module with the given name. * @kmod_name name of the module requested by the kernel * Return 0 if successful. + * @kernel_module_from_file: + * Load a kernel module from userspace. + * @file contains the file structure pointing to the file containing + * the kernel module to load. If the module is being loaded from a blob, + * this argument will be NULL. + * Return 0 if permission is granted. * @task_fix_setuid: * Update the module's state after setting one or more of the user * identity attributes of the current process. The @flags parameter @@ -1508,6 +1514,7 @@ struct security_operations { int (*kernel_act_as)(struct cred *new, u32 secid); int (*kernel_create_files_as)(struct cred *new, struct inode *inode); int (*kernel_module_request)(char *kmod_name); + int (*kernel_module_from_file)(struct file *file); int (*task_fix_setuid) (struct cred *new, const struct cred *old, int flags); int (*task_setpgid) (struct task_struct *p, pid_t pgid); @@ -1765,6 +1772,7 @@ void security_transfer_creds(struct cred *new, const struct cred *old); int security_kernel_act_as(struct cred *new, u32 secid); int security_kernel_create_files_as(struct cred *new, struct inode *inode); int security_kernel_module_request(char *kmod_name); +int security_kernel_module_from_file(struct file *file); int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags); int security_task_setpgid(struct task_struct *p, pid_t pgid); @@ -2278,6 +2286,11 @@ static inline int security_kernel_module_request(char *kmod_name) return 0; } +static inline int security_kernel_module_from_file(struct file *file) +{ + return 0; +} + static inline int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags) diff --git a/kernel/module.c b/kernel/module.c index 1395ca3..a1d2ed8 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -2485,10 +2486,16 @@ static int elf_header_check(struct load_info *info) static int copy_module_from_user(const void __user *umod, unsigned long len, struct load_info *info) { + int err; + info->len = len; if (info->len < sizeof(*(info->hdr))) return -ENOEXEC; + err = security_kernel_module_from_file(NULL); + if (err) + return err; + /* Suck in entire file: we'll want most of it. */ info->hdr = vmalloc(info->len); if (!info->hdr) @@ -2515,6 +2522,10 @@ static int copy_module_from_fd(int fd, struct load_info *info) if (!file) return -ENOEXEC; + err = security_kernel_module_from_file(file); + if (err) + goto out; + err = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat); if (err) goto out; diff --git a/security/capability.c b/security/capability.c index b14a30c..0fe5a02 100644 --- a/security/capability.c +++ b/security/capability.c @@ -395,6 +395,11 @@ static int cap_kernel_module_request(char *kmod_name) return 0; } +static int cap_kernel_module_from_file(struct file *file) +{ + return 0; +} + static int cap_task_setpgid(struct task_struct *p, pid_t pgid) { return 0; @@ -967,6 +972,7 @@ void __init security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, kernel_act_as); set_to_cap_if_null(ops, kernel_create_files_as); set_to_cap_if_null(ops, kernel_module_request); + set_to_cap_if_null(ops, kernel_module_from_file); set_to_cap_if_null(ops, task_fix_setuid); set_to_cap_if_null(ops, task_setpgid); set_to_cap_if_null(ops, task_getpgid); diff --git a/security/security.c b/security/security.c index 8dcd4ae..ce88630 100644 --- a/security/security.c +++ b/security/security.c @@ -820,6 +820,11 @@ int security_kernel_module_request(char *kmod_name) return security_ops->kernel_module_request(kmod_name); } +int security_kernel_module_from_file(struct file *file) +{ + return security_ops->kernel_module_from_file(file); +} + int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags) { -- cgit v0.10.2 From 4926f65224e49f253feb0320b03814ea630b7541 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 16 Oct 2012 12:38:47 +1030 Subject: ARM: add finit_module syscall to ARM Add finit_module syscall to the ARM syscall list. Signed-off-by: Kees Cook Cc: Russell King Signed-off-by: Rusty Russell diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h index ac03bdb..4da7cde 100644 --- a/arch/arm/include/uapi/asm/unistd.h +++ b/arch/arm/include/uapi/asm/unistd.h @@ -405,6 +405,7 @@ #define __NR_process_vm_readv (__NR_SYSCALL_BASE+376) #define __NR_process_vm_writev (__NR_SYSCALL_BASE+377) /* 378 for kcmp */ +#define __NR_finit_module (__NR_SYSCALL_BASE+379) /* * This may need to be greater than __NR_last_syscall+1 in order to diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 831cd38..36e27df 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -388,6 +388,7 @@ CALL(sys_process_vm_readv) CALL(sys_process_vm_writev) CALL(sys_ni_syscall) /* reserved for sys_kcmp */ + CALL(sys_finit_module) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted -- cgit v0.10.2 From 1625cee56f8e6193b5a0809a414dfa395bd9cf1e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 16 Oct 2012 12:40:03 +1030 Subject: add finit_module syscall to asm-generic This adds the finit_module syscall to the generic syscall list. Signed-off-by: Kees Cook Acked-by: Arnd Bergmann Signed-off-by: Rusty Russell diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 6e595ba..2c531f4 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -690,9 +690,11 @@ __SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \ compat_sys_process_vm_writev) #define __NR_kcmp 272 __SYSCALL(__NR_kcmp, sys_kcmp) +#define __NR_finit_module 273 +__SYSCALL(__NR_finit_module, sys_finit_module) #undef __NR_syscalls -#define __NR_syscalls 273 +#define __NR_syscalls 274 /* * All syscalls below here should go away really, -- cgit v0.10.2 From fdf90729e57812cb12d7938e2dee7c71e875fb08 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Tue, 16 Oct 2012 12:40:08 +1030 Subject: ima: support new kernel module syscall With the addition of the new kernel module syscall, which defines two arguments - a file descriptor to the kernel module and a pointer to a NULL terminated string of module arguments - it is now possible to measure and appraise kernel modules like any other file on the file system. This patch adds support to measure and appraise kernel modules in an extensible and consistent manner. To support filesystems without extended attribute support, additional patches could pass the signature as the first parameter. Signed-off-by: Mimi Zohar Signed-off-by: Rusty Russell diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 9869466..ec0a38e 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy @@ -23,7 +23,7 @@ Description: lsm: [[subj_user=] [subj_role=] [subj_type=] [obj_user=] [obj_role=] [obj_type=]] - base: func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK] + base: func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK][MODULE_CHECK] mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] fsmagic:= hex value uid:= decimal value @@ -53,6 +53,7 @@ Description: measure func=BPRM_CHECK measure func=FILE_MMAP mask=MAY_EXEC measure func=FILE_CHECK mask=MAY_READ uid=0 + measure func=MODULE_CHECK uid=0 appraise fowner=0 The default policy measures all executables in bprm_check, diff --git a/include/linux/ima.h b/include/linux/ima.h index 2c7223d..86c361e 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -18,6 +18,7 @@ extern int ima_bprm_check(struct linux_binprm *bprm); extern int ima_file_check(struct file *file, int mask); extern void ima_file_free(struct file *file); extern int ima_file_mmap(struct file *file, unsigned long prot); +extern int ima_module_check(struct file *file); #else static inline int ima_bprm_check(struct linux_binprm *bprm) @@ -40,6 +41,11 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot) return 0; } +static inline int ima_module_check(struct file *file) +{ + return 0; +} + #endif /* CONFIG_IMA_H */ #ifdef CONFIG_IMA_APPRAISE diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 6ee8826..3b2adb7 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -127,7 +127,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); struct integrity_iint_cache *integrity_iint_find(struct inode *inode); /* IMA policy related functions */ -enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR }; +enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, MODULE_CHECK, POST_SETATTR }; int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, int flags); diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index b356884..0cea3db 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -100,12 +100,12 @@ err_out: * ima_get_action - appraise & measure decision based on policy. * @inode: pointer to inode to measure * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) - * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP) + * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP, MODULE_CHECK) * * The policy is defined in terms of keypairs: * subj=, obj=, type=, func=, mask=, fsmagic= * subj,obj, and type: are LSM specific. - * func: FILE_CHECK | BPRM_CHECK | FILE_MMAP + * func: FILE_CHECK | BPRM_CHECK | FILE_MMAP | MODULE_CHECK * mask: contains the permission mask * fsmagic: hex value * diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 73c9a26..45de18e 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -280,6 +280,27 @@ int ima_file_check(struct file *file, int mask) } EXPORT_SYMBOL_GPL(ima_file_check); +/** + * ima_module_check - based on policy, collect/store/appraise measurement. + * @file: pointer to the file to be measured/appraised + * + * Measure/appraise kernel modules based on policy. + * + * Always return 0 and audit dentry_open failures. + * Return code is based upon measurement appraisal. + */ +int ima_module_check(struct file *file) +{ + int rc; + + if (!file) + rc = INTEGRITY_UNKNOWN; + else + rc = process_measurement(file, file->f_dentry->d_name.name, + MAY_EXEC, MODULE_CHECK); + return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0; +} + static int __init init_ima(void) { int error; diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index c7dacd2..af7d182 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -80,6 +80,7 @@ static struct ima_rule_entry default_rules[] = { .flags = IMA_FUNC | IMA_MASK}, {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID}, + {.action = MEASURE,.func = MODULE_CHECK, .flags = IMA_FUNC}, }; static struct ima_rule_entry default_appraise_rules[] = { @@ -401,6 +402,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) /* PATH_CHECK is for backwards compat */ else if (strcmp(args[0].from, "PATH_CHECK") == 0) entry->func = FILE_CHECK; + else if (strcmp(args[0].from, "MODULE_CHECK") == 0) + entry->func = MODULE_CHECK; else if (strcmp(args[0].from, "FILE_MMAP") == 0) entry->func = FILE_MMAP; else if (strcmp(args[0].from, "BPRM_CHECK") == 0) diff --git a/security/security.c b/security/security.c index ce88630..daa97f4 100644 --- a/security/security.c +++ b/security/security.c @@ -822,7 +822,12 @@ int security_kernel_module_request(char *kmod_name) int security_kernel_module_from_file(struct file *file) { - return security_ops->kernel_module_from_file(file); + int ret; + + ret = security_ops->kernel_module_from_file(file); + if (ret) + return ret; + return ima_module_check(file); } int security_task_fix_setuid(struct cred *new, const struct cred *old, -- cgit v0.10.2 From 71eac70257b469bd43737232bce0fd960caebee1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 2 Nov 2012 14:57:20 +1030 Subject: powerpc: add finit_module syscall. (This is just for Acks: this won't work without the actual syscall patches, sitting in my tree for -next at the moment). Acked-by: Benjamin Herrenschmidt Signed-off-by: Rusty Russell diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 8408387..d0b27f8 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -356,3 +356,4 @@ COMPAT_SYS_SPU(sendmmsg) SYSCALL_SPU(setns) COMPAT_SYS(process_vm_readv) COMPAT_SYS(process_vm_writev) +SYSCALL(finit_module) diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index 921dce6..8d219a0 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -12,7 +12,7 @@ #include -#define __NR_syscalls 353 +#define __NR_syscalls 354 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/arch/powerpc/include/uapi/asm/unistd.h b/arch/powerpc/include/uapi/asm/unistd.h index 380b5d3..8c478c6 100644 --- a/arch/powerpc/include/uapi/asm/unistd.h +++ b/arch/powerpc/include/uapi/asm/unistd.h @@ -375,6 +375,7 @@ #define __NR_setns 350 #define __NR_process_vm_readv 351 #define __NR_process_vm_writev 352 +#define __NR_finit_module 353 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */ -- cgit v0.10.2 From d890f510c8e45aaf33b8737f211ea05aecb8b460 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 5 Nov 2012 09:09:24 +1030 Subject: MODSIGN: Add modules_sign make target If CONFIG_MODULE_SIG is set, and 'make modules_sign' is called then this patch will cause the modules to get a signature appended. The make target is intended to be run after 'make modules_install', and will modify the modules in-place in the installed location. It can be used to produce signed modules after they have been processed by distribution build scripts. Signed-off-by: Josh Boyer Signed-off-by: Rusty Russell (minor typo fix) diff --git a/Makefile b/Makefile index 6cab75b..f00e0e3 100644 --- a/Makefile +++ b/Makefile @@ -981,6 +981,12 @@ _modinst_post: _modinst_ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modinst $(call cmd,depmod) +ifeq ($(CONFIG_MODULE_SIG), y) +PHONY += modules_sign +modules_sign: + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modsign +endif + else # CONFIG_MODULES # Modules not configured diff --git a/scripts/Makefile.modsign b/scripts/Makefile.modsign new file mode 100644 index 0000000..abfda62 --- /dev/null +++ b/scripts/Makefile.modsign @@ -0,0 +1,32 @@ +# ========================================================================== +# Signing modules +# ========================================================================== + +PHONY := __modsign +__modsign: + +include scripts/Kbuild.include + +__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) +modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o))) + +PHONY += $(modules) +__modsign: $(modules) + @: + +quiet_cmd_sign_ko = SIGN [M] $(2)/$(notdir $@) + cmd_sign_ko = $(mod_sign_cmd) $(2)/$(notdir $@) + +# Modules built outside the kernel source tree go into extra by default +INSTALL_MOD_DIR ?= extra +ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(patsubst %/,%,$(KBUILD_EXTMOD)),,$(@D)) + +modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D)) + +$(modules): + $(call cmd,sign_ko,$(MODLIB)/$(modinst_dir)) + +# Declare the contents of the .PHONY variable as phony. We keep that +# information in a variable se we can use it in if_changed and friends. + +.PHONY: $(PHONY) -- cgit v0.10.2 From 6f33d58794ef4cef4b2c706029810f9688bd3026 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 22 Nov 2012 12:30:25 +1030 Subject: __UNIQUE_ID() Jan Beulich points out __COUNTER__ (gcc 4.3 and above), so let's use that to create unique ids. This is better than __LINE__ which we use today, so provide a wrapper. Stanislaw Gruszka reported that some module parameters start with a digit, so we need to prepend when we for the unique id. Signed-off-by: Rusty Russell Acked-by: Jan Beulich diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h index 412bc6c..56c802c 100644 --- a/include/linux/compiler-gcc4.h +++ b/include/linux/compiler-gcc4.h @@ -31,6 +31,8 @@ #define __linktime_error(message) __attribute__((__error__(message))) +#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) + #if __GNUC_MINOR__ >= 5 /* * Mark a position in code as unreachable. This can be used to diff --git a/include/linux/compiler.h b/include/linux/compiler.h index f430e41..5f45335 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -42,6 +42,10 @@ extern void __chk_io_ptr(const volatile void __iomem *); # define __rcu #endif +/* Indirect macros required for expanded argument pasting, eg. __LINE__. */ +#define ___PASTE(a,b) a##b +#define __PASTE(a,b) ___PASTE(a,b) + #ifdef __KERNEL__ #ifdef __GNUC__ @@ -164,6 +168,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); (typeof(ptr)) (__ptr + (off)); }) #endif +/* Not-quite-unique ID. */ +#ifndef __UNIQUE_ID +# define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__) +#endif + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ -- cgit v0.10.2 From 34182eea36fc1d70d748b0947c873314980ba806 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 22 Nov 2012 12:30:25 +1030 Subject: moduleparam: use __UNIQUE_ID() Signed-off-by: Rusty Russell diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index d6a5806..137b419 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -16,17 +16,15 @@ /* Chosen so that structs with an unsigned long line up. */ #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) -#define ___module_cat(a,b) __mod_ ## a ## b -#define __module_cat(a,b) ___module_cat(a,b) #ifdef MODULE #define __MODULE_INFO(tag, name, info) \ -static const char __module_cat(name,__LINE__)[] \ +static const char __UNIQUE_ID(name)[] \ __used __attribute__((section(".modinfo"), unused, aligned(1))) \ = __stringify(tag) "=" info #else /* !MODULE */ /* This struct is here for syntactic coherency, it is not used */ #define __MODULE_INFO(tag, name, info) \ - struct __module_cat(name,__LINE__) {} + struct __UNIQUE_ID(name) {} #endif #define __MODULE_PARM_TYPE(name, _type) \ __MODULE_INFO(parmtype, name##type, #name ":" _type) -- cgit v0.10.2 From facc0a6bd494ce21e31b34fc355ecf702518272b Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 5 Dec 2012 11:55:28 +1030 Subject: ASN.1: Define indefinite length marker constant Define a constant to hold the marker value seen in an indefinite-length element. Signed-off-by: David Howells Signed-off-by: Rusty Russell diff --git a/include/linux/asn1.h b/include/linux/asn1.h index 5c3f4e4..eed6982 100644 --- a/include/linux/asn1.h +++ b/include/linux/asn1.h @@ -64,4 +64,6 @@ enum asn1_tag { ASN1_LONG_TAG = 31 /* Long form tag */ }; +#define ASN1_INDEFINITE_LENGTH 0x80 + #endif /* _LINUX_ASN1_H */ -- cgit v0.10.2 From 99cca91e370ab9224755365dda98b78eb5a5417f Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 5 Dec 2012 11:55:30 +1030 Subject: ASN.1: Use the ASN1_LONG_TAG and ASN1_INDEFINITE_LENGTH constants Use the ASN1_LONG_TAG and ASN1_INDEFINITE_LENGTH constants in the ASN.1 general decoder instead of the equivalent numbers. Signed-off-by: David Howells Signed-off-by: Rusty Russell diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c index de2c8b5..7bd2188 100644 --- a/lib/asn1_decoder.c +++ b/lib/asn1_decoder.c @@ -81,7 +81,7 @@ next_tag: goto next_tag; } - if (unlikely((tag & 0x1f) == 0x1f)) { + if (unlikely((tag & 0x1f) == ASN1_LONG_TAG)) { do { if (unlikely(datalen - dp < 2)) goto data_overrun_error; @@ -96,7 +96,7 @@ next_tag: goto next_tag; } - if (unlikely(len == 0x80)) { + if (unlikely(len == ASN1_INDEFINITE_LENGTH)) { /* Indefinite length */ if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5)) goto indefinite_len_primitive; @@ -222,7 +222,7 @@ next_op: if (unlikely(dp >= datalen - 1)) goto data_overrun_error; tag = data[dp++]; - if (unlikely((tag & 0x1f) == 0x1f)) + if (unlikely((tag & 0x1f) == ASN1_LONG_TAG)) goto long_tag_not_supported; if (op & ASN1_OP_MATCH__ANY) { @@ -254,7 +254,7 @@ next_op: len = data[dp++]; if (len > 0x7f) { - if (unlikely(len == 0x80)) { + if (unlikely(len == ASN1_INDEFINITE_LENGTH)) { /* Indefinite length */ if (unlikely(!(tag & ASN1_CONS_BIT))) goto indefinite_len_primitive; -- cgit v0.10.2 From 54523ec71f8ce99accae97c74152f14f261f7e18 Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Wed, 5 Dec 2012 12:29:04 +1030 Subject: module: Remove a extra null character at the top of module->strtab. There is a extra null character('\0') at the top of module->strtab for each module. Commit 59ef28b introduced this bug and this patch fixes it. Live dump log of the current linus git kernel(HEAD is 2844a4870): ============================================================================ crash> mod | grep loop ffffffffa01db0a0 loop 16689 (not loaded) [CONFIG_KALLSYMS] crash> module.core_symtab ffffffffa01db0a0 core_symtab = 0xffffffffa01db320crash> rd 0xffffffffa01db320 12 ffffffffa01db320: 0000005500000001 0000000000000000 ....U........... ffffffffa01db330: 0000000000000000 0002007400000002 ............t... ffffffffa01db340: ffffffffa01d8000 0000000000000038 ........8....... ffffffffa01db350: 001a00640000000e ffffffffa01daeb0 ....d........... ffffffffa01db360: 00000000000000a0 0002007400000019 ............t... ffffffffa01db370: ffffffffa01d8068 000000000000001b h............... crash> module.core_strtab ffffffffa01db0a0 core_strtab = 0xffffffffa01dbb30 "" crash> rd 0xffffffffa01dbb30 4 ffffffffa01dbb30: 615f70616d6b0000 66780063696d6f74 ..kmap_atomic.xf ffffffffa01dbb40: 73636e75665f7265 72665f646e696600 er_funcs.find_fr ============================================================================ We expect Just first one byte of '\0', but actually first two bytes are '\0'. Here is The relationship between symtab and strtab. symtab_idx strtab_idx symbol ----------------------------------------------- 0 0x1 "\0" # startab_idx should be 0 1 0x2 "kmap_atomic" 2 0xe "xfer_funcs" 3 0x19 "find_fr..." By applying this patch, it becomes as follows. symtab_idx strtab_idx symbol ----------------------------------------------- 0 0x0 "\0" # extra byte is removed 1 0x1 "kmap_atomic" 2 0xd "xfer_funcs" 3 0x18 "find_fr..." Signed-off-by: Satoru Takeuchi Cc: Masaki Kimura Cc: Rusty Russell Cc: Greg Kroah-Hartman Signed-off-by: Rusty Russell diff --git a/kernel/module.c b/kernel/module.c index a1d2ed8..79a526d 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2285,7 +2285,7 @@ static void layout_symtab(struct module *mod, struct load_info *info) Elf_Shdr *symsect = info->sechdrs + info->index.sym; Elf_Shdr *strsect = info->sechdrs + info->index.str; const Elf_Sym *src; - unsigned int i, nsrc, ndst, strtab_size; + unsigned int i, nsrc, ndst, strtab_size = 0; /* Put symbol section at end of init part of module. */ symsect->sh_flags |= SHF_ALLOC; @@ -2296,9 +2296,6 @@ static void layout_symtab(struct module *mod, struct load_info *info) src = (void *)info->hdr + symsect->sh_offset; nsrc = symsect->sh_size / sizeof(*src); - /* strtab always starts with a nul, so offset 0 is the empty string. */ - strtab_size = 1; - /* Compute total space required for the core symbols' strtab. */ for (ndst = i = 0; i < nsrc; i++) { if (i == 0 || @@ -2340,7 +2337,6 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) mod->core_symtab = dst = mod->module_core + info->symoffs; mod->core_strtab = s = mod->module_core + info->stroffs; src = mod->symtab; - *s++ = 0; for (ndst = i = 0; i < mod->num_symtab; i++) { if (i == 0 || is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) { -- cgit v0.10.2 From 82fab442f5322b016f72891c0db2436c6a6c20b7 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 11 Dec 2012 09:38:33 +1030 Subject: modules: don't hand 0 to vmalloc. In commit d0a21265dfb5fa8a David Rientjes unified various archs' module_alloc implementation (including x86) and removed the graduitous shortcut for size == 0. Then, in commit de7d2b567d040e3b, Joe Perches added a warning for zero-length vmallocs, which can happen without kallsyms on modules with no init sections (eg. zlib_deflate). Fix this once and for all; the module code has to handle zero length anyway, so get it right at the caller and remove the now-gratuitous checks within the arch-specific module_alloc implementations. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42608 Reported-by: Conrad Kostecki Cc: David Rientjes Cc: Joe Perches Signed-off-by: Rusty Russell diff --git a/arch/cris/kernel/module.c b/arch/cris/kernel/module.c index 37400f5..51123f9 100644 --- a/arch/cris/kernel/module.c +++ b/arch/cris/kernel/module.c @@ -32,8 +32,6 @@ #ifdef CONFIG_ETRAX_KMALLOCED_MODULES void *module_alloc(unsigned long size) { - if (size == 0) - return NULL; return kmalloc(size, GFP_KERNEL); } diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index 5e34ccf..2a625fb 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -214,8 +214,6 @@ static inline int reassemble_22(int as22) void *module_alloc(unsigned long size) { - if (size == 0) - return NULL; /* using RWX means less protection for modules, but it's * easier than trying to map the text, data, init_text and * init_data correctly */ diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index f1ddc0d..4435488 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -43,10 +43,6 @@ void *module_alloc(unsigned long size) { void *ret; - /* We handle the zero case fine, unlike vmalloc */ - if (size == 0) - return NULL; - ret = module_map(size); if (ret) memset(ret, 0, size); diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c index 243ffeb..4918d91 100644 --- a/arch/tile/kernel/module.c +++ b/arch/tile/kernel/module.c @@ -42,8 +42,6 @@ void *module_alloc(unsigned long size) int i = 0; int npages; - if (size == 0) - return NULL; npages = (size + PAGE_SIZE - 1) / PAGE_SIZE; pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL); if (pages == NULL) diff --git a/arch/unicore32/kernel/module.c b/arch/unicore32/kernel/module.c index 8fbe857..16bd149 100644 --- a/arch/unicore32/kernel/module.c +++ b/arch/unicore32/kernel/module.c @@ -27,9 +27,6 @@ void *module_alloc(unsigned long size) struct vm_struct *area; size = PAGE_ALIGN(size); - if (!size) - return NULL; - area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END); if (!area) return NULL; diff --git a/kernel/module.c b/kernel/module.c index 79a526d..4542ff3 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2377,7 +2377,7 @@ static void dynamic_debug_remove(struct _ddebug *debug) void * __weak module_alloc(unsigned long size) { - return size == 0 ? NULL : vmalloc_exec(size); + return vmalloc_exec(size); } static void *module_alloc_update_bounds(unsigned long size) @@ -2793,20 +2793,23 @@ static int move_module(struct module *mod, struct load_info *info) memset(ptr, 0, mod->core_size); mod->module_core = ptr; - ptr = module_alloc_update_bounds(mod->init_size); - /* - * The pointer to this block is stored in the module structure - * which is inside the block. This block doesn't need to be - * scanned as it contains data and code that will be freed - * after the module is initialized. - */ - kmemleak_ignore(ptr); - if (!ptr && mod->init_size) { - module_free(mod, mod->module_core); - return -ENOMEM; - } - memset(ptr, 0, mod->init_size); - mod->module_init = ptr; + if (mod->init_size) { + ptr = module_alloc_update_bounds(mod->init_size); + /* + * The pointer to this block is stored in the module structure + * which is inside the block. This block doesn't need to be + * scanned as it contains data and code that will be freed + * after the module is initialized. + */ + kmemleak_ignore(ptr); + if (!ptr) { + module_free(mod, mod->module_core); + return -ENOMEM; + } + memset(ptr, 0, mod->init_size); + mod->module_init = ptr; + } else + mod->module_init = NULL; /* Transfer each section which specifies SHF_ALLOC */ pr_debug("final section addresses:\n"); -- cgit v0.10.2 From 919aa45e43a84d40c27c83f6117cfa6542cee14e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 11 Dec 2012 11:37:13 +1030 Subject: MODSIGN: Avoid using .incbin in C source Using the asm .incbin statement in C sources breaks any gcc wrapper which assumes that preprocessed C source is self-contained. Use a separate .S file to include the siging key and certificate. [ This means we no longer need SYMBOL_PREFIX which is defined in kernel.h from cbdbf2abb7844548a7d7a6a2ae7af6b6fbcea401, so I removed it -- RR ] Tested-by: Michal Marek Signed-off-by: Takashi Iwai Signed-off-by: Rusty Russell Acked-by: James Hogan diff --git a/kernel/Makefile b/kernel/Makefile index 86e3285..0bd9d43 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -54,7 +54,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o obj-$(CONFIG_PROVE_LOCKING) += spinlock.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o +obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_KEXEC) += kexec.o @@ -139,7 +139,7 @@ ifeq ($(CONFIG_MODULE_SIG),y) extra_certificates: touch $@ -kernel/modsign_pubkey.o: signing_key.x509 extra_certificates +kernel/modsign_certificate.o: signing_key.x509 extra_certificates ############################################################################### # diff --git a/kernel/modsign_certificate.S b/kernel/modsign_certificate.S new file mode 100644 index 0000000..246b4c6 --- /dev/null +++ b/kernel/modsign_certificate.S @@ -0,0 +1,19 @@ +/* SYMBOL_PREFIX defined on commandline from CONFIG_SYMBOL_PREFIX */ +#ifndef SYMBOL_PREFIX +#define ASM_SYMBOL(sym) sym +#else +#define PASTE2(x,y) x##y +#define PASTE(x,y) PASTE2(x,y) +#define ASM_SYMBOL(sym) PASTE(SYMBOL_PREFIX, sym) +#endif + +#define GLOBAL(name) \ + .globl ASM_SYMBOL(name); \ + ASM_SYMBOL(name): + + .section ".init.data","aw" + +GLOBAL(modsign_certificate_list) + .incbin "signing_key.x509" + .incbin "extra_certificates" +GLOBAL(modsign_certificate_list_end) diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c index 767e559..045504f 100644 --- a/kernel/modsign_pubkey.c +++ b/kernel/modsign_pubkey.c @@ -20,12 +20,6 @@ struct key *modsign_keyring; extern __initdata const u8 modsign_certificate_list[]; extern __initdata const u8 modsign_certificate_list_end[]; -asm(".section .init.data,\"aw\"\n" - SYMBOL_PREFIX "modsign_certificate_list:\n" - ".incbin \"signing_key.x509\"\n" - ".incbin \"extra_certificates\"\n" - SYMBOL_PREFIX "modsign_certificate_list_end:" - ); /* * We need to make sure ccache doesn't cache the .o file as it doesn't notice -- cgit v0.10.2 From e10e1774efbdaec54698454200619a03a01e1d64 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Tue, 11 Dec 2012 12:26:22 +1030 Subject: MODSIGN: Fix kbuild output when using default extra_certificates Reported-by: Peter Foley Signed-off-by: Michal Marek Acked-by: Peter Foley Signed-off-by: Rusty Russell diff --git a/kernel/Makefile b/kernel/Makefile index 0bd9d43..17f90b6 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -136,8 +136,12 @@ ifeq ($(CONFIG_MODULE_SIG),y) # # Pull the signing certificate and any extra certificates into the kernel # + +quiet_cmd_touch = TOUCH $@ + cmd_touch = touch $@ + extra_certificates: - touch $@ + $(call cmd,touch) kernel/modsign_certificate.o: signing_key.x509 extra_certificates -- cgit v0.10.2 From 86794b43569c9b8936dff2e8eed503393379af6e Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Fri, 14 Dec 2012 11:19:24 +0800 Subject: blackfin: SEC: clean up SEC interrupt initialization Append the SEC IRQ after the IVG6, which is consistent to BF5xx SIC. Exclude SIC irqchip fucntions from SEC code. Call handle_fasteoi_irq in SEC error and fault handler. Signed-off-by: Sonic Zhang Signed-off-by: Bob Liu diff --git a/arch/blackfin/include/mach-common/irq.h b/arch/blackfin/include/mach-common/irq.h index cab14e9..af9fc81 100644 --- a/arch/blackfin/include/mach-common/irq.h +++ b/arch/blackfin/include/mach-common/irq.h @@ -40,8 +40,6 @@ #define IRQ_HWERR 5 /* Hardware Error */ #define IRQ_CORETMR 6 /* Core timer */ -#define BFIN_IRQ(x) ((x) + 7) - #define IVG7 7 #define IVG8 8 #define IVG9 9 @@ -52,6 +50,9 @@ #define IVG14 14 #define IVG15 15 +#define BFIN_IRQ(x) ((x) + IVG7) +#define BFIN_SYSIRQ(x) ((x) - IVG7) + #define NR_IRQS (NR_MACH_IRQS + NR_SPARE_IRQS) #endif diff --git a/arch/blackfin/mach-bf609/include/mach/irq.h b/arch/blackfin/mach-bf609/include/mach/irq.h index 23e74cd..fa0843d 100644 --- a/arch/blackfin/mach-bf609/include/mach/irq.h +++ b/arch/blackfin/mach-bf609/include/mach/irq.h @@ -9,9 +9,6 @@ #include -#undef BFIN_IRQ -#define BFIN_IRQ(x) ((x) + IVG15) - #define NR_PERI_INTS (5 * 32) #define IRQ_SEC_ERR BFIN_IRQ(0) /* SEC Error */ diff --git a/arch/blackfin/mach-bf609/pm.c b/arch/blackfin/mach-bf609/pm.c index dacafc1..ad505d9 100644 --- a/arch/blackfin/mach-bf609/pm.c +++ b/arch/blackfin/mach-bf609/pm.c @@ -174,7 +174,6 @@ void bfin_hibernate_syscontrol(void) bfin_write32(DPM0_RESTORE5, bfin_read32(DPM0_RESTORE5) | 4); } -#define IRQ_SID(irq) ((irq) - IVG15) asmlinkage void enter_deepsleep(void); __attribute__((l1_text)) @@ -311,7 +310,7 @@ static irqreturn_t test_isr(int irq, void *dev_id) { printk(KERN_DEBUG "gpio irq %d\n", irq); if (irq == 231) - bfin_sec_raise_irq(IRQ_SID(IRQ_SOFT1)); + bfin_sec_raise_irq(BFIN_SYSIRQ(IRQ_SOFT1)); return IRQ_HANDLED; } diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index 902bebc..83ff311 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -28,12 +28,6 @@ #include #include -#ifndef SEC_GCTL -# define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1)) -#else -# define SIC_SYSIRQ(irq) ((irq) - IVG15) -#endif - /* * NOTES: * - we have separated the physical Hardware interrupt from the @@ -141,13 +135,13 @@ static void bfin_core_unmask_irq(struct irq_data *d) return; } +#ifndef SEC_GCTL void bfin_internal_mask_irq(unsigned int irq) { unsigned long flags = hard_local_irq_save(); -#ifndef SEC_GCTL #ifdef SIC_IMASK0 - unsigned mask_bank = SIC_SYSIRQ(irq) / 32; - unsigned mask_bit = SIC_SYSIRQ(irq) % 32; + unsigned mask_bank = BFIN_SYSIRQ(irq) / 32; + unsigned mask_bit = BFIN_SYSIRQ(irq) % 32; bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) & ~(1 << mask_bit)); # if defined(CONFIG_SMP) || defined(CONFIG_ICC) @@ -156,9 +150,8 @@ void bfin_internal_mask_irq(unsigned int irq) # endif #else bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() & - ~(1 << SIC_SYSIRQ(irq))); + ~(1 << BFIN_SYSIRQ(irq))); #endif /* end of SIC_IMASK0 */ -#endif hard_local_irq_restore(flags); } @@ -176,10 +169,9 @@ void bfin_internal_unmask_irq(unsigned int irq) { unsigned long flags = hard_local_irq_save(); -#ifndef SEC_GCTL #ifdef SIC_IMASK0 - unsigned mask_bank = SIC_SYSIRQ(irq) / 32; - unsigned mask_bit = SIC_SYSIRQ(irq) % 32; + unsigned mask_bank = BFIN_SYSIRQ(irq) / 32; + unsigned mask_bit = BFIN_SYSIRQ(irq) % 32; # ifdef CONFIG_SMP if (cpumask_test_cpu(0, affinity)) # endif @@ -194,17 +186,103 @@ void bfin_internal_unmask_irq(unsigned int irq) # endif #else bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | - (1 << SIC_SYSIRQ(irq))); + (1 << BFIN_SYSIRQ(irq))); +#endif + hard_local_irq_restore(flags); +} + +#ifdef CONFIG_SMP +static void bfin_internal_unmask_irq_chip(struct irq_data *d) +{ + bfin_internal_unmask_irq_affinity(d->irq, d->affinity); +} + +static int bfin_internal_set_affinity(struct irq_data *d, + const struct cpumask *mask, bool force) +{ + bfin_internal_mask_irq(d->irq); + bfin_internal_unmask_irq_affinity(d->irq, mask); + + return 0; +} +#else +static void bfin_internal_unmask_irq_chip(struct irq_data *d) +{ + bfin_internal_unmask_irq(d->irq); +} #endif + +#if defined(CONFIG_PM) +int bfin_internal_set_wake(unsigned int irq, unsigned int state) +{ + u32 bank, bit, wakeup = 0; + unsigned long flags; + bank = BFIN_SYSIRQ(irq) / 32; + bit = BFIN_SYSIRQ(irq) % 32; + + switch (irq) { +#ifdef IRQ_RTC + case IRQ_RTC: + wakeup |= WAKE; + break; +#endif +#ifdef IRQ_CAN0_RX + case IRQ_CAN0_RX: + wakeup |= CANWE; + break; #endif +#ifdef IRQ_CAN1_RX + case IRQ_CAN1_RX: + wakeup |= CANWE; + break; +#endif +#ifdef IRQ_USB_INT0 + case IRQ_USB_INT0: + wakeup |= USBWE; + break; +#endif +#ifdef CONFIG_BF54x + case IRQ_CNT: + wakeup |= ROTWE; + break; +#endif + default: + break; + } + + flags = hard_local_irq_save(); + + if (state) { + bfin_sic_iwr[bank] |= (1 << bit); + vr_wakeup |= wakeup; + + } else { + bfin_sic_iwr[bank] &= ~(1 << bit); + vr_wakeup &= ~wakeup; + } + hard_local_irq_restore(flags); + + return 0; } -#ifdef SEC_GCTL +static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state) +{ + return bfin_internal_set_wake(d->irq, state); +} +#else +inline int bfin_internal_set_wake(unsigned int irq, unsigned int state) +{ + return 0; +} +# define bfin_internal_set_wake_chip NULL +#endif + +#else /* SEC_GCTL */ static void bfin_sec_preflow_handler(struct irq_data *d) { unsigned long flags = hard_local_irq_save(); - unsigned int sid = SIC_SYSIRQ(d->irq); + unsigned int sid = BFIN_SYSIRQ(d->irq); bfin_write_SEC_SCI(0, SEC_CSID, sid); @@ -214,7 +292,7 @@ static void bfin_sec_preflow_handler(struct irq_data *d) static void bfin_sec_mask_ack_irq(struct irq_data *d) { unsigned long flags = hard_local_irq_save(); - unsigned int sid = SIC_SYSIRQ(d->irq); + unsigned int sid = BFIN_SYSIRQ(d->irq); bfin_write_SEC_SCI(0, SEC_CSID, sid); @@ -224,7 +302,7 @@ static void bfin_sec_mask_ack_irq(struct irq_data *d) static void bfin_sec_unmask_irq(struct irq_data *d) { unsigned long flags = hard_local_irq_save(); - unsigned int sid = SIC_SYSIRQ(d->irq); + unsigned int sid = BFIN_SYSIRQ(d->irq); bfin_write32(SEC_END, sid); @@ -269,7 +347,7 @@ static void bfin_sec_enable_sci(unsigned int sid) unsigned long flags = hard_local_irq_save(); uint32_t reg_sctl = bfin_read_SEC_SCTL(sid); - if (sid == SIC_SYSIRQ(IRQ_WATCH0)) + if (sid == BFIN_SYSIRQ(IRQ_WATCH0)) reg_sctl |= SEC_SCTL_FAULT_EN; else reg_sctl |= SEC_SCTL_INT_EN; @@ -292,7 +370,7 @@ static void bfin_sec_disable_sci(unsigned int sid) static void bfin_sec_enable(struct irq_data *d) { unsigned long flags = hard_local_irq_save(); - unsigned int sid = SIC_SYSIRQ(d->irq); + unsigned int sid = BFIN_SYSIRQ(d->irq); bfin_sec_enable_sci(sid); bfin_sec_enable_ssi(sid); @@ -303,7 +381,7 @@ static void bfin_sec_enable(struct irq_data *d) static void bfin_sec_disable(struct irq_data *d) { unsigned long flags = hard_local_irq_save(); - unsigned int sid = SIC_SYSIRQ(d->irq); + unsigned int sid = BFIN_SYSIRQ(d->irq); bfin_sec_disable_sci(sid); bfin_sec_disable_ssi(sid); @@ -328,9 +406,10 @@ static void bfin_sec_set_priority(unsigned int sec_int_levels, u8 *sec_int_prior hard_local_irq_restore(flags); } -void bfin_sec_raise_irq(unsigned int sid) +void bfin_sec_raise_irq(unsigned int irq) { unsigned long flags = hard_local_irq_save(); + unsigned int sid = BFIN_SYSIRQ(irq); bfin_write32(SEC_RAISE, sid); @@ -341,8 +420,13 @@ static void init_software_driven_irq(void) { bfin_sec_set_ssi_coreid(34, 0); bfin_sec_set_ssi_coreid(35, 1); + + bfin_sec_enable_sci(35); + bfin_sec_enable_ssi(35); bfin_sec_set_ssi_coreid(36, 0); bfin_sec_set_ssi_coreid(37, 1); + bfin_sec_enable_sci(37); + bfin_sec_enable_ssi(37); } void bfin_sec_resume(void) @@ -412,6 +496,8 @@ void handle_sec_fault(unsigned int irq, struct irq_desc *desc) } raw_spin_unlock(&desc->lock); + + handle_fasteoi_irq(irq, desc); } void handle_core_fault(unsigned int irq, struct irq_desc *desc) @@ -431,105 +517,18 @@ void handle_core_fault(unsigned int irq, struct irq_desc *desc) printk(KERN_NOTICE "Kernel Stack\n"); show_stack(current, NULL); print_modules(); - panic("Kernel core hardware error"); + panic("Core 0 hardware error"); break; case IRQ_C0_NMI_L1_PARITY_ERR: - panic("NMI occurs unexpectedly"); + panic("Core 0 NMI L1 parity error"); break; default: - panic("Core 1 fault occurs unexpectedly"); + panic("Core 1 fault %d occurs unexpectedly", irq); } raw_spin_unlock(&desc->lock); } -#endif - -#ifdef CONFIG_SMP -static void bfin_internal_unmask_irq_chip(struct irq_data *d) -{ - bfin_internal_unmask_irq_affinity(d->irq, d->affinity); -} - -static int bfin_internal_set_affinity(struct irq_data *d, - const struct cpumask *mask, bool force) -{ - bfin_internal_mask_irq(d->irq); - bfin_internal_unmask_irq_affinity(d->irq, mask); - - return 0; -} -#else -static void bfin_internal_unmask_irq_chip(struct irq_data *d) -{ - bfin_internal_unmask_irq(d->irq); -} -#endif - -#if defined(CONFIG_PM) && !defined(SEC_GCTL) -int bfin_internal_set_wake(unsigned int irq, unsigned int state) -{ - u32 bank, bit, wakeup = 0; - unsigned long flags; - bank = SIC_SYSIRQ(irq) / 32; - bit = SIC_SYSIRQ(irq) % 32; - - switch (irq) { -#ifdef IRQ_RTC - case IRQ_RTC: - wakeup |= WAKE; - break; -#endif -#ifdef IRQ_CAN0_RX - case IRQ_CAN0_RX: - wakeup |= CANWE; - break; -#endif -#ifdef IRQ_CAN1_RX - case IRQ_CAN1_RX: - wakeup |= CANWE; - break; -#endif -#ifdef IRQ_USB_INT0 - case IRQ_USB_INT0: - wakeup |= USBWE; - break; -#endif -#ifdef CONFIG_BF54x - case IRQ_CNT: - wakeup |= ROTWE; - break; -#endif - default: - break; - } - - flags = hard_local_irq_save(); - - if (state) { - bfin_sic_iwr[bank] |= (1 << bit); - vr_wakeup |= wakeup; - - } else { - bfin_sic_iwr[bank] &= ~(1 << bit); - vr_wakeup &= ~wakeup; - } - - hard_local_irq_restore(flags); - - return 0; -} - -static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state) -{ - return bfin_internal_set_wake(d->irq, state); -} -#else -inline int bfin_internal_set_wake(unsigned int irq, unsigned int state) -{ - return 0; -} -# define bfin_internal_set_wake_chip NULL -#endif +#endif /* SEC_GCTL */ static struct irq_chip bfin_core_irqchip = { .name = "CORE", @@ -537,6 +536,7 @@ static struct irq_chip bfin_core_irqchip = { .irq_unmask = bfin_core_unmask_irq, }; +#ifndef SEC_GCTL static struct irq_chip bfin_internal_irqchip = { .name = "INTN", .irq_mask = bfin_internal_mask_irq_chip, @@ -548,8 +548,7 @@ static struct irq_chip bfin_internal_irqchip = { #endif .irq_set_wake = bfin_internal_set_wake_chip, }; - -#ifdef SEC_GCTL +#else static struct irq_chip bfin_sec_irqchip = { .name = "SEC", .irq_mask_ack = bfin_sec_mask_ack_irq, @@ -1138,7 +1137,9 @@ static int bfin_gpio_set_wake(struct irq_data *d, unsigned int state) return -EINVAL; } +#ifndef SEC_GCTL bfin_internal_set_wake(pint_irq, state); +#endif return 0; } @@ -1173,7 +1174,7 @@ static int sec_suspend(void) u32 bank; for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) - save_pint_sec_ctl[bank] = bfin_read_SEC_SCTL(bank + SIC_SYSIRQ(IRQ_PINT0)); + save_pint_sec_ctl[bank] = bfin_read_SEC_SCTL(bank + BFIN_SYSIRQ(IRQ_PINT0)); return 0; } @@ -1187,7 +1188,7 @@ static void sec_resume(void) bfin_write_SEC_SCI(0, SEC_CCTL, SEC_CCTL_EN | SEC_CCTL_NMI_EN); for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) - bfin_write_SEC_SCTL(bank + SIC_SYSIRQ(IRQ_PINT0), save_pint_sec_ctl[bank]); + bfin_write_SEC_SCTL(bank + BFIN_SYSIRQ(IRQ_PINT0), save_pint_sec_ctl[bank]); } static struct syscore_ops sec_pm_syscore_ops = { @@ -1538,33 +1539,26 @@ int __init init_arch_irq(void) for (irq = 0; irq <= SYS_IRQS; irq++) { if (irq <= IRQ_CORETMR) { - irq_set_chip(irq, &bfin_core_irqchip); -#ifdef CONFIG_TICKSOURCE_CORETMR + irq_set_chip_and_handler(irq, &bfin_core_irqchip, + handle_simple_irq); +#if defined(CONFIG_TICKSOURCE_CORETMR) && defined(CONFIG_SMP) if (irq == IRQ_CORETMR) -# ifdef CONFIG_SMP irq_set_handler(irq, handle_percpu_irq); -# else - irq_set_handler(irq, handle_simple_irq); -# endif #endif - } else if (irq < BFIN_IRQ(0)) { - irq_set_chip_and_handler(irq, &bfin_internal_irqchip, - handle_simple_irq); - } else if (irq == IRQ_SEC_ERR) { - irq_set_chip_and_handler(irq, &bfin_sec_irqchip, - handle_sec_fault); - } else if (irq < CORE_IRQS && irq >= IRQ_C0_DBL_FAULT) { - irq_set_chip_and_handler(irq, &bfin_sec_irqchip, - handle_core_fault); } else if (irq >= BFIN_IRQ(21) && irq <= BFIN_IRQ(26)) { irq_set_chip(irq, &bfin_sec_irqchip); irq_set_chained_handler(irq, bfin_demux_gpio_irq); } else if (irq >= BFIN_IRQ(34) && irq <= BFIN_IRQ(37)) { - irq_set_chip(irq, &bfin_sec_irqchip); - irq_set_handler(irq, handle_percpu_irq); - } else { irq_set_chip_and_handler(irq, &bfin_sec_irqchip, - handle_fasteoi_irq); + handle_percpu_irq); + } else { + irq_set_chip(irq, &bfin_sec_irqchip); + if (irq == IRQ_SEC_ERR) + irq_set_handler(irq, handle_sec_fault); + else if (irq >= IRQ_C0_DBL_FAULT && irq < CORE_IRQS) + irq_set_handler(irq, handle_core_fault); + else + irq_set_handler(irq, handle_fasteoi_irq); __irq_set_preflow_handler(irq, bfin_sec_preflow_handler); } } @@ -1593,8 +1587,8 @@ int __init init_arch_irq(void) bfin_write_SEC_FCTL(SEC_FCTL_EN | SEC_FCTL_SYSRST_EN | SEC_FCTL_FLTIN_EN); - bfin_sec_enable_sci(SIC_SYSIRQ(IRQ_WATCH0)); - bfin_sec_enable_ssi(SIC_SYSIRQ(IRQ_WATCH0)); + bfin_sec_enable_sci(BFIN_SYSIRQ(IRQ_WATCH0)); + bfin_sec_enable_ssi(BFIN_SYSIRQ(IRQ_WATCH0)); bfin_write_SEC_SCI(0, SEC_CCTL, SEC_CCTL_RESET); udelay(100); bfin_write_SEC_GCTL(SEC_GCTL_EN); -- cgit v0.10.2 From 20e8ac3eea4dcfeea6ebeae57cd2c739fa48da11 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 14 Dec 2012 15:58:58 +0900 Subject: pwm: samsung: add missing s3c->pwm_id assignment The s3c->pwm_id is used to calculate offset of related register. Signed-off-by: Joonyoung Shim Signed-off-by: Thierry Reding diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index 023a3be..0704a2a 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -222,6 +222,7 @@ static int s3c_pwm_probe(struct platform_device *pdev) /* calculate base of control bits in TCON */ s3c->tcon_base = id == 0 ? 0 : (id * 4) + 4; + s3c->pwm_id = id; s3c->chip.dev = &pdev->dev; s3c->chip.ops = &s3c_pwm_ops; s3c->chip.base = -1; -- cgit v0.10.2 From d0b0885316ab7a97cc8a19027905de3ff7bd1e79 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 11 Dec 2012 14:53:35 +0100 Subject: s390/pci: performance statistics and debug infrastructure Add support for reading the PCI function measurement block counters provided by the hypervisor. Add two s390 debug features, one for critical errors and one for tracing and provide wrappers to log data. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index a6175ad..b1fa93c 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -9,6 +9,7 @@ #include #include #include +#include #define PCIBIOS_MIN_IO 0x1000 #define PCIBIOS_MIN_MEM 0x10000000 @@ -33,6 +34,25 @@ int pci_proc_domain(struct pci_bus *); #define ZPCI_FC_BLOCKED 0x20 #define ZPCI_FC_DMA_ENABLED 0x10 +struct zpci_fmb { + u32 format : 8; + u32 dma_valid : 1; + u32 : 23; + u32 samples; + u64 last_update; + /* hardware counters */ + u64 ld_ops; + u64 st_ops; + u64 stb_ops; + u64 rpcit_ops; + u64 dma_rbytes; + u64 dma_wbytes; + /* software counters */ + atomic64_t allocated_pages; + atomic64_t mapped_pages; + atomic64_t unmapped_pages; +} __packed __aligned(16); + struct msi_map { unsigned long irq; struct msi_desc *msi; @@ -92,7 +112,15 @@ struct zpci_dev { u64 end_dma; /* End of available DMA addresses */ u64 dma_mask; /* DMA address space mask */ + /* Function measurement block */ + struct zpci_fmb *fmb; + u16 fmb_update; /* update interval */ + enum pci_bus_speed max_bus_speed; + + struct dentry *debugfs_dev; + struct dentry *debugfs_perf; + struct dentry *debugfs_debug; }; struct pci_hp_callback_ops { @@ -155,4 +183,15 @@ extern struct list_head zpci_list; extern struct pci_hp_callback_ops hotplug_ops; extern unsigned int pci_probe; +/* FMB */ +int zpci_fmb_enable_device(struct zpci_dev *); +int zpci_fmb_disable_device(struct zpci_dev *); + +/* Debug */ +int zpci_debug_init(void); +void zpci_debug_exit(void); +void zpci_debug_init_device(struct zpci_dev *); +void zpci_debug_exit_device(struct zpci_dev *); +void zpci_debug_info(struct zpci_dev *, struct seq_file *); + #endif diff --git a/arch/s390/include/asm/pci_debug.h b/arch/s390/include/asm/pci_debug.h new file mode 100644 index 0000000..6bbec42 --- /dev/null +++ b/arch/s390/include/asm/pci_debug.h @@ -0,0 +1,36 @@ +#ifndef _S390_ASM_PCI_DEBUG_H +#define _S390_ASM_PCI_DEBUG_H + +#include + +extern debug_info_t *pci_debug_msg_id; +extern debug_info_t *pci_debug_err_id; + +#ifdef CONFIG_PCI_DEBUG +#define zpci_dbg(fmt, args...) \ + do { \ + if (pci_debug_msg_id->level >= 2) \ + debug_sprintf_event(pci_debug_msg_id, 2, fmt , ## args);\ + } while (0) + +#else /* !CONFIG_PCI_DEBUG */ +#define zpci_dbg(fmt, args...) do { } while (0) +#endif + +#define zpci_err(text...) \ + do { \ + char debug_buffer[16]; \ + snprintf(debug_buffer, 16, text); \ + debug_text_event(pci_debug_err_id, 0, debug_buffer); \ + } while (0) + +static inline void zpci_err_hex(void *addr, int len) +{ + while (len > 0) { + debug_event(pci_debug_err_id, 0, (void *) addr, len); + len -= pci_debug_err_id->buf_size; + addr += pci_debug_err_id->buf_size; + } +} + +#endif diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile index ab0827b..f0f426a 100644 --- a/arch/s390/pci/Makefile +++ b/arch/s390/pci/Makefile @@ -3,4 +3,4 @@ # obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o \ - pci_sysfs.o pci_event.o + pci_sysfs.o pci_event.o pci_debug.o diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 7ed38e5..8fa416b 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -98,6 +98,10 @@ EXPORT_SYMBOL_GPL(zpci_iomap_start); static int __read_mostly aisb_max; static struct kmem_cache *zdev_irq_cache; +static struct kmem_cache *zdev_fmb_cache; + +debug_info_t *pci_debug_msg_id; +debug_info_t *pci_debug_err_id; static inline int irq_to_msi_nr(unsigned int irq) { @@ -216,6 +220,7 @@ struct mod_pci_args { u64 base; u64 limit; u64 iota; + u64 fmb_addr; }; static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args *args) @@ -232,6 +237,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args fib->pba = args->base; fib->pal = args->limit; fib->iota = args->iota; + fib->fmb_addr = args->fmb_addr; rc = mpcifc_instr(req, fib); free_page((unsigned long) fib); @@ -242,7 +248,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas, u64 base, u64 limit, u64 iota) { - struct mod_pci_args args = { base, limit, iota }; + struct mod_pci_args args = { base, limit, iota, 0 }; WARN_ON_ONCE(iota & 0x3fff); args.iota |= ZPCI_IOTA_RTTO_FLAG; @@ -252,7 +258,7 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas, /* Modify PCI: Unregister I/O address translation parameters */ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas) { - struct mod_pci_args args = { 0, 0, 0 }; + struct mod_pci_args args = { 0, 0, 0, 0 }; return mod_pci(zdev, ZPCI_MOD_FC_DEREG_IOAT, dmaas, &args); } @@ -260,11 +266,46 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas) /* Modify PCI: Unregister adapter interruptions */ static int zpci_unregister_airq(struct zpci_dev *zdev) { - struct mod_pci_args args = { 0, 0, 0 }; + struct mod_pci_args args = { 0, 0, 0, 0 }; return mod_pci(zdev, ZPCI_MOD_FC_DEREG_INT, 0, &args); } +/* Modify PCI: Set PCI function measurement parameters */ +int zpci_fmb_enable_device(struct zpci_dev *zdev) +{ + struct mod_pci_args args = { 0, 0, 0, 0 }; + + if (zdev->fmb) + return -EINVAL; + + zdev->fmb = kmem_cache_alloc(zdev_fmb_cache, GFP_KERNEL); + if (!zdev->fmb) + return -ENOMEM; + memset(zdev->fmb, 0, sizeof(*zdev->fmb)); + WARN_ON((u64) zdev->fmb & 0xf); + + args.fmb_addr = virt_to_phys(zdev->fmb); + return mod_pci(zdev, ZPCI_MOD_FC_SET_MEASURE, 0, &args); +} + +/* Modify PCI: Disable PCI function measurement */ +int zpci_fmb_disable_device(struct zpci_dev *zdev) +{ + struct mod_pci_args args = { 0, 0, 0, 0 }; + int rc; + + if (!zdev->fmb) + return -EINVAL; + + /* Function measurement is disabled if fmb address is zero */ + rc = mod_pci(zdev, ZPCI_MOD_FC_SET_MEASURE, 0, &args); + + kmem_cache_free(zdev_fmb_cache, zdev->fmb); + zdev->fmb = NULL; + return rc; +} + #define ZPCI_PCIAS_CFGSPC 15 static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len) @@ -633,6 +674,7 @@ static void zpci_remove_device(struct pci_dev *pdev) dev_info(&pdev->dev, "Removing device %u\n", zdev->domain); zdev->state = ZPCI_FN_STATE_CONFIGURED; zpci_dma_exit_device(zdev); + zpci_fmb_disable_device(zdev); zpci_sysfs_remove_device(&pdev->dev); zpci_unmap_resources(pdev); list_del(&zdev->entry); /* can be called from init */ @@ -799,6 +841,16 @@ static void zpci_irq_exit(void) kfree(bucket); } +void zpci_debug_info(struct zpci_dev *zdev, struct seq_file *m) +{ + if (!zdev) + return; + + seq_printf(m, "global irq retries: %u\n", atomic_read(&irq_retries)); + seq_printf(m, "aibv[0]:%016lx aibv[1]:%016lx aisb:%016lx\n", + get_imap(0)->aibv, get_imap(1)->aibv, *bucket->aisb); +} + static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size, unsigned long flags, int domain) { @@ -994,6 +1046,8 @@ int zpci_scan_device(struct zpci_dev *zdev) goto out; } + zpci_debug_init_device(zdev); + zpci_fmb_enable_device(zdev); zpci_map_resources(zdev); pci_bus_add_devices(zdev->bus); @@ -1020,6 +1074,11 @@ static int zpci_mem_init(void) if (!zdev_irq_cache) goto error_zdev; + zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb), + 16, 0, NULL); + if (!zdev_fmb_cache) + goto error_fmb; + /* TODO: use realloc */ zpci_iomap_start = kzalloc(ZPCI_IOMAP_MAX_ENTRIES * sizeof(*zpci_iomap_start), GFP_KERNEL); @@ -1028,6 +1087,8 @@ static int zpci_mem_init(void) return 0; error_iomap: + kmem_cache_destroy(zdev_fmb_cache); +error_fmb: kmem_cache_destroy(zdev_irq_cache); error_zdev: return -ENOMEM; @@ -1037,6 +1098,7 @@ static void zpci_mem_exit(void) { kfree(zpci_iomap_start); kmem_cache_destroy(zdev_irq_cache); + kmem_cache_destroy(zdev_fmb_cache); } unsigned int pci_probe = 1; @@ -1066,6 +1128,10 @@ static int __init pci_base_init(void) test_facility(69), test_facility(70), test_facility(71)); + rc = zpci_debug_init(); + if (rc) + return rc; + rc = zpci_mem_init(); if (rc) goto out_mem; @@ -1098,6 +1164,7 @@ out_irq: out_hash: zpci_mem_exit(); out_mem: + zpci_debug_exit(); return rc; } subsys_initcall(pci_base_init); diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index 7f4ce8d..2c84714 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c @@ -51,6 +51,7 @@ static void clp_store_query_pci_fngrp(struct zpci_dev *zdev, zdev->tlb_refresh = response->refresh; zdev->dma_mask = response->dasm; zdev->msi_addr = response->msia; + zdev->fmb_update = response->mui; pr_debug("Supported number of MSI vectors: %u\n", response->noi); switch (response->version) { diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c new file mode 100644 index 0000000..a303c95 --- /dev/null +++ b/arch/s390/pci/pci_debug.c @@ -0,0 +1,193 @@ +/* + * Copyright IBM Corp. 2012 + * + * Author(s): + * Jan Glauber + */ + +#define COMPONENT "zPCI" +#define pr_fmt(fmt) COMPONENT ": " fmt + +#include +#include +#include +#include +#include + +#include + +static struct dentry *debugfs_root; + +static char *pci_perf_names[] = { + /* hardware counters */ + "Load operations", + "Store operations", + "Store block operations", + "Refresh operations", + "DMA read bytes", + "DMA write bytes", + /* software counters */ + "Allocated pages", + "Mapped pages", + "Unmapped pages", +}; + +static int pci_perf_show(struct seq_file *m, void *v) +{ + struct zpci_dev *zdev = m->private; + u64 *stat; + int i; + + if (!zdev) + return 0; + if (!zdev->fmb) + return seq_printf(m, "FMB statistics disabled\n"); + + /* header */ + seq_printf(m, "FMB @ %p\n", zdev->fmb); + seq_printf(m, "Update interval: %u ms\n", zdev->fmb_update); + seq_printf(m, "Samples: %u\n", zdev->fmb->samples); + seq_printf(m, "Last update TOD: %Lx\n", zdev->fmb->last_update); + + /* hardware counters */ + stat = (u64 *) &zdev->fmb->ld_ops; + for (i = 0; i < 4; i++) + seq_printf(m, "%26s:\t%llu\n", + pci_perf_names[i], *(stat + i)); + if (zdev->fmb->dma_valid) + for (i = 4; i < 6; i++) + seq_printf(m, "%26s:\t%llu\n", + pci_perf_names[i], *(stat + i)); + /* software counters */ + for (i = 6; i < ARRAY_SIZE(pci_perf_names); i++) + seq_printf(m, "%26s:\t%llu\n", + pci_perf_names[i], + atomic64_read((atomic64_t *) (stat + i))); + + return 0; +} + +static ssize_t pci_perf_seq_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *off) +{ + struct zpci_dev *zdev = ((struct seq_file *) file->private_data)->private; + unsigned long val; + int rc; + + if (!zdev) + return 0; + + rc = kstrtoul_from_user(ubuf, count, 10, &val); + if (rc) + return rc; + + switch (val) { + case 0: + rc = zpci_fmb_disable_device(zdev); + if (rc) + return rc; + break; + case 1: + rc = zpci_fmb_enable_device(zdev); + if (rc) + return rc; + break; + } + return count; +} + +static int pci_perf_seq_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, pci_perf_show, + filp->f_path.dentry->d_inode->i_private); +} + +static const struct file_operations debugfs_pci_perf_fops = { + .open = pci_perf_seq_open, + .read = seq_read, + .write = pci_perf_seq_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int pci_debug_show(struct seq_file *m, void *v) +{ + struct zpci_dev *zdev = m->private; + + zpci_debug_info(zdev, m); + return 0; +} + +static int pci_debug_seq_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, pci_debug_show, + filp->f_path.dentry->d_inode->i_private); +} + +static const struct file_operations debugfs_pci_debug_fops = { + .open = pci_debug_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void zpci_debug_init_device(struct zpci_dev *zdev) +{ + zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev), + debugfs_root); + if (IS_ERR(zdev->debugfs_dev)) + zdev->debugfs_dev = NULL; + + zdev->debugfs_perf = debugfs_create_file("statistics", + S_IFREG | S_IRUGO | S_IWUSR, + zdev->debugfs_dev, zdev, + &debugfs_pci_perf_fops); + if (IS_ERR(zdev->debugfs_perf)) + zdev->debugfs_perf = NULL; + + zdev->debugfs_debug = debugfs_create_file("debug", + S_IFREG | S_IRUGO | S_IWUSR, + zdev->debugfs_dev, zdev, + &debugfs_pci_debug_fops); + if (IS_ERR(zdev->debugfs_debug)) + zdev->debugfs_debug = NULL; +} + +void zpci_debug_exit_device(struct zpci_dev *zdev) +{ + debugfs_remove(zdev->debugfs_perf); + debugfs_remove(zdev->debugfs_debug); + debugfs_remove(zdev->debugfs_dev); +} + +int __init zpci_debug_init(void) +{ + /* event trace buffer */ + pci_debug_msg_id = debug_register("pci_msg", 16, 1, 16 * sizeof(long)); + if (!pci_debug_msg_id) + return -EINVAL; + debug_register_view(pci_debug_msg_id, &debug_sprintf_view); + debug_set_level(pci_debug_msg_id, 3); + zpci_dbg("Debug view initialized\n"); + + /* error log */ + pci_debug_err_id = debug_register("pci_error", 2, 1, 16); + if (!pci_debug_err_id) + return -EINVAL; + debug_register_view(pci_debug_err_id, &debug_hex_ascii_view); + debug_set_level(pci_debug_err_id, 6); + zpci_err("Debug view initialized\n"); + + debugfs_root = debugfs_create_dir("pci", NULL); + return 0; +} + +void zpci_debug_exit(void) +{ + if (pci_debug_msg_id) + debug_unregister(pci_debug_msg_id); + if (pci_debug_err_id) + debug_unregister(pci_debug_err_id); + + debugfs_remove(debugfs_root); +} diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index c64b4b2..6138468 100644 --- a/arch/s390/pci/pci_dma.c +++ b/arch/s390/pci/pci_dma.c @@ -291,8 +291,10 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page, if (direction == DMA_NONE || direction == DMA_TO_DEVICE) flags |= ZPCI_TABLE_PROTECTED; - if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) + if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) { + atomic64_add(nr_pages, (atomic64_t *) &zdev->fmb->mapped_pages); return dma_addr + offset; + } out_free: dma_free_iommu(zdev, iommu_page_index, nr_pages); @@ -315,6 +317,7 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr, ZPCI_TABLE_PROTECTED | ZPCI_PTE_INVALID)) dev_err(dev, "Failed to unmap addr: %Lx\n", dma_addr); + atomic64_add(npages, (atomic64_t *) &zdev->fmb->unmapped_pages); iommu_page_index = (dma_addr - zdev->start_dma) >> PAGE_SHIFT; dma_free_iommu(zdev, iommu_page_index, npages); } @@ -323,6 +326,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag, struct dma_attrs *attrs) { + struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev)); struct page *page; unsigned long pa; dma_addr_t map; @@ -331,6 +335,8 @@ static void *s390_dma_alloc(struct device *dev, size_t size, page = alloc_pages(flag, get_order(size)); if (!page) return NULL; + + atomic64_add(size / PAGE_SIZE, (atomic64_t *) &zdev->fmb->allocated_pages); pa = page_to_phys(page); memset((void *) pa, 0, size); diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index dbed8cd..ec62e3a 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c @@ -45,6 +45,8 @@ static void zpci_event_log_err(struct zpci_ccdf_err *ccdf) { struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); + zpci_err("SEI error CCD:\n"); + zpci_err_hex(ccdf, sizeof(*ccdf)); dev_err(&zdev->pdev->dev, "event code: 0x%x\n", ccdf->pec); } -- cgit v0.10.2 From 6169b673618bf0b2518ce413b54925782a603f06 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 14 Dec 2012 10:22:35 +0100 Subject: ALSA: hda - Always turn on pins for HDMI/DP We've seen the broken HDMI *video* output on some machines with GM965, and the debugging session pointed that the culprit is the disabled audio output pins. Toggling these pins dynamically on demand caused flickering of HDMI TV. This patch changes the behavior to keep the pin ON constantly. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=51421 Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 0fcfa6f..37dd06d 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -431,9 +431,11 @@ static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid) if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* Disable pin out until stream is active*/ + /* Enable pin out: some machines with GM965 gets broken output when + * the pin is disabled or changed while using with HDMI + */ snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); } static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid) @@ -1341,7 +1343,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hdmi_spec *spec = codec->spec; int pin_idx = hinfo_to_pin_index(spec, hinfo); hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid; - int pinctl; bool non_pcm; non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); @@ -1350,11 +1351,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream); - pinctl = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl | PIN_OUT); - return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); } @@ -1374,7 +1370,6 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, int cvt_idx, pin_idx; struct hdmi_spec_per_cvt *per_cvt; struct hdmi_spec_per_pin *per_pin; - int pinctl; if (hinfo->nid) { cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); @@ -1391,11 +1386,6 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, return -EINVAL; per_pin = &spec->pins[pin_idx]; - pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinctl & ~PIN_OUT); snd_hda_spdif_ctls_unassign(codec, pin_idx); per_pin->chmap_set = false; memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); -- cgit v0.10.2 From 861d66601acda6d7a2038fb3c95f68009128003a Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Fri, 30 Nov 2012 16:03:31 +0200 Subject: exofs: don't leak io_state and pages on read error Same bug as fixed by Idan for write_exec was in read_exec. Fix the io_state leak and pages state on read error. Also while at it: The if (!pcol->read_4_write) at the error path is redundant because all goto err; are after the if (pcol->read_4_write) bale out. Signed-off-by: Boaz Harrosh diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 1634b94..d1f80ab 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -361,12 +361,12 @@ static int read_exec(struct page_collect *pcol) return 0; err: - if (!pcol->read_4_write) - _unlock_pcol_pages(pcol, ret, READ); - - pcol_free(pcol); - + if (!pcol_copy) /* Failed before ownership transfer */ + pcol_copy = pcol; + _unlock_pcol_pages(pcol_copy, ret, READ); + pcol_free(pcol_copy); kfree(pcol_copy); + return ret; } -- cgit v0.10.2 From c6ba8d06ecfc1dadcf7f1b54960cf9332ba5ae8d Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Fri, 14 Dec 2012 08:47:59 +0200 Subject: scripts/config: Fix wrong "shift" for --keep-case Remove wrong "shift" for --keep-case. There is always "shift" at beginning of while-loop. No need "shift" at --keep-case just before "continue" to process next argument. Now the following works as expected: ./scripts/config -e aAa -k -e bBb -e cCc && tail -3 .config CONFIG_AAA=y CONFIG_bBb=y CONFIG_cCc=y Signed-off-by: Hiroshi Doyu Signed-off-by: Michal Marek diff --git a/scripts/config b/scripts/config index ee35539..bb4d3de 100755 --- a/scripts/config +++ b/scripts/config @@ -101,7 +101,6 @@ while [ "$1" != "" ] ; do case "$CMD" in --keep-case|-k) MUNGE_CASE=no - shift continue ;; --refresh) -- cgit v0.10.2 From 34cceb7464f2db0da4da900afa82a210f4470b89 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 27 Nov 2012 11:22:39 -0600 Subject: ARM: OMAP2+: Fix realtime_counter_init warning in timer.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit fa6d79d (ARM: OMAP: Add initialisation for the real-time counter), the function realtime_counter_init() was added. However, if the kernel configuration option CONFIG_SOC_OMAP5 is not selected then the following compiler warning is observed. CC arch/arm/mach-omap2/timer.o arch/arm/mach-omap2/timer.c:489:20: warning: ‘realtime_counter_init’ defined but not used [-Wunused-function] Commit fa6d79d also introduced the kernel configuration option CONFIG_SOC_HAS_REALTIME_COUNTER. If this option is not selected then the a stub function for realtime_counter_init() is defined. For non-OMAP5 devices, there is no realtime counter and so realtime_counter_init() function and stub function are not used for these devices. Therefore, fix this warning by only allowing the kernel configuration option CONFIG_SOC_HAS_REALTIME_COUNTER to be enabled for OMAP5 devices. Cc: Santosh Shilimkar Reported-by: Tony Lindgren Signed-off-by: Jon Hunter Acked-by Santosh Shilimkar diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index be0f62b..41b581f 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -26,6 +26,8 @@ config SOC_HAS_OMAP2_SDRC config SOC_HAS_REALTIME_COUNTER bool "Real time free running counter" + depends on SOC_OMAP5 + default y config ARCH_OMAP2 bool "TI OMAP2" @@ -79,7 +81,6 @@ config SOC_OMAP5 select ARM_GIC select CPU_V7 select HAVE_SMP - select SOC_HAS_REALTIME_COUNTER select COMMON_CLK comment "OMAP Core Type" -- cgit v0.10.2 From e0c3e27ce19fcc81156ba49c91d83a676144a103 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 27 Nov 2012 15:24:12 -0600 Subject: ARM: AM335x: Fix warning in timer.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling the kernel with configuration options ... # CONFIG_ARCH_OMAP2 is not set # CONFIG_ARCH_OMAP3 is not set # CONFIG_ARCH_OMAP4 is not set # CONFIG_SOC_OMAP5 is not set CONFIG_SOC_AM33XX=y ... the following build warning is seen. CC arch/arm/mach-omap2/timer.o arch/arm/mach-omap2/timer.c:395:19: warning: ‘omap2_sync32k_clocksource_init’ defined but not used [-Wunused-function] This issue was introduced by commit 6f80b3b (ARM: OMAP2+: timer: remove CONFIG_OMAP_32K_TIMER) where the omap2_sync32k_clocksource_init() is no longer referenced by the timer initialisation function for the AM335x device as it has no 32k-sync timer. Fix this by adding the "__maybe_unused" compiler directive to the omap2_sync32k_clocksource_init() function to indicate that this function may be used for certain configurations. Cc: Igor Grinberg Signed-off-by: Jon Hunter diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 7016637..e2ffe0ad 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -392,7 +392,7 @@ static struct of_device_id omap_counter_match[] __initdata = { }; /* Setup free-running counter for clocksource */ -static int __init omap2_sync32k_clocksource_init(void) +static int __init __maybe_unused omap2_sync32k_clocksource_init(void) { int ret; struct device_node *np = NULL; -- cgit v0.10.2 From bf85f205d95eb223e849914101e0db1a5a576a3c Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Wed, 28 Nov 2012 15:56:41 -0600 Subject: ARM: OMAP2+: Fix sparse warnings in timer.c Sparse generates the following warnings when compiling mach-omap2/timer.c. CHECK arch/arm/mach-omap2/timer.c arch/arm/mach-omap2/timer.c:193:13: warning: symbol 'omap_dmtimer_init' was not declared. Should it be static? arch/arm/mach-omap2/timer.c:213:12: warning: symbol 'omap_dm_timer_get_errata' was not declared. Should it be static? Add static to function declaration to fix warnings. Signed-off-by: Vaibhav Hiremath Signed-off-by: Jon Hunter diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index e2ffe0ad..06e1415 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -190,7 +190,7 @@ static struct device_node * __init omap_get_timer_dt(struct of_device_id *match, * kernel registering these devices remove them dynamically from the device * tree on boot. */ -void __init omap_dmtimer_init(void) +static void __init omap_dmtimer_init(void) { struct device_node *np; @@ -210,7 +210,7 @@ void __init omap_dmtimer_init(void) * * Get the timer errata flags that are specific to the OMAP device being used. */ -u32 __init omap_dm_timer_get_errata(void) +static u32 __init omap_dm_timer_get_errata(void) { if (cpu_is_omap24xx()) return 0; -- cgit v0.10.2 From 395e095ed92b1ccfe74c90fee4cc637cff468ea7 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Thu, 13 Dec 2012 11:34:45 -0500 Subject: arch/tile: clean up tile-specific PTRACE_SETOPTIONS Use the newer idioms for setting PTRACE_O_xxx and PT_TRACE_xxx flags. Only set/clear tile-specific flags if the generic routine returns success, since otherwise we want to avoid setting any flags at all. Atomically update the ptrace flags with the new values. Eliminate the PT_TRACE_MASK_TILE bitmask and just shift PTRACE_O_MASK_TILE. Add a BUILD_BUG_ON to avoid overlapping with generic bits. Acked-by: Oleg Nesterov Signed-off-by: Chris Metcalf diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h index 1a4fd9a..5ce052e 100644 --- a/arch/tile/include/asm/ptrace.h +++ b/arch/tile/include/asm/ptrace.h @@ -24,8 +24,7 @@ typedef unsigned long pt_reg_t; #include #define PTRACE_O_MASK_TILE (PTRACE_O_TRACEMIGRATE) -#define PT_TRACE_MIGRATE 0x00080000 -#define PT_TRACE_MASK_TILE (PT_TRACE_MIGRATE) +#define PT_TRACE_MIGRATE PT_EVENT_FLAG(PTRACE_EVENT_MIGRATE) /* Flag bits in pt_regs.flags */ #define PT_FLAGS_DISABLE_IRQ 1 /* on return to kernel, disable irqs */ diff --git a/arch/tile/include/uapi/asm/ptrace.h b/arch/tile/include/uapi/asm/ptrace.h index 0d22088..7757e19 100644 --- a/arch/tile/include/uapi/asm/ptrace.h +++ b/arch/tile/include/uapi/asm/ptrace.h @@ -81,8 +81,8 @@ struct pt_regs { #define PTRACE_SETFPREGS 15 /* Support TILE-specific ptrace options, with events starting at 16. */ -#define PTRACE_O_TRACEMIGRATE 0x00010000 #define PTRACE_EVENT_MIGRATE 16 +#define PTRACE_O_TRACEMIGRATE (1 << PTRACE_EVENT_MIGRATE) /* * Flag bits in pt_regs.flags that are part of the ptrace API. diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c index 64ba102..b32bc3f 100644 --- a/arch/tile/kernel/ptrace.c +++ b/arch/tile/kernel/ptrace.c @@ -151,12 +151,16 @@ long arch_ptrace(struct task_struct *child, long request, case PTRACE_SETOPTIONS: /* Support TILE-specific ptrace options. */ - child->ptrace &= ~PT_TRACE_MASK_TILE; + BUILD_BUG_ON(PTRACE_O_MASK_TILE & PTRACE_O_MASK); tmp = data & PTRACE_O_MASK_TILE; data &= ~PTRACE_O_MASK_TILE; ret = ptrace_request(child, request, addr, data); - if (tmp & PTRACE_O_TRACEMIGRATE) - child->ptrace |= PT_TRACE_MIGRATE; + if (ret == 0) { + unsigned int flags = child->ptrace; + flags &= ~(PTRACE_O_MASK_TILE << PT_OPT_FLAG_SHIFT); + flags |= (tmp << PT_OPT_FLAG_SHIFT); + child->ptrace = flags; + } break; default: -- cgit v0.10.2 From 8fa45a70badf6ce2c57421c17e86e8967ce0d478 Mon Sep 17 00:00:00 2001 From: Ang Way Chuang Date: Thu, 13 Dec 2012 23:08:39 +0000 Subject: bridge: remove temporary variable for MLDv2 maximum response code computation As suggested by Stephen Hemminger, this remove the temporary variable introduced in commit eca2a43bb0d2c6ebd528be6acb30a88435abe307 ("bridge: fix icmpv6 endian bug and other sparse warnings") Signed-off-by: Ang Way Chuang Acked-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 1093c89..2561af9 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1165,7 +1165,6 @@ static int br_ip6_multicast_query(struct net_bridge *br, if (max_delay) group = &mld->mld_mca; } else if (skb->len >= sizeof(*mld2q)) { - u16 mrc; if (!pskb_may_pull(skb, sizeof(*mld2q))) { err = -EINVAL; goto out; @@ -1173,8 +1172,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, mld2q = (struct mld2_query *)icmp6_hdr(skb); if (!mld2q->mld2q_nsrcs) group = &mld2q->mld2q_mca; - mrc = ntohs(mld2q->mld2q_mrc); - max_delay = mrc ? MLDV2_MRC(mrc) : 1; + max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1; } if (!group) -- cgit v0.10.2 From 4008e97f866db66511f065ae9052e0733a3a8429 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 13 Dec 2012 23:53:30 +0000 Subject: tuntap: fix ambigious multiqueue API The current multiqueue API is ambigious which may confuse both user and LSM to do things correctly: - Both TUNSETIFF and TUNSETQUEUE could be used to create the queues of a tuntap device. - TUNSETQUEUE were used to disable and enable a specific queue of the device. But since the state of tuntap were completely removed from the queue, it could be used to attach to another device (there's no such kind of requirement currently, and it needs new kind of LSM policy. - TUNSETQUEUE could be used to attach to a persistent device without any queues. This kind of attching bypass the necessary checking during TUNSETIFF and may lead unexpected result. So this patch tries to make a cleaner and simpler API by: - Only allow TUNSETIFF to create queues. - TUNSETQUEUE could be only used to disable and enabled the queues of a device, and the state of the tuntap device were not detachd from the queues when it was disabled, so TUNSETQUEUE could be only used after TUNSETIFF and with the same device. This is done by introducing a list which keeps track of all queues which were disabled. The queue would be moved between this list and tfiles[] array when it was enabled/disabled. A pointer of the tun_struct were also introdued to track the device it belongs to when it was disabled. After the change, the isolation between management and application could be done through: TUNSETIFF were only called by management software and TUNSETQUEUE were only called by application.For LSM/SELinux, the things left is to do proper check during tun_set_queue() if needed. Signed-off-by: Jason Wang Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 40b426e..255a9f5 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -138,6 +138,8 @@ struct tun_file { /* only used for fasnyc */ unsigned int flags; u16 queue_index; + struct list_head next; + struct tun_struct *detached; }; struct tun_flow_entry { @@ -182,6 +184,8 @@ struct tun_struct { struct hlist_head flows[TUN_NUM_FLOW_ENTRIES]; struct timer_list flow_gc_timer; unsigned long ageing_time; + unsigned int numdisabled; + struct list_head disabled; }; static inline u32 tun_hashfn(u32 rxhash) @@ -385,6 +389,23 @@ static void tun_set_real_num_queues(struct tun_struct *tun) netif_set_real_num_rx_queues(tun->dev, tun->numqueues); } +static void tun_disable_queue(struct tun_struct *tun, struct tun_file *tfile) +{ + tfile->detached = tun; + list_add_tail(&tfile->next, &tun->disabled); + ++tun->numdisabled; +} + +struct tun_struct *tun_enable_queue(struct tun_file *tfile) +{ + struct tun_struct *tun = tfile->detached; + + tfile->detached = NULL; + list_del_init(&tfile->next); + --tun->numdisabled; + return tun; +} + static void __tun_detach(struct tun_file *tfile, bool clean) { struct tun_file *ntfile; @@ -406,20 +427,25 @@ static void __tun_detach(struct tun_file *tfile, bool clean) ntfile->queue_index = index; --tun->numqueues; - sock_put(&tfile->sk); + if (clean) + sock_put(&tfile->sk); + else + tun_disable_queue(tun, tfile); synchronize_net(); tun_flow_delete_by_queue(tun, tun->numqueues + 1); /* Drop read queue */ skb_queue_purge(&tfile->sk.sk_receive_queue); tun_set_real_num_queues(tun); - - if (tun->numqueues == 0 && !(tun->flags & TUN_PERSIST)) - if (dev->reg_state == NETREG_REGISTERED) - unregister_netdevice(dev); - } + } else if (tfile->detached && clean) + tun = tun_enable_queue(tfile); if (clean) { + if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && + !(tun->flags & TUN_PERSIST)) + if (tun->dev->reg_state == NETREG_REGISTERED) + unregister_netdevice(tun->dev); + BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags)); sk_release_kernel(&tfile->sk); @@ -436,7 +462,7 @@ static void tun_detach(struct tun_file *tfile, bool clean) static void tun_detach_all(struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); - struct tun_file *tfile; + struct tun_file *tfile, *tmp; int i, n = tun->numqueues; for (i = 0; i < n; i++) { @@ -457,6 +483,12 @@ static void tun_detach_all(struct net_device *dev) skb_queue_purge(&tfile->sk.sk_receive_queue); sock_put(&tfile->sk); } + list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) { + tun_enable_queue(tfile); + skb_queue_purge(&tfile->sk.sk_receive_queue); + sock_put(&tfile->sk); + } + BUG_ON(tun->numdisabled != 0); } static int tun_attach(struct tun_struct *tun, struct file *file) @@ -473,7 +505,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file) goto out; err = -E2BIG; - if (tun->numqueues == MAX_TAP_QUEUES) + if (!tfile->detached && + tun->numqueues + tun->numdisabled == MAX_TAP_QUEUES) goto out; err = 0; @@ -487,9 +520,13 @@ static int tun_attach(struct tun_struct *tun, struct file *file) tfile->queue_index = tun->numqueues; rcu_assign_pointer(tfile->tun, tun); rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile); - sock_hold(&tfile->sk); tun->numqueues++; + if (tfile->detached) + tun_enable_queue(tfile); + else + sock_hold(&tfile->sk); + tun_set_real_num_queues(tun); /* device is allowed to go away first, so no need to hold extra @@ -1349,6 +1386,7 @@ static void tun_free_netdev(struct net_device *dev) { struct tun_struct *tun = netdev_priv(dev); + BUG_ON(!(list_empty(&tun->disabled))); tun_flow_uninit(tun); free_netdev(dev); } @@ -1543,6 +1581,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) err = tun_attach(tun, file); if (err < 0) return err; + + if (tun->flags & TUN_TAP_MQ && + (tun->numqueues + tun->numdisabled > 1)) + return err; } else { char *name; @@ -1601,6 +1643,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) TUN_USER_FEATURES; dev->features = dev->hw_features; + INIT_LIST_HEAD(&tun->disabled); err = tun_attach(tun, file); if (err < 0) goto err_free_dev; @@ -1755,32 +1798,28 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr) { struct tun_file *tfile = file->private_data; struct tun_struct *tun; - struct net_device *dev; int ret = 0; rtnl_lock(); if (ifr->ifr_flags & IFF_ATTACH_QUEUE) { - dev = __dev_get_by_name(tfile->net, ifr->ifr_name); - if (!dev) { - ret = -EINVAL; - goto unlock; - } - - tun = netdev_priv(dev); - if (dev->netdev_ops != &tap_netdev_ops && - dev->netdev_ops != &tun_netdev_ops) + tun = tfile->detached; + if (!tun) ret = -EINVAL; else if (tun_not_capable(tun)) ret = -EPERM; else ret = tun_attach(tun, file); - } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) - __tun_detach(tfile, false); - else + } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { + tun = rcu_dereference_protected(tfile->tun, + lockdep_rtnl_is_held()); + if (!tun || !(tun->flags & TUN_TAP_MQ)) + ret = -EINVAL; + else + __tun_detach(tfile, false); + } else ret = -EINVAL; -unlock: rtnl_unlock(); return ret; } @@ -2092,6 +2131,7 @@ static int tun_chr_open(struct inode *inode, struct file * file) file->private_data = tfile; set_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags); + INIT_LIST_HEAD(&tfile->next); return 0; } -- cgit v0.10.2 From 4a0ae7b0a9e55db9b85f8abda623f145311eb951 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Fri, 14 Dec 2012 01:02:36 +0000 Subject: mISDN: fix race in timer canceling on module unloading Using timer_pending() without additional syncronization is racy, del_timer_sync() must be used here for waiting in-flight handler. Bug caught with help from "debug-objects" during random insmod/rmmod. Signed-off-by: Konstantin Khlebnikov Cc: Karsten Keil Cc: David S. Miller Cc: netdev Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 28c99c6..22b720e 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -1217,8 +1217,7 @@ static void __exit dsp_cleanup(void) { mISDN_unregister_Bprotocol(&DSP); - if (timer_pending(&dsp_spl_tl)) - del_timer(&dsp_spl_tl); + del_timer_sync(&dsp_spl_tl); if (!list_empty(&dsp_ilist)) { printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not " -- cgit v0.10.2 From 493682b8b8a9bf130a544d983c63f1b35df688b9 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Fri, 14 Dec 2012 01:02:51 +0000 Subject: stmmac: fix platform driver unregistering This patch fixes platform device drivers unregistering and adds proper error handing on module loading. Signed-off-by: Konstantin Khlebnikov Cc: Giuseppe Cavallaro Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 023a4fb..b05df89 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -127,14 +127,14 @@ static inline int stmmac_register_platform(void) } static inline void stmmac_unregister_platform(void) { - platform_driver_register(&stmmac_pltfr_driver); + platform_driver_unregister(&stmmac_pltfr_driver); } #else static inline int stmmac_register_platform(void) { pr_debug("stmmac: do not register the platf driver\n"); - return -EINVAL; + return 0; } static inline void stmmac_unregister_platform(void) { @@ -162,7 +162,7 @@ static inline int stmmac_register_pci(void) { pr_debug("stmmac: do not register the PCI driver\n"); - return -EINVAL; + return 0; } static inline void stmmac_unregister_pci(void) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 542edbc..f07c061 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2194,18 +2194,20 @@ int stmmac_restore(struct net_device *ndev) */ static int __init stmmac_init(void) { - int err_plt = 0; - int err_pci = 0; - - err_plt = stmmac_register_platform(); - err_pci = stmmac_register_pci(); - - if ((err_pci) && (err_plt)) { - pr_err("stmmac: driver registration failed\n"); - return -EINVAL; - } + int ret; + ret = stmmac_register_platform(); + if (ret) + goto err; + ret = stmmac_register_pci(); + if (ret) + goto err_pci; return 0; +err_pci: + stmmac_unregister_platform(); +err: + pr_err("stmmac: driver registration failed\n"); + return ret; } static void __exit stmmac_exit(void) -- cgit v0.10.2 From cfb6f99dd9629ec7759b78cff51d9bf7eedf105a Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Fri, 14 Dec 2012 01:02:55 +0000 Subject: bonding: do not cancel works in bond_uninit() Bonding initializes these works in bond_open() and cancels in bond_close(), thus in bond_uninit() they are already canceled but may be unitialized yet. Signed-off-by: Konstantin Khlebnikov Cc: Nikolay Aleksandrov Cc: Jay Vosburgh Cc: Andy Gospodarek Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ef2cb24..b7d45f3 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4431,8 +4431,6 @@ static void bond_uninit(struct net_device *bond_dev) list_del(&bond->bond_list); - bond_work_cancel_all(bond); - bond_debug_unregister(bond); __hw_addr_flush(&bond->mc_list); -- cgit v0.10.2 From 1e9f954516ee03251e0ac2e98cad2e4be6ce9958 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Fri, 14 Dec 2012 01:03:03 +0000 Subject: mac802154: fix destructon ordering for ieee802154 devices mutex_destroy() must be called before wpan_phy_free(), because it puts the last reference and frees memory. Catched as overwritten poison in kmalloc-2048. Signed-off-by: Konstantin Khlebnikov Cc: Alexander Smirnov Cc: Dmitry Eremin-Solenikov Cc: David S. Miller Cc: linux-zigbee-devel@lists.sourceforge.net Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c index e748aed..b7c7f81 100644 --- a/net/mac802154/ieee802154_dev.c +++ b/net/mac802154/ieee802154_dev.c @@ -224,9 +224,9 @@ void ieee802154_free_device(struct ieee802154_dev *hw) BUG_ON(!list_empty(&priv->slaves)); - wpan_phy_free(priv->phy); - mutex_destroy(&priv->slaves_mtx); + + wpan_phy_free(priv->phy); } EXPORT_SYMBOL(ieee802154_free_device); -- cgit v0.10.2 From 093d04d42fa094f6740bb188f0ad0c215ff61e2c Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Fri, 14 Dec 2012 02:59:59 +0000 Subject: ipv6: Change skb->data before using icmpv6_notify() to propagate redirect In function ndisc_redirect_rcv(), the skb->data points to the transport header, but function icmpv6_notify() need the skb->data points to the inner IP packet. So before using icmpv6_notify() to propagate redirect, change skb->data to point the inner IP packet that triggered the sending of the Redirect, and introduce struct rd_msg to make it easy. Signed-off-by: Duan Jiong Signed-off-by: David S. Miller diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 7af1ea8..23b3a7c 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -78,6 +78,13 @@ struct ra_msg { __be32 retrans_timer; }; +struct rd_msg { + struct icmp6hdr icmph; + struct in6_addr target; + struct in6_addr dest; + __u8 opt[0]; +}; + struct nd_opt_hdr { __u8 nd_opt_type; __u8 nd_opt_len; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f2a007b..6574175 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1314,6 +1314,12 @@ out: static void ndisc_redirect_rcv(struct sk_buff *skb) { + u8 *hdr; + struct ndisc_options ndopts; + struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb); + u32 ndoptlen = skb->tail - (skb->transport_header + + offsetof(struct rd_msg, opt)); + #ifdef CONFIG_IPV6_NDISC_NODETYPE switch (skb->ndisc_nodetype) { case NDISC_NODETYPE_HOST: @@ -1330,6 +1336,17 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) return; } + if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) + return; + + if (!ndopts.nd_opts_rh) + return; + + hdr = (u8 *)ndopts.nd_opts_rh; + hdr += 8; + if (!pskb_pull(skb, hdr - skb_transport_header(skb))) + return; + icmpv6_notify(skb, NDISC_REDIRECT, 0, 0); } -- cgit v0.10.2 From e337e24d6624e74a558aa69071e112a65f7b5758 Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Fri, 14 Dec 2012 04:07:58 +0000 Subject: inet: Fix kmemleak in tcp_v4/6_syn_recv_sock and dccp_v4/6_request_recv_sock If in either of the above functions inet_csk_route_child_sock() or __inet_inherit_port() fails, the newsk will not be freed: unreferenced object 0xffff88022e8a92c0 (size 1592): comm "softirq", pid 0, jiffies 4294946244 (age 726.160s) hex dump (first 32 bytes): 0a 01 01 01 0a 01 01 02 00 00 00 00 a7 cc 16 00 ................ 02 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] kmemleak_alloc+0x21/0x3e [] kmem_cache_alloc+0xb5/0xc5 [] sk_prot_alloc.isra.53+0x2b/0xcd [] sk_clone_lock+0x16/0x21e [] inet_csk_clone_lock+0x10/0x7b [] tcp_create_openreq_child+0x21/0x481 [] tcp_v4_syn_recv_sock+0x3a/0x23b [] tcp_check_req+0x29f/0x416 [] tcp_v4_do_rcv+0x161/0x2bc [] tcp_v4_rcv+0x6c9/0x701 [] ip_local_deliver_finish+0x70/0xc4 [] ip_local_deliver+0x4e/0x7f [] ip_rcv_finish+0x1fc/0x233 [] ip_rcv+0x217/0x267 [] __netif_receive_skb+0x49e/0x553 [] netif_receive_skb+0x50/0x82 This happens, because sk_clone_lock initializes sk_refcnt to 2, and thus a single sock_put() is not enough to free the memory. Additionally, things like xfrm, memcg, cookie_values,... may have been initialized. We have to free them properly. This is fixed by forcing a call to tcp_done(), ending up in inet_csk_destroy_sock, doing the final sock_put(). tcp_done() is necessary, because it ends up doing all the cleanup on xfrm, memcg, cookie_values, xfrm,... Before calling tcp_done, we have to set the socket to SOCK_DEAD, to force it entering inet_csk_destroy_sock. To avoid the warning in inet_csk_destroy_sock, inet_num has to be set to 0. As inet_csk_destroy_sock does a dec on orphan_count, we first have to increase it. Calling tcp_done() allows us to remove the calls to tcp_clear_xmit_timer() and tcp_cleanup_congestion_control(). A similar approach is taken for dccp by calling dccp_done(). This is in the kernel since 093d282321 (tproxy: fix hash locking issue when using port redirection in __inet_inherit_port()), thus since version >= 2.6.37. Signed-off-by: Christoph Paasch Signed-off-by: David S. Miller diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index ba1d361..1832927 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -318,6 +318,7 @@ extern void inet_csk_reqsk_queue_prune(struct sock *parent, const unsigned long max_rto); extern void inet_csk_destroy_sock(struct sock *sk); +extern void inet_csk_prepare_forced_close(struct sock *sk); /* * LISTEN is a special case for poll.. diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 176ecdb..4f9f5eb 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -439,8 +439,8 @@ exit: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return NULL; put_and_exit: - bh_unlock_sock(newsk); - sock_put(newsk); + inet_csk_prepare_forced_close(newsk); + dccp_done(newsk); goto exit; } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 56840b2..6e05981 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -585,7 +585,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, newinet->inet_rcv_saddr = LOOPBACK4_IPV6; if (__inet_inherit_port(sk, newsk) < 0) { - sock_put(newsk); + inet_csk_prepare_forced_close(newsk); + dccp_done(newsk); goto out; } __inet6_hash(newsk, NULL); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 2026542..d0670f0 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -710,6 +710,22 @@ void inet_csk_destroy_sock(struct sock *sk) } EXPORT_SYMBOL(inet_csk_destroy_sock); +/* This function allows to force a closure of a socket after the call to + * tcp/dccp_create_openreq_child(). + */ +void inet_csk_prepare_forced_close(struct sock *sk) +{ + /* sk_clone_lock locked the socket and set refcnt to 2 */ + bh_unlock_sock(sk); + sock_put(sk); + + /* The below has to be done to allow calling inet_csk_destroy_sock */ + sock_set_flag(sk, SOCK_DEAD); + percpu_counter_inc(sk->sk_prot->orphan_count); + inet_sk(sk)->inet_num = 0; +} +EXPORT_SYMBOL(inet_csk_prepare_forced_close); + int inet_csk_listen_start(struct sock *sk, const int nr_table_entries) { struct inet_sock *inet = inet_sk(sk); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1ed2307..54139fa 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1767,10 +1767,8 @@ exit: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return NULL; put_and_exit: - tcp_clear_xmit_timers(newsk); - tcp_cleanup_congestion_control(newsk); - bh_unlock_sock(newsk); - sock_put(newsk); + inet_csk_prepare_forced_close(newsk); + tcp_done(newsk); goto exit; } EXPORT_SYMBOL(tcp_v4_syn_recv_sock); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 6565cf5..93825dd 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1288,7 +1288,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, #endif if (__inet_inherit_port(sk, newsk) < 0) { - sock_put(newsk); + inet_csk_prepare_forced_close(newsk); + tcp_done(newsk); goto out; } __inet6_hash(newsk, NULL); -- cgit v0.10.2 From e133b539ae97a44daaa42d96a4607617788c5351 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 13 Dec 2012 11:36:41 +0000 Subject: cpts: Fix build error caused by include of plat/clock.h Commit 87c0e764 (cpts: introduce time stamping code and a PTP hardware clock) mistakenly included plat/clock.h that should not be included by drivers even if it exists. Otherwise we get the following error with at least omap2plus_defconfig: drivers/net/ethernet/ti/cpts.c:30:24: error: plat/clock.h: No such file or directory Signed-off-by: Tony Lindgren diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c index 3377667..5e62c1a 100644 --- a/drivers/net/ethernet/ti/cpts.c +++ b/drivers/net/ethernet/ti/cpts.c @@ -27,8 +27,6 @@ #include #include -#include - #include "cpts.h" #ifdef CONFIG_TI_CPTS -- cgit v0.10.2 From ca2e16faa7378878c1522a7c1b6c38211de3331d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 22 Nov 2012 10:39:56 +0200 Subject: OMAP: board-files: fix i2c_bus for tfp410 The i2c handling in tfp410 driver, which handles converting parallel RGB to DVI, was changed in 958f2717b84e88bf833d996997fda8f73276f2af (OMAPDSS: TFP410: pdata rewrite). The patch changed what value the driver considers as invalid/undefined. Before the patch, 0 was the invalid value, but as 0 is a valid bus number, the patch changed this to -1. However, the fact was missed that many board files do not define the bus number at all, thus it's left to 0. This causes the driver to fail to get the i2c bus, exiting from the driver's probe with an error, meaning that the DVI output does not work for those boards. This patch fixes the issue by changing the i2c_bus number field in the driver's platform data from u16 to int, and setting the bus number to -1 in the board files for the boards that did not define the bus. The exception is devkit8000, for which the bus is set to 1, which is the correct bus for that board. The bug exists in v3.5+ kernels. Signed-off-by: Tomi Valkeinen Reported-by: Thomas Weber Cc: Thomas Weber Cc: # v3.5+ Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index 7b20154..bb73afc 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -157,6 +157,7 @@ static struct omap_dss_device sdp3430_lcd_device = { static struct tfp410_platform_data dvi_panel = { .power_down_gpio = -1, + .i2c_bus_num = -1, }; static struct omap_dss_device sdp3430_dvi_device = { diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index 4be58fd..f81a303 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -208,6 +208,7 @@ static struct omap_dss_device am3517_evm_tv_device = { static struct tfp410_platform_data dvi_panel = { .power_down_gpio = -1, + .i2c_bus_num = -1, }; static struct omap_dss_device am3517_evm_dvi_device = { diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index c8e37dc..b3102c2 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -241,6 +241,7 @@ static struct omap_dss_device cm_t35_lcd_device = { static struct tfp410_platform_data dvi_panel = { .power_down_gpio = CM_T35_DVI_EN_GPIO, + .i2c_bus_num = -1, }; static struct omap_dss_device cm_t35_dvi_device = { diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c index 7667eb7..12865af 100644 --- a/arch/arm/mach-omap2/board-devkit8000.c +++ b/arch/arm/mach-omap2/board-devkit8000.c @@ -141,6 +141,7 @@ static struct omap_dss_device devkit8000_lcd_device = { static struct tfp410_platform_data dvi_panel = { .power_down_gpio = -1, + .i2c_bus_num = 1, }; static struct omap_dss_device devkit8000_dvi_device = { diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 54647d6..3985f35 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -240,6 +240,7 @@ static struct omap_dss_device omap3_evm_tv_device = { static struct tfp410_platform_data dvi_panel = { .power_down_gpio = OMAP3EVM_DVI_PANEL_EN_GPIO, + .i2c_bus_num = -1, }; static struct omap_dss_device omap3_evm_dvi_device = { diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c index d8638b3..53a6cbc 100644 --- a/arch/arm/mach-omap2/board-omap3stalker.c +++ b/arch/arm/mach-omap2/board-omap3stalker.c @@ -118,6 +118,7 @@ static struct omap_dss_device omap3_stalker_tv_device = { static struct tfp410_platform_data dvi_panel = { .power_down_gpio = DSS_ENABLE_GPIO, + .i2c_bus_num = -1, }; static struct omap_dss_device omap3_stalker_dvi_device = { diff --git a/include/video/omap-panel-tfp410.h b/include/video/omap-panel-tfp410.h index 68c31d7..aef35e4 100644 --- a/include/video/omap-panel-tfp410.h +++ b/include/video/omap-panel-tfp410.h @@ -28,7 +28,7 @@ struct omap_dss_device; * @power_down_gpio: gpio number for PD pin (or -1 if not available) */ struct tfp410_platform_data { - u16 i2c_bus_num; + int i2c_bus_num; int power_down_gpio; }; -- cgit v0.10.2 From 421e84509980206fb3b3bc039bc05bae1dd41c7b Mon Sep 17 00:00:00 2001 From: Oleg Matcovschi Date: Mon, 26 Nov 2012 17:02:03 -0800 Subject: OMAP2+: mux: Fixed gpio mux mode analysis OMAP_MODE_GPIO() macro verified only OMAP_MUX_MODE4. It is not correct for following platforms: 2430 - gpio mux mode 3 44xx - gpio mux mode 3 54xx - gpio mux mode 6 Patch reserves first 3 bits in partition flags for storing gpio mux mode in same format as stored in control pad register. Modified OMAP_MODE_GPIO() macro to handle all possible cases of gpio mux mode. Modified omap_mux_init() flags of omap34xx to include OMAP_MUX_GPIO_IN_MODE4. Signed-off-by: Oleg Matcovschi Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 2612634..6a217c9 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -135,10 +135,7 @@ static int __init _omap_mux_init_gpio(struct omap_mux_partition *partition, old_mode = omap_mux_read(partition, gpio_mux->reg_offset); mux_mode = val & ~(OMAP_MUX_NR_MODES - 1); - if (partition->flags & OMAP_MUX_GPIO_IN_MODE3) - mux_mode |= OMAP_MUX_MODE3; - else - mux_mode |= OMAP_MUX_MODE4; + mux_mode |= partition->gpio; pr_debug("%s: Setting signal %s.gpio%i 0x%04x -> 0x%04x\n", __func__, gpio_mux->muxnames[0], gpio, old_mode, mux_mode); omap_mux_write(partition, mux_mode, gpio_mux->reg_offset); @@ -800,7 +797,7 @@ int __init omap_mux_late_init(void) struct omap_mux *m = &e->mux; u16 mode = omap_mux_read(partition, m->reg_offset); - if (OMAP_MODE_GPIO(mode)) + if (OMAP_MODE_GPIO(partition, mode)) continue; #ifndef CONFIG_DEBUG_FS @@ -1065,7 +1062,7 @@ static void __init omap_mux_init_list(struct omap_mux_partition *partition, } #else /* Skip pins that are not muxed as GPIO by bootloader */ - if (!OMAP_MODE_GPIO(omap_mux_read(partition, + if (!OMAP_MODE_GPIO(partition, omap_mux_read(partition, superset->reg_offset))) { superset++; continue; @@ -1132,6 +1129,7 @@ int __init omap_mux_init(const char *name, u32 flags, partition->name = name; partition->flags = flags; + partition->gpio = flags & OMAP_MUX_MODE7; partition->size = mux_size; partition->phys = mux_pbase; partition->base = ioremap(mux_pbase, mux_size); diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h index 76f9b3c..fdb22f1 100644 --- a/arch/arm/mach-omap2/mux.h +++ b/arch/arm/mach-omap2/mux.h @@ -58,7 +58,8 @@ #define OMAP_PIN_OFF_INPUT_PULLDOWN (OMAP_OFF_EN | OMAP_OFF_PULL_EN) #define OMAP_PIN_OFF_WAKEUPENABLE OMAP_WAKEUP_EN -#define OMAP_MODE_GPIO(x) (((x) & OMAP_MUX_MODE7) == OMAP_MUX_MODE4) +#define OMAP_MODE_GPIO(partition, x) (((x) & OMAP_MUX_MODE7) == \ + partition->gpio) #define OMAP_MODE_UART(x) (((x) & OMAP_MUX_MODE7) == OMAP_MUX_MODE0) /* Flags for omapX_mux_init */ @@ -79,13 +80,20 @@ /* * omap_mux_init flags definition: * + * OMAP_GPIO_MUX_MODE, bits 0-2: gpio muxing mode, same like pad control + * register which includes values from 0-7. * OMAP_MUX_REG_8BIT: Ensure that access to padconf is done in 8 bits. * The default value is 16 bits. - * OMAP_MUX_GPIO_IN_MODE3: The GPIO is selected in mode3. - * The default is mode4. */ -#define OMAP_MUX_REG_8BIT (1 << 0) -#define OMAP_MUX_GPIO_IN_MODE3 (1 << 1) +#define OMAP_MUX_GPIO_IN_MODE0 OMAP_MUX_MODE0 +#define OMAP_MUX_GPIO_IN_MODE1 OMAP_MUX_MODE1 +#define OMAP_MUX_GPIO_IN_MODE2 OMAP_MUX_MODE2 +#define OMAP_MUX_GPIO_IN_MODE3 OMAP_MUX_MODE3 +#define OMAP_MUX_GPIO_IN_MODE4 OMAP_MUX_MODE4 +#define OMAP_MUX_GPIO_IN_MODE5 OMAP_MUX_MODE5 +#define OMAP_MUX_GPIO_IN_MODE6 OMAP_MUX_MODE6 +#define OMAP_MUX_GPIO_IN_MODE7 OMAP_MUX_MODE7 +#define OMAP_MUX_REG_8BIT (1 << 3) /** * struct omap_board_data - board specific device data @@ -105,6 +113,7 @@ struct omap_board_data { * struct mux_partition - contain partition related information * @name: name of the current partition * @flags: flags specific to this partition + * @gpio: gpio mux mode * @phys: physical address * @size: partition size * @base: virtual address after ioremap @@ -114,6 +123,7 @@ struct omap_board_data { struct omap_mux_partition { const char *name; u32 flags; + u32 gpio; u32 phys; u32 size; void __iomem *base; diff --git a/arch/arm/mach-omap2/mux34xx.c b/arch/arm/mach-omap2/mux34xx.c index c47140b..c53609f4 100644 --- a/arch/arm/mach-omap2/mux34xx.c +++ b/arch/arm/mach-omap2/mux34xx.c @@ -2053,7 +2053,7 @@ int __init omap3_mux_init(struct omap_board_mux *board_subset, int flags) return -EINVAL; } - return omap_mux_init("core", 0, + return omap_mux_init("core", OMAP_MUX_GPIO_IN_MODE4, OMAP3_CONTROL_PADCONF_MUX_PBASE, OMAP3_CONTROL_PADCONF_MUX_SIZE, omap3_muxmodes, package_subset, board_subset, -- cgit v0.10.2 From eed9935745cc44071043ec8c4cde64c820b5c601 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 14 Dec 2012 14:36:36 -0500 Subject: NFS: Ensure that we always drop inodes that have been marked as stale There is no need to cache stale inodes. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 117183b..2faae14 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -107,6 +107,12 @@ u64 nfs_compat_user_ino64(u64 fileid) return ino; } +int nfs_drop_inode(struct inode *inode) +{ + return NFS_STALE(inode) || generic_drop_inode(inode); +} +EXPORT_SYMBOL_GPL(nfs_drop_inode); + void nfs_clear_inode(struct inode *inode) { /* diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 89c1ee4..f0e6c7d 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -296,6 +296,7 @@ extern struct workqueue_struct *nfsiod_workqueue; extern struct inode *nfs_alloc_inode(struct super_block *sb); extern void nfs_destroy_inode(struct inode *); extern int nfs_write_inode(struct inode *, struct writeback_control *); +extern int nfs_drop_inode(struct inode *); extern void nfs_clear_inode(struct inode *); extern void nfs_evict_inode(struct inode *); void nfs_zap_acl_cache(struct inode *inode); diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index bd61221..84d2e9e 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c @@ -51,6 +51,7 @@ static const struct super_operations nfs4_sops = { .alloc_inode = nfs_alloc_inode, .destroy_inode = nfs_destroy_inode, .write_inode = nfs4_write_inode, + .drop_inode = nfs_drop_inode, .put_super = nfs_put_super, .statfs = nfs_statfs, .evict_inode = nfs4_evict_inode, diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e12cea4..aa5315b 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -308,6 +308,7 @@ const struct super_operations nfs_sops = { .alloc_inode = nfs_alloc_inode, .destroy_inode = nfs_destroy_inode, .write_inode = nfs_write_inode, + .drop_inode = nfs_drop_inode, .put_super = nfs_put_super, .statfs = nfs_statfs, .evict_inode = nfs_evict_inode, -- cgit v0.10.2 From 86c35960852b726a1d773ae65302dcfb24267180 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 13 Nov 2012 16:02:19 -0600 Subject: ARM: OMAP2420: Fix ethernet support for OMAP2420 H4 Ethernet is not currently working on the OMAP2420 H4 board. In commit f604931 (ARM: OMAP: abstract debug card setup (smc, leds)) the function h4_init_smc91x() that initialised the ethernet controller was renamed to h4_init_debug() but was never called when initialising the board. Adding a call to h4_init_debug() fixes ethernet support, however, instead of using the legacy H4 code migrate the H4 to use the gpmc_smc91x_init() function instead and remove the legacy H4 code. Signed-off-by: Jon Hunter Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index 9a3878e..3be1311 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -27,14 +27,12 @@ #include #include #include +#include #include #include #include -#include -#include - #include