diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 68 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.c | 19 |
3 files changed, 58 insertions, 30 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index e487e079..f9b29396 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c | |||
@@ -47,6 +47,19 @@ | |||
47 | #define NVGPU_CHANNEL_MIN_TIMESLICE_US 1000 | 47 | #define NVGPU_CHANNEL_MIN_TIMESLICE_US 1000 |
48 | #define NVGPU_CHANNEL_MAX_TIMESLICE_US 50000 | 48 | #define NVGPU_CHANNEL_MAX_TIMESLICE_US 50000 |
49 | 49 | ||
50 | /* | ||
51 | * Although channels do have pointers back to the gk20a struct that they were | ||
52 | * created under in cases where the driver is killed that pointer can be bad. | ||
53 | * The channel memory can be freed before the release() function for a given | ||
54 | * channel is called. This happens when the driver dies and userspace doesn't | ||
55 | * get a chance to call release() until after the entire gk20a driver data is | ||
56 | * unloaded and freed. | ||
57 | */ | ||
58 | struct channel_priv { | ||
59 | struct gk20a *g; | ||
60 | struct channel_gk20a *c; | ||
61 | }; | ||
62 | |||
50 | static struct channel_gk20a *allocate_channel(struct fifo_gk20a *f); | 63 | static struct channel_gk20a *allocate_channel(struct fifo_gk20a *f); |
51 | static void free_channel(struct fifo_gk20a *f, struct channel_gk20a *c); | 64 | static void free_channel(struct fifo_gk20a *f, struct channel_gk20a *c); |
52 | 65 | ||
@@ -392,7 +405,6 @@ void channel_gk20a_unbind(struct channel_gk20a *ch_gk20a) | |||
392 | 405 | ||
393 | gk20a_dbg_fn(""); | 406 | gk20a_dbg_fn(""); |
394 | 407 | ||
395 | |||
396 | if (atomic_cmpxchg(&ch_gk20a->bound, true, false)) { | 408 | if (atomic_cmpxchg(&ch_gk20a->bound, true, false)) { |
397 | gk20a_writel(g, ccsr_channel_inst_r(ch_gk20a->hw_chid), | 409 | gk20a_writel(g, ccsr_channel_inst_r(ch_gk20a->hw_chid), |
398 | ccsr_channel_inst_ptr_f(0) | | 410 | ccsr_channel_inst_ptr_f(0) | |
@@ -1123,16 +1135,31 @@ void gk20a_channel_close(struct channel_gk20a *ch) | |||
1123 | gk20a_free_channel(ch); | 1135 | gk20a_free_channel(ch); |
1124 | } | 1136 | } |
1125 | 1137 | ||
1126 | int gk20a_channel_release(struct inode *inode, struct file *filp) | 1138 | struct channel_gk20a *gk20a_get_channel_from_file(int fd) |
1127 | { | 1139 | { |
1128 | struct channel_gk20a *ch = (struct channel_gk20a *)filp->private_data; | 1140 | struct channel_priv *priv; |
1129 | struct gk20a *g = ch ? ch->g : NULL; | 1141 | struct file *f = fget(fd); |
1130 | int err; | ||
1131 | 1142 | ||
1132 | if (!ch) | 1143 | if (!f) |
1133 | return 0; | 1144 | return NULL; |
1134 | 1145 | ||
1135 | trace_gk20a_channel_release(dev_name(g->dev)); | 1146 | if (f->f_op != &gk20a_channel_ops) { |
1147 | fput(f); | ||
1148 | return NULL; | ||
1149 | } | ||
1150 | |||
1151 | priv = (struct channel_priv *)f->private_data; | ||
1152 | fput(f); | ||
1153 | return priv->c; | ||
1154 | } | ||
1155 | |||
1156 | int gk20a_channel_release(struct inode *inode, struct file *filp) | ||
1157 | { | ||
1158 | struct channel_priv *priv = filp->private_data; | ||
1159 | struct channel_gk20a *ch = priv->c; | ||
1160 | struct gk20a *g = priv->g; | ||
1161 | |||
1162 | int err; | ||
1136 | 1163 | ||
1137 | err = gk20a_busy(g->dev); | 1164 | err = gk20a_busy(g->dev); |
1138 | if (err) { | 1165 | if (err) { |
@@ -1140,6 +1167,9 @@ int gk20a_channel_release(struct inode *inode, struct file *filp) | |||
1140 | ch->hw_chid); | 1167 | ch->hw_chid); |
1141 | return err; | 1168 | return err; |
1142 | } | 1169 | } |
1170 | |||
1171 | trace_gk20a_channel_release(dev_name(g->dev)); | ||
1172 | |||
1143 | gk20a_channel_close(ch); | 1173 | gk20a_channel_close(ch); |
1144 | gk20a_idle(g->dev); | 1174 | gk20a_idle(g->dev); |
1145 | 1175 | ||
@@ -1279,15 +1309,20 @@ static int __gk20a_channel_open(struct gk20a *g, struct file *filp, s32 runlist_ | |||
1279 | { | 1309 | { |
1280 | int err; | 1310 | int err; |
1281 | struct channel_gk20a *ch; | 1311 | struct channel_gk20a *ch; |
1312 | struct channel_priv *priv; | ||
1282 | 1313 | ||
1283 | gk20a_dbg_fn(""); | 1314 | gk20a_dbg_fn(""); |
1284 | 1315 | ||
1285 | trace_gk20a_channel_open(dev_name(g->dev)); | 1316 | trace_gk20a_channel_open(dev_name(g->dev)); |
1286 | 1317 | ||
1318 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
1319 | if (!priv) | ||
1320 | return -ENOMEM; | ||
1321 | |||
1287 | err = gk20a_busy(g->dev); | 1322 | err = gk20a_busy(g->dev); |
1288 | if (err) { | 1323 | if (err) { |
1289 | gk20a_err(dev_from_gk20a(g), "failed to power on, %d", err); | 1324 | gk20a_err(dev_from_gk20a(g), "failed to power on, %d", err); |
1290 | return err; | 1325 | goto fail_busy; |
1291 | } | 1326 | } |
1292 | /* All the user space channel should be non privilege */ | 1327 | /* All the user space channel should be non privilege */ |
1293 | ch = gk20a_open_new_channel(g, runlist_id, false); | 1328 | ch = gk20a_open_new_channel(g, runlist_id, false); |
@@ -1295,14 +1330,22 @@ static int __gk20a_channel_open(struct gk20a *g, struct file *filp, s32 runlist_ | |||
1295 | if (!ch) { | 1330 | if (!ch) { |
1296 | gk20a_err(dev_from_gk20a(g), | 1331 | gk20a_err(dev_from_gk20a(g), |
1297 | "failed to get f"); | 1332 | "failed to get f"); |
1298 | return -ENOMEM; | 1333 | err = -ENOMEM; |
1334 | goto fail_busy; | ||
1299 | } | 1335 | } |
1300 | 1336 | ||
1301 | gk20a_channel_trace_sched_param( | 1337 | gk20a_channel_trace_sched_param( |
1302 | trace_gk20a_channel_sched_defaults, ch); | 1338 | trace_gk20a_channel_sched_defaults, ch); |
1303 | 1339 | ||
1304 | filp->private_data = ch; | 1340 | priv->g = g; |
1341 | priv->c = ch; | ||
1342 | |||
1343 | filp->private_data = priv; | ||
1305 | return 0; | 1344 | return 0; |
1345 | |||
1346 | fail_busy: | ||
1347 | kfree(priv); | ||
1348 | return err; | ||
1306 | } | 1349 | } |
1307 | 1350 | ||
1308 | int gk20a_channel_open(struct inode *inode, struct file *filp) | 1351 | int gk20a_channel_open(struct inode *inode, struct file *filp) |
@@ -3421,7 +3464,8 @@ void gk20a_init_channel(struct gpu_ops *gops) | |||
3421 | long gk20a_channel_ioctl(struct file *filp, | 3464 | long gk20a_channel_ioctl(struct file *filp, |
3422 | unsigned int cmd, unsigned long arg) | 3465 | unsigned int cmd, unsigned long arg) |
3423 | { | 3466 | { |
3424 | struct channel_gk20a *ch = filp->private_data; | 3467 | struct channel_priv *priv = filp->private_data; |
3468 | struct channel_gk20a *ch = priv->c; | ||
3425 | struct device *dev = ch->g->dev; | 3469 | struct device *dev = ch->g->dev; |
3426 | u8 buf[NVGPU_IOCTL_CHANNEL_MAX_ARG_SIZE] = {0}; | 3470 | u8 buf[NVGPU_IOCTL_CHANNEL_MAX_ARG_SIZE] = {0}; |
3427 | int err = 0; | 3471 | int err = 0; |
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h index 66052950..0ad1bbaa 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h | |||
@@ -39,6 +39,7 @@ struct gk20a_fence; | |||
39 | #include "fence_gk20a.h" | 39 | #include "fence_gk20a.h" |
40 | 40 | ||
41 | extern const struct file_operations gk20a_event_id_ops; | 41 | extern const struct file_operations gk20a_event_id_ops; |
42 | extern const struct file_operations gk20a_channel_ops; | ||
42 | 43 | ||
43 | struct notification { | 44 | struct notification { |
44 | struct { | 45 | struct { |
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index 086f756b..156d33ed 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c | |||
@@ -168,7 +168,7 @@ static inline void set_gk20a(struct platform_device *pdev, struct gk20a *gk20a) | |||
168 | gk20a_get_platform(&pdev->dev)->g = gk20a; | 168 | gk20a_get_platform(&pdev->dev)->g = gk20a; |
169 | } | 169 | } |
170 | 170 | ||
171 | static const struct file_operations gk20a_channel_ops = { | 171 | const struct file_operations gk20a_channel_ops = { |
172 | .owner = THIS_MODULE, | 172 | .owner = THIS_MODULE, |
173 | .release = gk20a_channel_release, | 173 | .release = gk20a_channel_release, |
174 | .open = gk20a_channel_open, | 174 | .open = gk20a_channel_open, |
@@ -1280,23 +1280,6 @@ fail: | |||
1280 | return err; | 1280 | return err; |
1281 | } | 1281 | } |
1282 | 1282 | ||
1283 | struct channel_gk20a *gk20a_get_channel_from_file(int fd) | ||
1284 | { | ||
1285 | struct channel_gk20a *ch; | ||
1286 | struct file *f = fget(fd); | ||
1287 | if (!f) | ||
1288 | return NULL; | ||
1289 | |||
1290 | if (f->f_op != &gk20a_channel_ops) { | ||
1291 | fput(f); | ||
1292 | return NULL; | ||
1293 | } | ||
1294 | |||
1295 | ch = (struct channel_gk20a *)f->private_data; | ||
1296 | fput(f); | ||
1297 | return ch; | ||
1298 | } | ||
1299 | |||
1300 | static int gk20a_pm_railgate(struct device *dev) | 1283 | static int gk20a_pm_railgate(struct device *dev) |
1301 | { | 1284 | { |
1302 | struct gk20a_platform *platform = dev_get_drvdata(dev); | 1285 | struct gk20a_platform *platform = dev_get_drvdata(dev); |