@@ -252,6 +252,8 @@ static void sdhci_init(struct sdhci_host *host, int soft)
252
252
253
253
sdhci_set_default_irqs (host );
254
254
255
+ host -> cqe_on = false;
256
+
255
257
if (soft ) {
256
258
/* force clock reconfiguration */
257
259
host -> clock = 0 ;
@@ -2672,13 +2674,19 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
2672
2674
}
2673
2675
2674
2676
do {
2677
+ DBG ("IRQ status 0x%08x\n" , intmask );
2678
+
2679
+ if (host -> ops -> irq ) {
2680
+ intmask = host -> ops -> irq (host , intmask );
2681
+ if (!intmask )
2682
+ goto cont ;
2683
+ }
2684
+
2675
2685
/* Clear selected interrupts. */
2676
2686
mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
2677
2687
SDHCI_INT_BUS_POWER );
2678
2688
sdhci_writel (host , mask , SDHCI_INT_STATUS );
2679
2689
2680
- DBG ("IRQ status 0x%08x\n" , intmask );
2681
-
2682
2690
if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE )) {
2683
2691
u32 present = sdhci_readl (host , SDHCI_PRESENT_STATE ) &
2684
2692
SDHCI_CARD_PRESENT ;
@@ -2738,7 +2746,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
2738
2746
unexpected |= intmask ;
2739
2747
sdhci_writel (host , intmask , SDHCI_INT_STATUS );
2740
2748
}
2741
-
2749
+ cont :
2742
2750
if (result == IRQ_NONE )
2743
2751
result = IRQ_HANDLED ;
2744
2752
@@ -2965,6 +2973,119 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
2965
2973
2966
2974
#endif /* CONFIG_PM */
2967
2975
2976
+ /*****************************************************************************\
2977
+ * *
2978
+ * Command Queue Engine (CQE) helpers *
2979
+ * *
2980
+ \*****************************************************************************/
2981
+
2982
+ void sdhci_cqe_enable (struct mmc_host * mmc )
2983
+ {
2984
+ struct sdhci_host * host = mmc_priv (mmc );
2985
+ unsigned long flags ;
2986
+ u8 ctrl ;
2987
+
2988
+ spin_lock_irqsave (& host -> lock , flags );
2989
+
2990
+ ctrl = sdhci_readb (host , SDHCI_HOST_CONTROL );
2991
+ ctrl &= ~SDHCI_CTRL_DMA_MASK ;
2992
+ if (host -> flags & SDHCI_USE_64_BIT_DMA )
2993
+ ctrl |= SDHCI_CTRL_ADMA64 ;
2994
+ else
2995
+ ctrl |= SDHCI_CTRL_ADMA32 ;
2996
+ sdhci_writeb (host , ctrl , SDHCI_HOST_CONTROL );
2997
+
2998
+ sdhci_writew (host , SDHCI_MAKE_BLKSZ (SDHCI_DEFAULT_BOUNDARY_ARG , 512 ),
2999
+ SDHCI_BLOCK_SIZE );
3000
+
3001
+ /* Set maximum timeout */
3002
+ sdhci_writeb (host , 0xE , SDHCI_TIMEOUT_CONTROL );
3003
+
3004
+ host -> ier = host -> cqe_ier ;
3005
+
3006
+ sdhci_writel (host , host -> ier , SDHCI_INT_ENABLE );
3007
+ sdhci_writel (host , host -> ier , SDHCI_SIGNAL_ENABLE );
3008
+
3009
+ host -> cqe_on = true;
3010
+
3011
+ pr_debug ("%s: sdhci: CQE on, IRQ mask %#x, IRQ status %#x\n" ,
3012
+ mmc_hostname (mmc ), host -> ier ,
3013
+ sdhci_readl (host , SDHCI_INT_STATUS ));
3014
+
3015
+ mmiowb ();
3016
+ spin_unlock_irqrestore (& host -> lock , flags );
3017
+ }
3018
+ EXPORT_SYMBOL_GPL (sdhci_cqe_enable );
3019
+
3020
+ void sdhci_cqe_disable (struct mmc_host * mmc , bool recovery )
3021
+ {
3022
+ struct sdhci_host * host = mmc_priv (mmc );
3023
+ unsigned long flags ;
3024
+
3025
+ spin_lock_irqsave (& host -> lock , flags );
3026
+
3027
+ sdhci_set_default_irqs (host );
3028
+
3029
+ host -> cqe_on = false;
3030
+
3031
+ if (recovery ) {
3032
+ sdhci_do_reset (host , SDHCI_RESET_CMD );
3033
+ sdhci_do_reset (host , SDHCI_RESET_DATA );
3034
+ }
3035
+
3036
+ pr_debug ("%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x\n" ,
3037
+ mmc_hostname (mmc ), host -> ier ,
3038
+ sdhci_readl (host , SDHCI_INT_STATUS ));
3039
+
3040
+ mmiowb ();
3041
+ spin_unlock_irqrestore (& host -> lock , flags );
3042
+ }
3043
+ EXPORT_SYMBOL_GPL (sdhci_cqe_disable );
3044
+
3045
+ bool sdhci_cqe_irq (struct sdhci_host * host , u32 intmask , int * cmd_error ,
3046
+ int * data_error )
3047
+ {
3048
+ u32 mask ;
3049
+
3050
+ if (!host -> cqe_on )
3051
+ return false;
3052
+
3053
+ if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC ))
3054
+ * cmd_error = - EILSEQ ;
3055
+ else if (intmask & SDHCI_INT_TIMEOUT )
3056
+ * cmd_error = - ETIMEDOUT ;
3057
+ else
3058
+ * cmd_error = 0 ;
3059
+
3060
+ if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC ))
3061
+ * data_error = - EILSEQ ;
3062
+ else if (intmask & SDHCI_INT_DATA_TIMEOUT )
3063
+ * data_error = - ETIMEDOUT ;
3064
+ else if (intmask & SDHCI_INT_ADMA_ERROR )
3065
+ * data_error = - EIO ;
3066
+ else
3067
+ * data_error = 0 ;
3068
+
3069
+ /* Clear selected interrupts. */
3070
+ mask = intmask & host -> cqe_ier ;
3071
+ sdhci_writel (host , mask , SDHCI_INT_STATUS );
3072
+
3073
+ if (intmask & SDHCI_INT_BUS_POWER )
3074
+ pr_err ("%s: Card is consuming too much power!\n" ,
3075
+ mmc_hostname (host -> mmc ));
3076
+
3077
+ intmask &= ~(host -> cqe_ier | SDHCI_INT_ERROR );
3078
+ if (intmask ) {
3079
+ sdhci_writel (host , intmask , SDHCI_INT_STATUS );
3080
+ pr_err ("%s: CQE: Unexpected interrupt 0x%08x.\n" ,
3081
+ mmc_hostname (host -> mmc ), intmask );
3082
+ sdhci_dumpregs (host );
3083
+ }
3084
+
3085
+ return true;
3086
+ }
3087
+ EXPORT_SYMBOL_GPL (sdhci_cqe_irq );
3088
+
2968
3089
/*****************************************************************************\
2969
3090
* *
2970
3091
* Device allocation/registration *
@@ -2990,6 +3111,9 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
2990
3111
2991
3112
host -> flags = SDHCI_SIGNALING_330 ;
2992
3113
3114
+ host -> cqe_ier = SDHCI_CQE_INT_MASK ;
3115
+ host -> cqe_err_ier = SDHCI_CQE_INT_ERR_MASK ;
3116
+
2993
3117
return host ;
2994
3118
}
2995
3119
0 commit comments