diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2010-09-01 01:24:33 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-09-24 02:20:28 -0400 |
commit | 5125bfd88608012d58652ac7ea6a03a78773200f (patch) | |
tree | 8ccb36c6a023392e3c8a9f2c4e84c74ccdcaeb44 /drivers/gpu/drm/nouveau/nouveau_object.c | |
parent | 43efc9ce25c6956133c07394a6fa44ef2c9268a4 (diff) |
drm/nv50: allow gpuobjs that aren't mapped into aperture
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_object.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_object.c | 102 |
1 files changed, 77 insertions, 25 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 4bcea11f54e6..df445fcb8321 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c | |||
@@ -75,7 +75,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, | |||
75 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 75 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
76 | struct nouveau_engine *engine = &dev_priv->engine; | 76 | struct nouveau_engine *engine = &dev_priv->engine; |
77 | struct nouveau_gpuobj *gpuobj; | 77 | struct nouveau_gpuobj *gpuobj; |
78 | struct drm_mm *pramin = NULL; | 78 | struct drm_mm_node *ramin = NULL; |
79 | int ret; | 79 | int ret; |
80 | 80 | ||
81 | NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n", | 81 | NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n", |
@@ -95,36 +95,42 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, | |||
95 | 95 | ||
96 | list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); | 96 | list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); |
97 | 97 | ||
98 | /* Choose between global instmem heap, and per-channel private | ||
99 | * instmem heap. On <NV50 allow requests for private instmem | ||
100 | * to be satisfied from global heap if no per-channel area | ||
101 | * available. | ||
102 | */ | ||
103 | if (chan) { | 98 | if (chan) { |
104 | NV_DEBUG(dev, "channel heap\n"); | 99 | NV_DEBUG(dev, "channel heap\n"); |
105 | pramin = &chan->ramin_heap; | 100 | |
101 | ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0); | ||
102 | if (ramin) | ||
103 | ramin = drm_mm_get_block(ramin, size, align); | ||
104 | |||
105 | if (!ramin) { | ||
106 | nouveau_gpuobj_ref(NULL, &gpuobj); | ||
107 | return -ENOMEM; | ||
108 | } | ||
106 | } else { | 109 | } else { |
107 | NV_DEBUG(dev, "global heap\n"); | 110 | NV_DEBUG(dev, "global heap\n"); |
108 | pramin = &dev_priv->ramin_heap; | ||
109 | 111 | ||
112 | /* allocate backing pages, sets vinst */ | ||
110 | ret = engine->instmem.populate(dev, gpuobj, &size); | 113 | ret = engine->instmem.populate(dev, gpuobj, &size); |
111 | if (ret) { | 114 | if (ret) { |
112 | nouveau_gpuobj_ref(NULL, &gpuobj); | 115 | nouveau_gpuobj_ref(NULL, &gpuobj); |
113 | return ret; | 116 | return ret; |
114 | } | 117 | } |
115 | } | ||
116 | 118 | ||
117 | /* Allocate a chunk of the PRAMIN aperture */ | 119 | /* try and get aperture space */ |
118 | gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0); | 120 | ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, align, 0); |
119 | if (gpuobj->im_pramin) | 121 | if (ramin) |
120 | gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align); | 122 | ramin = drm_mm_get_block(ramin, size, align); |
121 | 123 | ||
122 | if (!gpuobj->im_pramin) { | 124 | /* on nv50 it's ok to fail, we have a fallback path */ |
123 | nouveau_gpuobj_ref(NULL, &gpuobj); | 125 | if (!ramin && dev_priv->card_type < NV_50) { |
124 | return -ENOMEM; | 126 | nouveau_gpuobj_ref(NULL, &gpuobj); |
127 | return -ENOMEM; | ||
128 | } | ||
125 | } | 129 | } |
126 | 130 | ||
127 | if (!chan) { | 131 | /* if we got a chunk of the aperture, map pages into it */ |
132 | gpuobj->im_pramin = ramin; | ||
133 | if (!chan && gpuobj->im_pramin) { | ||
128 | ret = engine->instmem.bind(dev, gpuobj); | 134 | ret = engine->instmem.bind(dev, gpuobj); |
129 | if (ret) { | 135 | if (ret) { |
130 | nouveau_gpuobj_ref(NULL, &gpuobj); | 136 | nouveau_gpuobj_ref(NULL, &gpuobj); |
@@ -134,7 +140,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, | |||
134 | 140 | ||
135 | /* calculate the various different addresses for the object */ | 141 | /* calculate the various different addresses for the object */ |
136 | if (chan) { | 142 | if (chan) { |
137 | gpuobj->pinst = gpuobj->im_pramin->start + chan->ramin->pinst; | 143 | gpuobj->pinst = chan->ramin->pinst; |
144 | if (gpuobj->pinst != ~0) | ||
145 | gpuobj->pinst += gpuobj->im_pramin->start; | ||
146 | |||
138 | if (dev_priv->card_type < NV_50) { | 147 | if (dev_priv->card_type < NV_50) { |
139 | gpuobj->cinst = gpuobj->pinst; | 148 | gpuobj->cinst = gpuobj->pinst; |
140 | } else { | 149 | } else { |
@@ -143,7 +152,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, | |||
143 | chan->ramin->vinst; | 152 | chan->ramin->vinst; |
144 | } | 153 | } |
145 | } else { | 154 | } else { |
146 | gpuobj->pinst = gpuobj->im_pramin->start; | 155 | if (gpuobj->im_pramin) |
156 | gpuobj->pinst = gpuobj->im_pramin->start; | ||
157 | else | ||
158 | gpuobj->pinst = ~0; | ||
147 | gpuobj->cinst = 0xdeadbeef; | 159 | gpuobj->cinst = 0xdeadbeef; |
148 | } | 160 | } |
149 | 161 | ||
@@ -168,6 +180,8 @@ nouveau_gpuobj_early_init(struct drm_device *dev) | |||
168 | NV_DEBUG(dev, "\n"); | 180 | NV_DEBUG(dev, "\n"); |
169 | 181 | ||
170 | INIT_LIST_HEAD(&dev_priv->gpuobj_list); | 182 | INIT_LIST_HEAD(&dev_priv->gpuobj_list); |
183 | spin_lock_init(&dev_priv->ramin_lock); | ||
184 | dev_priv->ramin_base = ~0; | ||
171 | 185 | ||
172 | return 0; | 186 | return 0; |
173 | } | 187 | } |
@@ -650,12 +664,15 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, | |||
650 | * locations determined during init. | 664 | * locations determined during init. |
651 | */ | 665 | */ |
652 | if (dev_priv->card_type >= NV_50) { | 666 | if (dev_priv->card_type >= NV_50) { |
653 | uint32_t vm_offset, pde; | 667 | u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200; |
668 | u64 vm_vinst = chan->ramin->vinst + pgd_offs; | ||
669 | u32 vm_pinst = chan->ramin->pinst; | ||
670 | u32 pde; | ||
654 | 671 | ||
655 | vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200; | 672 | if (vm_pinst != ~0) |
656 | vm_offset += chan->ramin->im_pramin->start; | 673 | vm_pinst += pgd_offs; |
657 | 674 | ||
658 | ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000, | 675 | ret = nouveau_gpuobj_new_fake(dev, vm_pinst, vm_vinst, 0x4000, |
659 | 0, &chan->vm_pd); | 676 | 0, &chan->vm_pd); |
660 | if (ret) | 677 | if (ret) |
661 | return ret; | 678 | return ret; |
@@ -941,11 +958,46 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, | |||
941 | u32 | 958 | u32 |
942 | nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset) | 959 | nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset) |
943 | { | 960 | { |
944 | return nv_ri32(gpuobj->dev, gpuobj->pinst + offset); | 961 | struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; |
962 | struct drm_device *dev = gpuobj->dev; | ||
963 | |||
964 | if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) { | ||
965 | u64 ptr = gpuobj->vinst + offset; | ||
966 | u32 base = ptr >> 16; | ||
967 | u32 val; | ||
968 | |||
969 | spin_lock(&dev_priv->ramin_lock); | ||
970 | if (dev_priv->ramin_base != base) { | ||
971 | dev_priv->ramin_base = base; | ||
972 | nv_wr32(dev, 0x001700, dev_priv->ramin_base); | ||
973 | } | ||
974 | val = nv_rd32(dev, 0x700000 + (ptr & 0xffff)); | ||
975 | spin_unlock(&dev_priv->ramin_lock); | ||
976 | return val; | ||
977 | } | ||
978 | |||
979 | return nv_ri32(dev, gpuobj->pinst + offset); | ||
945 | } | 980 | } |
946 | 981 | ||
947 | void | 982 | void |
948 | nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val) | 983 | nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val) |
949 | { | 984 | { |
950 | nv_wi32(gpuobj->dev, gpuobj->pinst + offset, val); | 985 | struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; |
986 | struct drm_device *dev = gpuobj->dev; | ||
987 | |||
988 | if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) { | ||
989 | u64 ptr = gpuobj->vinst + offset; | ||
990 | u32 base = ptr >> 16; | ||
991 | |||
992 | spin_lock(&dev_priv->ramin_lock); | ||
993 | if (dev_priv->ramin_base != base) { | ||
994 | dev_priv->ramin_base = base; | ||
995 | nv_wr32(dev, 0x001700, dev_priv->ramin_base); | ||
996 | } | ||
997 | nv_wr32(dev, 0x700000 + (ptr & 0xffff), val); | ||
998 | spin_unlock(&dev_priv->ramin_lock); | ||
999 | return; | ||
1000 | } | ||
1001 | |||
1002 | nv_wi32(dev, gpuobj->pinst + offset, val); | ||
951 | } | 1003 | } |