Loading drivers/video/msm/mdss/mdp3.c +44 −6 Original line number Diff line number Diff line Loading @@ -1834,9 +1834,13 @@ int mdp3_put_img(struct mdp3_img_data *data, int client) return -ENOMEM; } if (data->mapped) { if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) mdss_smmu_unmap_dma_buf(data->tab_clone, dom, dir, data->srcp_dma_buf); else mdss_smmu_unmap_dma_buf(data->srcp_table, dom, dir, data->srcp_dma_buf); dom, dir, data->srcp_dma_buf); data->mapped = false; } if (!data->skip_detach) { Loading @@ -1851,6 +1855,10 @@ int mdp3_put_img(struct mdp3_img_data *data, int client) } else { return -EINVAL; } if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { kfree(data->tab_clone->sgl); kfree(data->tab_clone); } return 0; } Loading Loading @@ -1913,9 +1921,27 @@ int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data, int client) goto err_detach; } if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { data->tab_clone = mdss_smmu_sg_table_clone(data->srcp_table, GFP_KERNEL, true); if (IS_ERR_OR_NULL(data->tab_clone)) { if (!(data->tab_clone)) ret = -EINVAL; else ret = PTR_ERR(data->tab_clone); goto clone_err; } ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf, data->tab_clone, dom, &data->addr, &data->len, DMA_BIDIRECTIONAL); } else { ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf, data->srcp_table, dom, &data->addr, &data->len, DMA_BIDIRECTIONAL); data->srcp_table, dom, &data->addr, &data->len, DMA_BIDIRECTIONAL); } if (IS_ERR_VALUE(ret)) { pr_err("smmu map dma buf failed: (%d)\n", ret); Loading @@ -1926,6 +1952,10 @@ int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data, int client) data->skip_detach = false; } done: if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { data->addr += data->tab_clone->sgl->length; data->len -= data->tab_clone->sgl->length; } if (!ret && (img->offset < data->len)) { data->addr += img->offset; data->len -= img->offset; Loading @@ -1940,6 +1970,9 @@ done: } return ret; clone_err: dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table, mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL)); err_detach: dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment); err_put: Loading @@ -1950,6 +1983,11 @@ err_unmap: mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL)); dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment); dma_buf_put(data->srcp_dma_buf); if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { kfree(data->tab_clone->sgl); kfree(data->tab_clone); } return ret; } Loading drivers/video/msm/mdss/mdp3.h +2 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2014, 2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2014, 2016-2017, The Linux Foundation. All rights reserved. * Copyright (C) 2007 Google Incorporated * * This program is free software; you can redistribute it and/or modify Loading Loading @@ -233,6 +233,7 @@ struct mdp3_img_data { struct dma_buf *srcp_dma_buf; struct dma_buf_attachment *srcp_attachment; struct sg_table *srcp_table; struct sg_table *tab_clone; }; extern struct mdp3_hw_resource *mdp3_res; Loading drivers/video/msm/mdss/mdss.h +2 −0 Original line number Diff line number Diff line Loading @@ -265,6 +265,8 @@ struct mdss_smmu_ops { void (*smmu_dsi_unmap_buffer)(dma_addr_t dma_addr, int domain, unsigned long size, int dir); void (*smmu_deinit)(struct mdss_data_type *mdata); struct sg_table * (*smmu_sg_table_clone)(struct sg_table *orig_table, gfp_t gfp_mask, bool padding); }; struct mdss_data_type { Loading drivers/video/msm/mdss/mdss_smmu.c +130 −1 Original line number Diff line number Diff line /* Copyright (c) 2007-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2007-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -480,6 +480,134 @@ static void mdss_smmu_deinit_v2(struct mdss_data_type *mdata) } } /* * sg_clone - Duplicate an existing chained sgl * @orig_sgl: Original sg list to be duplicated * @len: Total length of sg while taking chaining into account * @gfp_mask: GFP allocation mask * @padding: specifies if padding is required * * Description: * Clone a chained sgl. This cloned copy may be modified in some ways while * keeping the original sgl in tact. Also allow the cloned copy to have * a smaller length than the original which may reduce the sgl total * sg entries and also allows cloned copy to have one extra sg entry on * either sides of sgl. * * Returns: * Pointer to new kmalloced sg list, ERR_PTR() on error * */ static struct scatterlist *sg_clone(struct scatterlist *orig_sgl, u64 len, gfp_t gfp_mask, bool padding) { int nents; bool last_entry; struct scatterlist *sgl, *head; nents = sg_nents(orig_sgl); if (nents < 0) return ERR_PTR(-EINVAL); if (padding) nents += 2; head = kmalloc_array(nents, sizeof(struct scatterlist), gfp_mask); if (!head) return ERR_PTR(-ENOMEM); sgl = head; sg_init_table(sgl, nents); if (padding) { *sgl = *orig_sgl; if (sg_is_chain(orig_sgl)) { orig_sgl = sg_next(orig_sgl); *sgl = *orig_sgl; } sgl->page_link &= (unsigned long)(~0x03); sgl = sg_next(sgl); } for (; sgl; orig_sgl = sg_next(orig_sgl), sgl = sg_next(sgl)) { last_entry = sg_is_last(sgl); /* * * If page_link is pointing to a chained sgl then set * the sg entry in the cloned list to the next sg entry * in the original sg list as chaining is already taken * care. */ if (sg_is_chain(orig_sgl)) orig_sgl = sg_next(orig_sgl); if (padding) last_entry = sg_is_last(orig_sgl); *sgl = *orig_sgl; sgl->page_link &= (unsigned long)(~0x03); if (last_entry) { if (padding) { len -= sg_dma_len(sgl); sgl = sg_next(sgl); *sgl = *orig_sgl; } sg_dma_len(sgl) = len ? len : SZ_4K; /* Set bit 1 to indicate end of sgl */ sgl->page_link |= 0x02; } else { len -= sg_dma_len(sgl); } } return head; } /* * sg_table_clone - Duplicate an existing sg_table including chained sgl * @orig_table: Original sg_table to be duplicated * @len: Total length of sg while taking chaining into account * @gfp_mask: GFP allocation mask * @padding: specifies if padding is required * * Description: * Clone a sg_table along with chained sgl. This cloned copy may be * modified in some ways while keeping the original table and sgl in tact. * Also allow the cloned sgl copy to have a smaller length than the original * which may reduce the sgl total sg entries. * * Returns: * Pointer to new kmalloced sg_table, ERR_PTR() on error * */ static struct sg_table *sg_table_clone(struct sg_table *orig_table, gfp_t gfp_mask, bool padding) { struct sg_table *table; struct scatterlist *sg = orig_table->sgl; u64 len = 0; for (len = 0; sg; sg = sg_next(sg)) len += sg->length; table = kmalloc(sizeof(struct sg_table), gfp_mask); if (!table) return ERR_PTR(-ENOMEM); table->sgl = sg_clone(orig_table->sgl, len, gfp_mask, padding); if (IS_ERR(table->sgl)) { kfree(table); return ERR_PTR(-ENOMEM); } table->nents = table->orig_nents = sg_nents(table->sgl); return table; } static void mdss_smmu_ops_init(struct mdss_data_type *mdata) { mdata->smmu_ops.smmu_attach = mdss_smmu_attach_v2; Loading @@ -501,6 +629,7 @@ static void mdss_smmu_ops_init(struct mdss_data_type *mdata) mdata->smmu_ops.smmu_dsi_unmap_buffer = mdss_smmu_dsi_unmap_buffer_v2; mdata->smmu_ops.smmu_deinit = mdss_smmu_deinit_v2; mdata->smmu_ops.smmu_sg_table_clone = sg_table_clone; } /* Loading drivers/video/msm/mdss/mdss_smmu.h +13 −1 Original line number Diff line number Diff line /* Copyright (c) 2007-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2007-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -292,4 +292,16 @@ static inline void mdss_smmu_deinit(struct mdss_data_type *mdata) mdata->smmu_ops.smmu_deinit(mdata); } static inline struct sg_table *mdss_smmu_sg_table_clone(struct sg_table *orig_table, gfp_t gfp_mask, bool padding) { struct mdss_data_type *mdata = mdss_mdp_get_mdata(); if (!mdata || !mdata->smmu_ops.smmu_sg_table_clone) return NULL; return mdata->smmu_ops.smmu_sg_table_clone(orig_table, gfp_mask, padding); } #endif /* MDSS_SMMU_H */ Loading
drivers/video/msm/mdss/mdp3.c +44 −6 Original line number Diff line number Diff line Loading @@ -1834,9 +1834,13 @@ int mdp3_put_img(struct mdp3_img_data *data, int client) return -ENOMEM; } if (data->mapped) { if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) mdss_smmu_unmap_dma_buf(data->tab_clone, dom, dir, data->srcp_dma_buf); else mdss_smmu_unmap_dma_buf(data->srcp_table, dom, dir, data->srcp_dma_buf); dom, dir, data->srcp_dma_buf); data->mapped = false; } if (!data->skip_detach) { Loading @@ -1851,6 +1855,10 @@ int mdp3_put_img(struct mdp3_img_data *data, int client) } else { return -EINVAL; } if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { kfree(data->tab_clone->sgl); kfree(data->tab_clone); } return 0; } Loading Loading @@ -1913,9 +1921,27 @@ int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data, int client) goto err_detach; } if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { data->tab_clone = mdss_smmu_sg_table_clone(data->srcp_table, GFP_KERNEL, true); if (IS_ERR_OR_NULL(data->tab_clone)) { if (!(data->tab_clone)) ret = -EINVAL; else ret = PTR_ERR(data->tab_clone); goto clone_err; } ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf, data->tab_clone, dom, &data->addr, &data->len, DMA_BIDIRECTIONAL); } else { ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf, data->srcp_table, dom, &data->addr, &data->len, DMA_BIDIRECTIONAL); data->srcp_table, dom, &data->addr, &data->len, DMA_BIDIRECTIONAL); } if (IS_ERR_VALUE(ret)) { pr_err("smmu map dma buf failed: (%d)\n", ret); Loading @@ -1926,6 +1952,10 @@ int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data, int client) data->skip_detach = false; } done: if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { data->addr += data->tab_clone->sgl->length; data->len -= data->tab_clone->sgl->length; } if (!ret && (img->offset < data->len)) { data->addr += img->offset; data->len -= img->offset; Loading @@ -1940,6 +1970,9 @@ done: } return ret; clone_err: dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table, mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL)); err_detach: dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment); err_put: Loading @@ -1950,6 +1983,11 @@ err_unmap: mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL)); dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment); dma_buf_put(data->srcp_dma_buf); if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { kfree(data->tab_clone->sgl); kfree(data->tab_clone); } return ret; } Loading
drivers/video/msm/mdss/mdp3.h +2 −1 Original line number Diff line number Diff line /* Copyright (c) 2013-2014, 2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2013-2014, 2016-2017, The Linux Foundation. All rights reserved. * Copyright (C) 2007 Google Incorporated * * This program is free software; you can redistribute it and/or modify Loading Loading @@ -233,6 +233,7 @@ struct mdp3_img_data { struct dma_buf *srcp_dma_buf; struct dma_buf_attachment *srcp_attachment; struct sg_table *srcp_table; struct sg_table *tab_clone; }; extern struct mdp3_hw_resource *mdp3_res; Loading
drivers/video/msm/mdss/mdss.h +2 −0 Original line number Diff line number Diff line Loading @@ -265,6 +265,8 @@ struct mdss_smmu_ops { void (*smmu_dsi_unmap_buffer)(dma_addr_t dma_addr, int domain, unsigned long size, int dir); void (*smmu_deinit)(struct mdss_data_type *mdata); struct sg_table * (*smmu_sg_table_clone)(struct sg_table *orig_table, gfp_t gfp_mask, bool padding); }; struct mdss_data_type { Loading
drivers/video/msm/mdss/mdss_smmu.c +130 −1 Original line number Diff line number Diff line /* Copyright (c) 2007-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2007-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -480,6 +480,134 @@ static void mdss_smmu_deinit_v2(struct mdss_data_type *mdata) } } /* * sg_clone - Duplicate an existing chained sgl * @orig_sgl: Original sg list to be duplicated * @len: Total length of sg while taking chaining into account * @gfp_mask: GFP allocation mask * @padding: specifies if padding is required * * Description: * Clone a chained sgl. This cloned copy may be modified in some ways while * keeping the original sgl in tact. Also allow the cloned copy to have * a smaller length than the original which may reduce the sgl total * sg entries and also allows cloned copy to have one extra sg entry on * either sides of sgl. * * Returns: * Pointer to new kmalloced sg list, ERR_PTR() on error * */ static struct scatterlist *sg_clone(struct scatterlist *orig_sgl, u64 len, gfp_t gfp_mask, bool padding) { int nents; bool last_entry; struct scatterlist *sgl, *head; nents = sg_nents(orig_sgl); if (nents < 0) return ERR_PTR(-EINVAL); if (padding) nents += 2; head = kmalloc_array(nents, sizeof(struct scatterlist), gfp_mask); if (!head) return ERR_PTR(-ENOMEM); sgl = head; sg_init_table(sgl, nents); if (padding) { *sgl = *orig_sgl; if (sg_is_chain(orig_sgl)) { orig_sgl = sg_next(orig_sgl); *sgl = *orig_sgl; } sgl->page_link &= (unsigned long)(~0x03); sgl = sg_next(sgl); } for (; sgl; orig_sgl = sg_next(orig_sgl), sgl = sg_next(sgl)) { last_entry = sg_is_last(sgl); /* * * If page_link is pointing to a chained sgl then set * the sg entry in the cloned list to the next sg entry * in the original sg list as chaining is already taken * care. */ if (sg_is_chain(orig_sgl)) orig_sgl = sg_next(orig_sgl); if (padding) last_entry = sg_is_last(orig_sgl); *sgl = *orig_sgl; sgl->page_link &= (unsigned long)(~0x03); if (last_entry) { if (padding) { len -= sg_dma_len(sgl); sgl = sg_next(sgl); *sgl = *orig_sgl; } sg_dma_len(sgl) = len ? len : SZ_4K; /* Set bit 1 to indicate end of sgl */ sgl->page_link |= 0x02; } else { len -= sg_dma_len(sgl); } } return head; } /* * sg_table_clone - Duplicate an existing sg_table including chained sgl * @orig_table: Original sg_table to be duplicated * @len: Total length of sg while taking chaining into account * @gfp_mask: GFP allocation mask * @padding: specifies if padding is required * * Description: * Clone a sg_table along with chained sgl. This cloned copy may be * modified in some ways while keeping the original table and sgl in tact. * Also allow the cloned sgl copy to have a smaller length than the original * which may reduce the sgl total sg entries. * * Returns: * Pointer to new kmalloced sg_table, ERR_PTR() on error * */ static struct sg_table *sg_table_clone(struct sg_table *orig_table, gfp_t gfp_mask, bool padding) { struct sg_table *table; struct scatterlist *sg = orig_table->sgl; u64 len = 0; for (len = 0; sg; sg = sg_next(sg)) len += sg->length; table = kmalloc(sizeof(struct sg_table), gfp_mask); if (!table) return ERR_PTR(-ENOMEM); table->sgl = sg_clone(orig_table->sgl, len, gfp_mask, padding); if (IS_ERR(table->sgl)) { kfree(table); return ERR_PTR(-ENOMEM); } table->nents = table->orig_nents = sg_nents(table->sgl); return table; } static void mdss_smmu_ops_init(struct mdss_data_type *mdata) { mdata->smmu_ops.smmu_attach = mdss_smmu_attach_v2; Loading @@ -501,6 +629,7 @@ static void mdss_smmu_ops_init(struct mdss_data_type *mdata) mdata->smmu_ops.smmu_dsi_unmap_buffer = mdss_smmu_dsi_unmap_buffer_v2; mdata->smmu_ops.smmu_deinit = mdss_smmu_deinit_v2; mdata->smmu_ops.smmu_sg_table_clone = sg_table_clone; } /* Loading
drivers/video/msm/mdss/mdss_smmu.h +13 −1 Original line number Diff line number Diff line /* Copyright (c) 2007-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2007-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -292,4 +292,16 @@ static inline void mdss_smmu_deinit(struct mdss_data_type *mdata) mdata->smmu_ops.smmu_deinit(mdata); } static inline struct sg_table *mdss_smmu_sg_table_clone(struct sg_table *orig_table, gfp_t gfp_mask, bool padding) { struct mdss_data_type *mdata = mdss_mdp_get_mdata(); if (!mdata || !mdata->smmu_ops.smmu_sg_table_clone) return NULL; return mdata->smmu_ops.smmu_sg_table_clone(orig_table, gfp_mask, padding); } #endif /* MDSS_SMMU_H */