summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c
diff options
context:
space:
mode:
authorAlex Waterman <alexw@nvidia.com>2016-08-16 20:01:44 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2016-09-20 17:56:39 -0400
commitd16415ac264777e00546ee3435818c5ee94baba0 (patch)
treed7e4b381a4b1686e5760df62cc896e3e0f3de739 /drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c
parentb102c11a4fbf88423b0220fe019b7ad96fd31430 (diff)
gpu: nvgpu: Implement carveout support in the buddy allocator
Implement carveout support in the buddy allocator so that the WPR space in the VIDMEM can be carved out. This is needed since the buddy allocator is used internally by the page allocator which is what manages the VIDMEM space. Jira DNVGPU-84 Change-Id: I864faa7e20fca5547cc3a8f85f1bc4c36af53ee0 Signed-off-by: Alex Waterman <alexw@nvidia.com> Reviewed-on: http://git-master/r/1203391 (cherry picked from commit a8a5fd265a8ae33093d144cd6ec5222e93280a0f) Reviewed-on: http://git-master/r/1223453 GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c134
1 files changed, 121 insertions, 13 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c b/drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c
index dd7f4d27..70a10c24 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c
+++ b/drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c
@@ -844,6 +844,8 @@ static u64 gk20a_buddy_balloc(struct gk20a_allocator *__a, u64 len)
844 alloc_dbg(balloc_owner(a), "Alloc failed: no mem!\n"); 844 alloc_dbg(balloc_owner(a), "Alloc failed: no mem!\n");
845 } 845 }
846 846
847 a->alloc_made = 1;
848
847 alloc_unlock(__a); 849 alloc_unlock(__a);
848 850
849 gk20a_alloc_trace_func_done(); 851 gk20a_alloc_trace_func_done();
@@ -851,15 +853,10 @@ static u64 gk20a_buddy_balloc(struct gk20a_allocator *__a, u64 len)
851} 853}
852 854
853/* 855/*
854 * Allocate a fixed address allocation. The address of the allocation is @base 856 * Requires @__a to be locked.
855 * and the length is @len. This is not a typical buddy allocator operation and
856 * as such has a high posibility of failure if the address space is heavily in
857 * use.
858 *
859 * Please do not use this function unless _absolutely_ necessary.
860 */ 857 */
861static u64 gk20a_balloc_fixed_buddy(struct gk20a_allocator *__a, 858static u64 __gk20a_balloc_fixed_buddy(struct gk20a_allocator *__a,
862 u64 base, u64 len) 859 u64 base, u64 len)
863{ 860{
864 u64 ret, real_bytes = 0; 861 u64 ret, real_bytes = 0;
865 struct gk20a_buddy *bud; 862 struct gk20a_buddy *bud;
@@ -883,7 +880,6 @@ static u64 gk20a_balloc_fixed_buddy(struct gk20a_allocator *__a,
883 falloc->start = base; 880 falloc->start = base;
884 falloc->end = base + len; 881 falloc->end = base + len;
885 882
886 alloc_lock(__a);
887 if (!balloc_is_range_free(a, base, base + len)) { 883 if (!balloc_is_range_free(a, base, base + len)) {
888 alloc_dbg(balloc_owner(a), 884 alloc_dbg(balloc_owner(a),
889 "Range not free: 0x%llx -> 0x%llx\n", 885 "Range not free: 0x%llx -> 0x%llx\n",
@@ -907,7 +903,6 @@ static u64 gk20a_balloc_fixed_buddy(struct gk20a_allocator *__a,
907 a->bytes_alloced += len; 903 a->bytes_alloced += len;
908 a->bytes_alloced_real += real_bytes; 904 a->bytes_alloced_real += real_bytes;
909 905
910 alloc_unlock(__a);
911 alloc_dbg(balloc_owner(a), "Alloc (fixed) 0x%llx\n", base); 906 alloc_dbg(balloc_owner(a), "Alloc (fixed) 0x%llx\n", base);
912 907
913 gk20a_alloc_trace_func_done(); 908 gk20a_alloc_trace_func_done();
@@ -922,6 +917,28 @@ fail:
922} 917}
923 918
924/* 919/*
920 * Allocate a fixed address allocation. The address of the allocation is @base
921 * and the length is @len. This is not a typical buddy allocator operation and
922 * as such has a high posibility of failure if the address space is heavily in
923 * use.
924 *
925 * Please do not use this function unless _absolutely_ necessary.
926 */
927static u64 gk20a_balloc_fixed_buddy(struct gk20a_allocator *__a,
928 u64 base, u64 len)
929{
930 u64 alloc;
931 struct gk20a_buddy_allocator *a = __a->priv;
932
933 alloc_lock(__a);
934 alloc = __gk20a_balloc_fixed_buddy(__a, base, len);
935 a->alloc_made = 1;
936 alloc_unlock(__a);
937
938 return alloc;
939}
940
941/*
925 * Free the passed allocation. 942 * Free the passed allocation.
926 */ 943 */
927static void gk20a_buddy_bfree(struct gk20a_allocator *__a, u64 addr) 944static void gk20a_buddy_bfree(struct gk20a_allocator *__a, u64 addr)
@@ -968,6 +985,81 @@ done:
968 return; 985 return;
969} 986}
970 987
988static bool gk20a_buddy_reserve_is_possible(struct gk20a_buddy_allocator *a,
989 struct gk20a_alloc_carveout *co)
990{
991 struct gk20a_alloc_carveout *tmp;
992 u64 co_base, co_end;
993
994 co_base = co->base;
995 co_end = co->base + co->length;
996
997 /*
998 * Not the fastest approach but we should not have that many carveouts
999 * for any reasonable allocator.
1000 */
1001 list_for_each_entry(tmp, &a->co_list, co_entry) {
1002 if ((co_base >= tmp->base &&
1003 co_base < (tmp->base + tmp->length)) ||
1004 (co_end >= tmp->base &&
1005 co_end < (tmp->base + tmp->length)))
1006 return false;
1007 }
1008
1009 return true;
1010}
1011
1012/*
1013 * Carveouts can only be reserved before any regular allocations have been
1014 * made.
1015 */
1016static int gk20a_buddy_reserve_co(struct gk20a_allocator *__a,
1017 struct gk20a_alloc_carveout *co)
1018{
1019 struct gk20a_buddy_allocator *a = __a->priv;
1020 u64 addr;
1021 int err = 0;
1022
1023 if (co->base < a->start || (co->base + co->length) > a->end ||
1024 a->alloc_made)
1025 return -EINVAL;
1026
1027 alloc_lock(__a);
1028
1029 if (!gk20a_buddy_reserve_is_possible(a, co)) {
1030 err = -EBUSY;
1031 goto done;
1032 }
1033
1034 /* Should not be possible to fail... */
1035 addr = __gk20a_balloc_fixed_buddy(__a, co->base, co->length);
1036 if (!addr) {
1037 err = -ENOMEM;
1038 pr_warn("%s: Failed to reserve a valid carveout!\n", __func__);
1039 goto done;
1040 }
1041
1042 list_add(&co->co_entry, &a->co_list);
1043
1044done:
1045 alloc_unlock(__a);
1046 return err;
1047}
1048
1049/*
1050 * Carveouts can be release at any time.
1051 */
1052static void gk20a_buddy_release_co(struct gk20a_allocator *__a,
1053 struct gk20a_alloc_carveout *co)
1054{
1055 alloc_lock(__a);
1056
1057 list_del_init(&co->co_entry);
1058 gk20a_free(__a, co->base);
1059
1060 alloc_unlock(__a);
1061}
1062
971static u64 gk20a_buddy_alloc_length(struct gk20a_allocator *a) 1063static u64 gk20a_buddy_alloc_length(struct gk20a_allocator *a)
972{ 1064{
973 struct gk20a_buddy_allocator *ba = a->priv; 1065 struct gk20a_buddy_allocator *ba = a->priv;
@@ -1004,9 +1096,10 @@ static u64 gk20a_buddy_alloc_end(struct gk20a_allocator *a)
1004static void gk20a_buddy_print_stats(struct gk20a_allocator *__a, 1096static void gk20a_buddy_print_stats(struct gk20a_allocator *__a,
1005 struct seq_file *s, int lock) 1097 struct seq_file *s, int lock)
1006{ 1098{
1007 int i; 1099 int i = 0;
1008 struct rb_node *node; 1100 struct rb_node *node;
1009 struct gk20a_fixed_alloc *falloc; 1101 struct gk20a_fixed_alloc *falloc;
1102 struct gk20a_alloc_carveout *tmp;
1010 struct gk20a_buddy_allocator *a = __a->priv; 1103 struct gk20a_buddy_allocator *a = __a->priv;
1011 1104
1012 __alloc_pstat(s, __a, "base = %llu, limit = %llu, blk_size = %llu\n", 1105 __alloc_pstat(s, __a, "base = %llu, limit = %llu, blk_size = %llu\n",
@@ -1018,12 +1111,23 @@ static void gk20a_buddy_print_stats(struct gk20a_allocator *__a,
1018 __alloc_pstat(s, __a, " blks = 0x%llx\n", a->blks); 1111 __alloc_pstat(s, __a, " blks = 0x%llx\n", a->blks);
1019 __alloc_pstat(s, __a, " max_order = %llu\n", a->max_order); 1112 __alloc_pstat(s, __a, " max_order = %llu\n", a->max_order);
1020 1113
1114 if (lock)
1115 alloc_lock(__a);
1116
1117 if (!list_empty(&a->co_list)) {
1118 __alloc_pstat(s, __a, "\n");
1119 __alloc_pstat(s, __a, "Carveouts:\n");
1120 list_for_each_entry(tmp, &a->co_list, co_entry)
1121 __alloc_pstat(s, __a,
1122 " CO %2d: %-20s 0x%010llx + 0x%llx\n",
1123 i++, tmp->name, tmp->base, tmp->length);
1124 }
1125
1126 __alloc_pstat(s, __a, "\n");
1021 __alloc_pstat(s, __a, "Buddy blocks:\n"); 1127 __alloc_pstat(s, __a, "Buddy blocks:\n");
1022 __alloc_pstat(s, __a, " Order Free Alloced Split\n"); 1128 __alloc_pstat(s, __a, " Order Free Alloced Split\n");
1023 __alloc_pstat(s, __a, " ----- ---- ------- -----\n"); 1129 __alloc_pstat(s, __a, " ----- ---- ------- -----\n");
1024 1130
1025 if (lock)
1026 alloc_lock(__a);
1027 for (i = a->max_order; i >= 0; i--) { 1131 for (i = a->max_order; i >= 0; i--) {
1028 if (a->buddy_list_len[i] == 0 && 1132 if (a->buddy_list_len[i] == 0 &&
1029 a->buddy_list_alloced[i] == 0 && 1133 a->buddy_list_alloced[i] == 0 &&
@@ -1067,6 +1171,9 @@ static const struct gk20a_allocator_ops buddy_ops = {
1067 .alloc_fixed = gk20a_balloc_fixed_buddy, 1171 .alloc_fixed = gk20a_balloc_fixed_buddy,
1068 /* .free_fixed not needed. */ 1172 /* .free_fixed not needed. */
1069 1173
1174 .reserve_carveout = gk20a_buddy_reserve_co,
1175 .release_carveout = gk20a_buddy_release_co,
1176
1070 .base = gk20a_buddy_alloc_base, 1177 .base = gk20a_buddy_alloc_base,
1071 .length = gk20a_buddy_alloc_length, 1178 .length = gk20a_buddy_alloc_length,
1072 .end = gk20a_buddy_alloc_end, 1179 .end = gk20a_buddy_alloc_end,
@@ -1172,6 +1279,7 @@ int __gk20a_buddy_allocator_init(struct gk20a_allocator *__a,
1172 1279
1173 a->alloced_buddies = RB_ROOT; 1280 a->alloced_buddies = RB_ROOT;
1174 a->fixed_allocs = RB_ROOT; 1281 a->fixed_allocs = RB_ROOT;
1282 INIT_LIST_HEAD(&a->co_list);
1175 err = balloc_init_lists(a); 1283 err = balloc_init_lists(a);
1176 if (err) 1284 if (err)
1177 goto fail; 1285 goto fail;