diff options
author | YoungJun Cho <yj44.cho@samsung.com> | 2013-03-13 04:10:08 -0400 |
---|---|---|
committer | Inki Dae <inki.dae@samsung.com> | 2013-03-20 06:09:11 -0400 |
commit | 9963cb6ef9e6f925617b3c74f0700bf5fbee9a1d (patch) | |
tree | b0d3638ea0874d5dd43380268d07c7ce550193f7 | |
parent | f3d2fc4a7315d8dd39e6fb37122a3aa08fea6e62 (diff) |
drm/exynos: Deal with g2d buffer info more efficiently
This patch adds g2d_buf_info structure and buffer relevant
variables moves into the g2d_buf_info to manage g2d buffer
information more efficiently.
Changelog v2:
- Fix merge conflict.
Signed-off-by: YoungJun Cho <yj44.cho@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_g2d.c | 160 |
1 files changed, 123 insertions, 37 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 7c1aac3871da..1a022dc4188e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c | |||
@@ -96,8 +96,6 @@ | |||
96 | #define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM) | 96 | #define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM) |
97 | #define G2D_CMDLIST_DATA_NUM (G2D_CMDLIST_SIZE / sizeof(u32) - 2) | 97 | #define G2D_CMDLIST_DATA_NUM (G2D_CMDLIST_SIZE / sizeof(u32) - 2) |
98 | 98 | ||
99 | #define MAX_BUF_ADDR_NR 6 | ||
100 | |||
101 | /* maximum buffer pool size of userptr is 64MB as default */ | 99 | /* maximum buffer pool size of userptr is 64MB as default */ |
102 | #define MAX_POOL (64 * 1024 * 1024) | 100 | #define MAX_POOL (64 * 1024 * 1024) |
103 | 101 | ||
@@ -106,6 +104,17 @@ enum { | |||
106 | BUF_TYPE_USERPTR, | 104 | BUF_TYPE_USERPTR, |
107 | }; | 105 | }; |
108 | 106 | ||
107 | enum g2d_reg_type { | ||
108 | REG_TYPE_NONE = -1, | ||
109 | REG_TYPE_SRC, | ||
110 | REG_TYPE_SRC_PLANE2, | ||
111 | REG_TYPE_DST, | ||
112 | REG_TYPE_DST_PLANE2, | ||
113 | REG_TYPE_PAT, | ||
114 | REG_TYPE_MSK, | ||
115 | MAX_REG_TYPE_NR | ||
116 | }; | ||
117 | |||
109 | /* cmdlist data structure */ | 118 | /* cmdlist data structure */ |
110 | struct g2d_cmdlist { | 119 | struct g2d_cmdlist { |
111 | u32 head; | 120 | u32 head; |
@@ -113,6 +122,22 @@ struct g2d_cmdlist { | |||
113 | u32 last; /* last data offset */ | 122 | u32 last; /* last data offset */ |
114 | }; | 123 | }; |
115 | 124 | ||
125 | /* | ||
126 | * A structure of buffer information | ||
127 | * | ||
128 | * @map_nr: manages the number of mapped buffers | ||
129 | * @reg_types: stores regitster type in the order of requested command | ||
130 | * @handles: stores buffer handle in its reg_type position | ||
131 | * @types: stores buffer type in its reg_type position | ||
132 | * | ||
133 | */ | ||
134 | struct g2d_buf_info { | ||
135 | unsigned int map_nr; | ||
136 | enum g2d_reg_type reg_types[MAX_REG_TYPE_NR]; | ||
137 | unsigned long handles[MAX_REG_TYPE_NR]; | ||
138 | unsigned int types[MAX_REG_TYPE_NR]; | ||
139 | }; | ||
140 | |||
116 | struct drm_exynos_pending_g2d_event { | 141 | struct drm_exynos_pending_g2d_event { |
117 | struct drm_pending_event base; | 142 | struct drm_pending_event base; |
118 | struct drm_exynos_g2d_event event; | 143 | struct drm_exynos_g2d_event event; |
@@ -134,10 +159,8 @@ struct g2d_cmdlist_userptr { | |||
134 | struct g2d_cmdlist_node { | 159 | struct g2d_cmdlist_node { |
135 | struct list_head list; | 160 | struct list_head list; |
136 | struct g2d_cmdlist *cmdlist; | 161 | struct g2d_cmdlist *cmdlist; |
137 | unsigned int map_nr; | ||
138 | unsigned long handles[MAX_BUF_ADDR_NR]; | ||
139 | unsigned int buf_type[MAX_BUF_ADDR_NR]; | ||
140 | dma_addr_t dma_addr; | 162 | dma_addr_t dma_addr; |
163 | struct g2d_buf_info buf_info; | ||
141 | 164 | ||
142 | struct drm_exynos_pending_g2d_event *event; | 165 | struct drm_exynos_pending_g2d_event *event; |
143 | }; | 166 | }; |
@@ -187,6 +210,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) | |||
187 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; | 210 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; |
188 | int nr; | 211 | int nr; |
189 | int ret; | 212 | int ret; |
213 | struct g2d_buf_info *buf_info; | ||
190 | 214 | ||
191 | init_dma_attrs(&g2d->cmdlist_dma_attrs); | 215 | init_dma_attrs(&g2d->cmdlist_dma_attrs); |
192 | dma_set_attr(DMA_ATTR_WRITE_COMBINE, &g2d->cmdlist_dma_attrs); | 216 | dma_set_attr(DMA_ATTR_WRITE_COMBINE, &g2d->cmdlist_dma_attrs); |
@@ -208,11 +232,17 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) | |||
208 | } | 232 | } |
209 | 233 | ||
210 | for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) { | 234 | for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) { |
235 | unsigned int i; | ||
236 | |||
211 | node[nr].cmdlist = | 237 | node[nr].cmdlist = |
212 | g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE; | 238 | g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE; |
213 | node[nr].dma_addr = | 239 | node[nr].dma_addr = |
214 | g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE; | 240 | g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE; |
215 | 241 | ||
242 | buf_info = &node[nr].buf_info; | ||
243 | for (i = 0; i < MAX_REG_TYPE_NR; i++) | ||
244 | buf_info->reg_types[i] = REG_TYPE_NONE; | ||
245 | |||
216 | list_add_tail(&node[nr].list, &g2d->free_cmdlist); | 246 | list_add_tail(&node[nr].list, &g2d->free_cmdlist); |
217 | } | 247 | } |
218 | 248 | ||
@@ -507,36 +537,80 @@ static void g2d_userptr_free_all(struct drm_device *drm_dev, | |||
507 | g2d->current_pool = 0; | 537 | g2d->current_pool = 0; |
508 | } | 538 | } |
509 | 539 | ||
540 | static enum g2d_reg_type g2d_get_reg_type(int reg_offset) | ||
541 | { | ||
542 | enum g2d_reg_type reg_type; | ||
543 | |||
544 | switch (reg_offset) { | ||
545 | case G2D_SRC_BASE_ADDR: | ||
546 | reg_type = REG_TYPE_SRC; | ||
547 | break; | ||
548 | case G2D_SRC_PLANE2_BASE_ADDR: | ||
549 | reg_type = REG_TYPE_SRC_PLANE2; | ||
550 | break; | ||
551 | case G2D_DST_BASE_ADDR: | ||
552 | reg_type = REG_TYPE_DST; | ||
553 | break; | ||
554 | case G2D_DST_PLANE2_BASE_ADDR: | ||
555 | reg_type = REG_TYPE_DST_PLANE2; | ||
556 | break; | ||
557 | case G2D_PAT_BASE_ADDR: | ||
558 | reg_type = REG_TYPE_PAT; | ||
559 | break; | ||
560 | case G2D_MSK_BASE_ADDR: | ||
561 | reg_type = REG_TYPE_MSK; | ||
562 | break; | ||
563 | default: | ||
564 | reg_type = REG_TYPE_NONE; | ||
565 | DRM_ERROR("Unknown register offset![%d]\n", reg_offset); | ||
566 | break; | ||
567 | }; | ||
568 | |||
569 | return reg_type; | ||
570 | } | ||
571 | |||
510 | static int g2d_map_cmdlist_gem(struct g2d_data *g2d, | 572 | static int g2d_map_cmdlist_gem(struct g2d_data *g2d, |
511 | struct g2d_cmdlist_node *node, | 573 | struct g2d_cmdlist_node *node, |
512 | struct drm_device *drm_dev, | 574 | struct drm_device *drm_dev, |
513 | struct drm_file *file) | 575 | struct drm_file *file) |
514 | { | 576 | { |
515 | struct g2d_cmdlist *cmdlist = node->cmdlist; | 577 | struct g2d_cmdlist *cmdlist = node->cmdlist; |
578 | struct g2d_buf_info *buf_info = &node->buf_info; | ||
516 | int offset; | 579 | int offset; |
580 | int ret; | ||
517 | int i; | 581 | int i; |
518 | 582 | ||
519 | for (i = 0; i < node->map_nr; i++) { | 583 | for (i = 0; i < buf_info->map_nr; i++) { |
584 | enum g2d_reg_type reg_type; | ||
585 | int reg_pos; | ||
520 | unsigned long handle; | 586 | unsigned long handle; |
521 | dma_addr_t *addr; | 587 | dma_addr_t *addr; |
522 | 588 | ||
523 | offset = cmdlist->last - (i * 2 + 1); | 589 | reg_pos = cmdlist->last - 2 * (i + 1); |
524 | handle = cmdlist->data[offset]; | 590 | |
591 | offset = cmdlist->data[reg_pos]; | ||
592 | handle = cmdlist->data[reg_pos + 1]; | ||
593 | |||
594 | reg_type = g2d_get_reg_type(offset); | ||
595 | if (reg_type == REG_TYPE_NONE) { | ||
596 | ret = -EFAULT; | ||
597 | goto err; | ||
598 | } | ||
525 | 599 | ||
526 | if (node->buf_type[i] == BUF_TYPE_GEM) { | 600 | if (buf_info->types[reg_type] == BUF_TYPE_GEM) { |
527 | addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, | 601 | addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, |
528 | file); | 602 | file); |
529 | if (IS_ERR(addr)) { | 603 | if (IS_ERR(addr)) { |
530 | node->map_nr = i; | 604 | ret = -EFAULT; |
531 | return -EFAULT; | 605 | goto err; |
532 | } | 606 | } |
533 | } else { | 607 | } else { |
534 | struct drm_exynos_g2d_userptr g2d_userptr; | 608 | struct drm_exynos_g2d_userptr g2d_userptr; |
535 | 609 | ||
536 | if (copy_from_user(&g2d_userptr, (void __user *)handle, | 610 | if (copy_from_user(&g2d_userptr, (void __user *)handle, |
537 | sizeof(struct drm_exynos_g2d_userptr))) { | 611 | sizeof(struct drm_exynos_g2d_userptr))) { |
538 | node->map_nr = i; | 612 | ret = -EFAULT; |
539 | return -EFAULT; | 613 | goto err; |
540 | } | 614 | } |
541 | 615 | ||
542 | addr = g2d_userptr_get_dma_addr(drm_dev, | 616 | addr = g2d_userptr_get_dma_addr(drm_dev, |
@@ -545,16 +619,21 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, | |||
545 | file, | 619 | file, |
546 | &handle); | 620 | &handle); |
547 | if (IS_ERR(addr)) { | 621 | if (IS_ERR(addr)) { |
548 | node->map_nr = i; | 622 | ret = -EFAULT; |
549 | return -EFAULT; | 623 | goto err; |
550 | } | 624 | } |
551 | } | 625 | } |
552 | 626 | ||
553 | cmdlist->data[offset] = *addr; | 627 | cmdlist->data[reg_pos + 1] = *addr; |
554 | node->handles[i] = handle; | 628 | buf_info->reg_types[i] = reg_type; |
629 | buf_info->handles[reg_type] = handle; | ||
555 | } | 630 | } |
556 | 631 | ||
557 | return 0; | 632 | return 0; |
633 | |||
634 | err: | ||
635 | buf_info->map_nr = i; | ||
636 | return ret; | ||
558 | } | 637 | } |
559 | 638 | ||
560 | static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, | 639 | static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, |
@@ -562,23 +641,30 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, | |||
562 | struct drm_file *filp) | 641 | struct drm_file *filp) |
563 | { | 642 | { |
564 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; | 643 | struct exynos_drm_subdrv *subdrv = &g2d->subdrv; |
644 | struct g2d_buf_info *buf_info = &node->buf_info; | ||
565 | int i; | 645 | int i; |
566 | 646 | ||
567 | for (i = 0; i < node->map_nr; i++) { | 647 | for (i = 0; i < buf_info->map_nr; i++) { |
568 | unsigned long handle = node->handles[i]; | 648 | enum g2d_reg_type reg_type; |
649 | unsigned long handle; | ||
650 | |||
651 | reg_type = buf_info->reg_types[i]; | ||
569 | 652 | ||
570 | if (node->buf_type[i] == BUF_TYPE_GEM) | 653 | handle = buf_info->handles[reg_type]; |
654 | |||
655 | if (buf_info->types[reg_type] == BUF_TYPE_GEM) | ||
571 | exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle, | 656 | exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle, |
572 | filp); | 657 | filp); |
573 | else | 658 | else |
574 | g2d_userptr_put_dma_addr(subdrv->drm_dev, handle, | 659 | g2d_userptr_put_dma_addr(subdrv->drm_dev, handle, |
575 | false); | 660 | false); |
576 | 661 | ||
577 | node->handles[i] = 0; | 662 | buf_info->reg_types[i] = REG_TYPE_NONE; |
578 | node->buf_type[i] = 0; | 663 | buf_info->handles[reg_type] = 0; |
664 | buf_info->types[reg_type] = 0; | ||
579 | } | 665 | } |
580 | 666 | ||
581 | node->map_nr = 0; | 667 | buf_info->map_nr = 0; |
582 | } | 668 | } |
583 | 669 | ||
584 | static void g2d_dma_start(struct g2d_data *g2d, | 670 | static void g2d_dma_start(struct g2d_data *g2d, |
@@ -721,20 +807,12 @@ static int g2d_check_reg_offset(struct device *dev, | |||
721 | int i; | 807 | int i; |
722 | 808 | ||
723 | for (i = 0; i < nr; i++) { | 809 | for (i = 0; i < nr; i++) { |
724 | index = cmdlist->last - 2 * (i + 1); | 810 | struct g2d_buf_info *buf_info = &node->buf_info; |
811 | enum g2d_reg_type reg_type; | ||
725 | 812 | ||
726 | if (for_addr) { | 813 | index = cmdlist->last - 2 * (i + 1); |
727 | /* check userptr buffer type. */ | ||
728 | reg_offset = (cmdlist->data[index] & | ||
729 | ~0x7fffffff) >> 31; | ||
730 | if (reg_offset) { | ||
731 | node->buf_type[i] = BUF_TYPE_USERPTR; | ||
732 | cmdlist->data[index] &= ~G2D_BUF_USERPTR; | ||
733 | } | ||
734 | } | ||
735 | 814 | ||
736 | reg_offset = cmdlist->data[index] & ~0xfffff000; | 815 | reg_offset = cmdlist->data[index] & ~0xfffff000; |
737 | |||
738 | if (reg_offset < G2D_VALID_START || reg_offset > G2D_VALID_END) | 816 | if (reg_offset < G2D_VALID_START || reg_offset > G2D_VALID_END) |
739 | goto err; | 817 | goto err; |
740 | if (reg_offset % 4) | 818 | if (reg_offset % 4) |
@@ -750,8 +828,16 @@ static int g2d_check_reg_offset(struct device *dev, | |||
750 | if (!for_addr) | 828 | if (!for_addr) |
751 | goto err; | 829 | goto err; |
752 | 830 | ||
753 | if (node->buf_type[i] != BUF_TYPE_USERPTR) | 831 | reg_type = g2d_get_reg_type(reg_offset); |
754 | node->buf_type[i] = BUF_TYPE_GEM; | 832 | if (reg_type == REG_TYPE_NONE) |
833 | goto err; | ||
834 | |||
835 | /* check userptr buffer type. */ | ||
836 | if ((cmdlist->data[index] & ~0x7fffffff) >> 31) { | ||
837 | buf_info->types[reg_type] = BUF_TYPE_USERPTR; | ||
838 | cmdlist->data[index] &= ~G2D_BUF_USERPTR; | ||
839 | } else | ||
840 | buf_info->types[reg_type] = BUF_TYPE_GEM; | ||
755 | break; | 841 | break; |
756 | default: | 842 | default: |
757 | if (for_addr) | 843 | if (for_addr) |
@@ -898,7 +984,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, | |||
898 | if (ret < 0) | 984 | if (ret < 0) |
899 | goto err_free_event; | 985 | goto err_free_event; |
900 | 986 | ||
901 | node->map_nr = req->cmd_buf_nr; | 987 | node->buf_info.map_nr = req->cmd_buf_nr; |
902 | if (req->cmd_buf_nr) { | 988 | if (req->cmd_buf_nr) { |
903 | struct drm_exynos_g2d_cmd *cmd_buf; | 989 | struct drm_exynos_g2d_cmd *cmd_buf; |
904 | 990 | ||