@@ -746,7 +746,7 @@ static void meson_mmc_desc_chain_transfer(struct mmc_host *mmc, u32 cmd_cfg)
746
746
writel (start , host -> regs + SD_EMMC_START );
747
747
}
748
748
749
- /* local sg copy to buffer version with _to/fromio usage for dram_access_quirk */
749
+ /* local sg copy for dram_access_quirk */
750
750
static void meson_mmc_copy_buffer (struct meson_host * host , struct mmc_data * data ,
751
751
size_t buflen , bool to_buffer )
752
752
{
@@ -764,21 +764,27 @@ static void meson_mmc_copy_buffer(struct meson_host *host, struct mmc_data *data
764
764
sg_miter_start (& miter , sgl , nents , sg_flags );
765
765
766
766
while ((offset < buflen ) && sg_miter_next (& miter )) {
767
- unsigned int len ;
767
+ unsigned int buf_offset = 0 ;
768
+ unsigned int len , left ;
769
+ u32 * buf = miter .addr ;
768
770
769
771
len = min (miter .length , buflen - offset );
772
+ left = len ;
770
773
771
- /* When dram_access_quirk, the bounce buffer is a iomem mapping */
772
- if (host -> dram_access_quirk ) {
773
- if (to_buffer )
774
- memcpy_toio (host -> bounce_iomem_buf + offset , miter .addr , len );
775
- else
776
- memcpy_fromio (miter .addr , host -> bounce_iomem_buf + offset , len );
774
+ if (to_buffer ) {
775
+ do {
776
+ writel (* buf ++ , host -> bounce_iomem_buf + offset + buf_offset );
777
+
778
+ buf_offset += 4 ;
779
+ left -= 4 ;
780
+ } while (left );
777
781
} else {
778
- if (to_buffer )
779
- memcpy (host -> bounce_buf + offset , miter .addr , len );
780
- else
781
- memcpy (miter .addr , host -> bounce_buf + offset , len );
782
+ do {
783
+ * buf ++ = readl (host -> bounce_iomem_buf + offset + buf_offset );
784
+
785
+ buf_offset += 4 ;
786
+ left -= 4 ;
787
+ } while (left );
782
788
}
783
789
784
790
offset += len ;
@@ -830,7 +836,11 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
830
836
if (data -> flags & MMC_DATA_WRITE ) {
831
837
cmd_cfg |= CMD_CFG_DATA_WR ;
832
838
WARN_ON (xfer_bytes > host -> bounce_buf_size );
833
- meson_mmc_copy_buffer (host , data , xfer_bytes , true);
839
+ if (host -> dram_access_quirk )
840
+ meson_mmc_copy_buffer (host , data , xfer_bytes , true);
841
+ else
842
+ sg_copy_to_buffer (data -> sg , data -> sg_len ,
843
+ host -> bounce_buf , xfer_bytes );
834
844
dma_wmb ();
835
845
}
836
846
@@ -849,12 +859,43 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
849
859
writel (cmd -> arg , host -> regs + SD_EMMC_CMD_ARG );
850
860
}
851
861
862
+ static int meson_mmc_validate_dram_access (struct mmc_host * mmc , struct mmc_data * data )
863
+ {
864
+ struct scatterlist * sg ;
865
+ int i ;
866
+
867
+ /* Reject request if any element offset or size is not 32bit aligned */
868
+ for_each_sg (data -> sg , sg , data -> sg_len , i ) {
869
+ if (!IS_ALIGNED (sg -> offset , sizeof (u32 )) ||
870
+ !IS_ALIGNED (sg -> length , sizeof (u32 ))) {
871
+ dev_err (mmc_dev (mmc ), "unaligned sg offset %u len %u\n" ,
872
+ data -> sg -> offset , data -> sg -> length );
873
+ return - EINVAL ;
874
+ }
875
+ }
876
+
877
+ return 0 ;
878
+ }
879
+
852
880
static void meson_mmc_request (struct mmc_host * mmc , struct mmc_request * mrq )
853
881
{
854
882
struct meson_host * host = mmc_priv (mmc );
855
883
bool needs_pre_post_req = mrq -> data &&
856
884
!(mrq -> data -> host_cookie & SD_EMMC_PRE_REQ_DONE );
857
885
886
+ /*
887
+ * The memory at the end of the controller used as bounce buffer for
888
+ * the dram_access_quirk only accepts 32bit read/write access,
889
+ * check the aligment and length of the data before starting the request.
890
+ */
891
+ if (host -> dram_access_quirk && mrq -> data ) {
892
+ mrq -> cmd -> error = meson_mmc_validate_dram_access (mmc , mrq -> data );
893
+ if (mrq -> cmd -> error ) {
894
+ mmc_request_done (mmc , mrq );
895
+ return ;
896
+ }
897
+ }
898
+
858
899
if (needs_pre_post_req ) {
859
900
meson_mmc_get_transfer_mode (mmc , mrq );
860
901
if (!meson_mmc_desc_chain_mode (mrq -> data ))
@@ -999,7 +1040,11 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
999
1040
if (meson_mmc_bounce_buf_read (data )) {
1000
1041
xfer_bytes = data -> blksz * data -> blocks ;
1001
1042
WARN_ON (xfer_bytes > host -> bounce_buf_size );
1002
- meson_mmc_copy_buffer (host , data , xfer_bytes , false);
1043
+ if (host -> dram_access_quirk )
1044
+ meson_mmc_copy_buffer (host , data , xfer_bytes , false);
1045
+ else
1046
+ sg_copy_from_buffer (data -> sg , data -> sg_len ,
1047
+ host -> bounce_buf , xfer_bytes );
1003
1048
}
1004
1049
1005
1050
next_cmd = meson_mmc_get_next_command (cmd );
0 commit comments