0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #include "nouveau_drv.h"
0028 #include "nouveau_dma.h"
0029 #include "nouveau_vmm.h"
0030
0031 #include <nvif/user.h>
0032
0033
0034
0035
0036
0037
0038
0039
0040 static inline int
0041 READ_GET(struct nouveau_channel *chan, uint64_t *prev_get, int *timeout)
0042 {
0043 uint64_t val;
0044
0045 val = nvif_rd32(&chan->user, chan->user_get);
0046 if (chan->user_get_hi)
0047 val |= (uint64_t)nvif_rd32(&chan->user, chan->user_get_hi) << 32;
0048
0049
0050
0051
0052
0053 if (val != *prev_get) {
0054 *prev_get = val;
0055 *timeout = 0;
0056 }
0057
0058 if ((++*timeout & 0xff) == 0) {
0059 udelay(1);
0060 if (*timeout > 100000)
0061 return -EBUSY;
0062 }
0063
0064 if (val < chan->push.addr ||
0065 val > chan->push.addr + (chan->dma.max << 2))
0066 return -EINVAL;
0067
0068 return (val - chan->push.addr) >> 2;
0069 }
0070
0071 void
0072 nv50_dma_push(struct nouveau_channel *chan, u64 offset, int length)
0073 {
0074 struct nvif_user *user = &chan->drm->client.device.user;
0075 struct nouveau_bo *pb = chan->push.buffer;
0076 int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base;
0077
0078 BUG_ON(chan->dma.ib_free < 1);
0079
0080 nouveau_bo_wr32(pb, ip++, lower_32_bits(offset));
0081 nouveau_bo_wr32(pb, ip++, upper_32_bits(offset) | length << 8);
0082
0083 chan->dma.ib_put = (chan->dma.ib_put + 1) & chan->dma.ib_max;
0084
0085 mb();
0086
0087 nouveau_bo_rd32(pb, 0);
0088
0089 nvif_wr32(&chan->user, 0x8c, chan->dma.ib_put);
0090 if (user->func && user->func->doorbell)
0091 user->func->doorbell(user, chan->token);
0092 chan->dma.ib_free--;
0093 }
0094
0095 static int
0096 nv50_dma_push_wait(struct nouveau_channel *chan, int count)
0097 {
0098 uint32_t cnt = 0, prev_get = 0;
0099
0100 while (chan->dma.ib_free < count) {
0101 uint32_t get = nvif_rd32(&chan->user, 0x88);
0102 if (get != prev_get) {
0103 prev_get = get;
0104 cnt = 0;
0105 }
0106
0107 if ((++cnt & 0xff) == 0) {
0108 udelay(1);
0109 if (cnt > 100000)
0110 return -EBUSY;
0111 }
0112
0113 chan->dma.ib_free = get - chan->dma.ib_put;
0114 if (chan->dma.ib_free <= 0)
0115 chan->dma.ib_free += chan->dma.ib_max;
0116 }
0117
0118 return 0;
0119 }
0120
0121 static int
0122 nv50_dma_wait(struct nouveau_channel *chan, int slots, int count)
0123 {
0124 uint64_t prev_get = 0;
0125 int ret, cnt = 0;
0126
0127 ret = nv50_dma_push_wait(chan, slots + 1);
0128 if (unlikely(ret))
0129 return ret;
0130
0131 while (chan->dma.free < count) {
0132 int get = READ_GET(chan, &prev_get, &cnt);
0133 if (unlikely(get < 0)) {
0134 if (get == -EINVAL)
0135 continue;
0136
0137 return get;
0138 }
0139
0140 if (get <= chan->dma.cur) {
0141 chan->dma.free = chan->dma.max - chan->dma.cur;
0142 if (chan->dma.free >= count)
0143 break;
0144
0145 FIRE_RING(chan);
0146 do {
0147 get = READ_GET(chan, &prev_get, &cnt);
0148 if (unlikely(get < 0)) {
0149 if (get == -EINVAL)
0150 continue;
0151 return get;
0152 }
0153 } while (get == 0);
0154 chan->dma.cur = 0;
0155 chan->dma.put = 0;
0156 }
0157
0158 chan->dma.free = get - chan->dma.cur - 1;
0159 }
0160
0161 return 0;
0162 }
0163
0164 int
0165 nouveau_dma_wait(struct nouveau_channel *chan, int slots, int size)
0166 {
0167 uint64_t prev_get = 0;
0168 int cnt = 0, get;
0169
0170 if (chan->dma.ib_max)
0171 return nv50_dma_wait(chan, slots, size);
0172
0173 while (chan->dma.free < size) {
0174 get = READ_GET(chan, &prev_get, &cnt);
0175 if (unlikely(get == -EBUSY))
0176 return -EBUSY;
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187 if (unlikely(get == -EINVAL) || get < NOUVEAU_DMA_SKIPS)
0188 continue;
0189
0190 if (get <= chan->dma.cur) {
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204 chan->dma.free = chan->dma.max - chan->dma.cur;
0205 if (chan->dma.free >= size)
0206 break;
0207
0208
0209
0210
0211
0212 OUT_RING(chan, chan->push.addr | 0x20000000);
0213
0214
0215
0216
0217
0218
0219 do {
0220 get = READ_GET(chan, &prev_get, &cnt);
0221 if (unlikely(get == -EBUSY))
0222 return -EBUSY;
0223 if (unlikely(get == -EINVAL))
0224 continue;
0225 } while (get <= NOUVEAU_DMA_SKIPS);
0226 WRITE_PUT(NOUVEAU_DMA_SKIPS);
0227
0228
0229
0230
0231 chan->dma.cur =
0232 chan->dma.put = NOUVEAU_DMA_SKIPS;
0233 }
0234
0235
0236
0237
0238
0239
0240
0241 chan->dma.free = get - chan->dma.cur - 1;
0242 }
0243
0244 return 0;
0245 }
0246