diff options
author | Alex Waterman <alexw@nvidia.com> | 2016-10-18 18:23:44 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2016-12-19 18:39:58 -0500 |
commit | 28fce3e72bd5231da0e648fb940e04b0ef49ca22 (patch) | |
tree | 7e53a771b6d5d25123c27bd9ba7942d917d10398 /drivers/gpu | |
parent | ca2c4995278f42835d4667cc486172e38e0186d6 (diff) |
gpu: nvgpu: Use struct to hold gk20a pointer
The private_data field in the file pointer passed to release() for
channels originally pointed directly to the referenced channel. The
problem with this is that when the driver is killed and the channel
mmeory is freed that pointer becomes invalid.
The necessity of that channel is to get access to the gk20a struct that
owns the channel. This can instead be accomplished by making a new
private data struct that has a pointer to the gk20a struct directly
instead of requiring the channel to be valid. This lets the release()
function work even if the channels are gone (though in such cases the
release function doesn't do very much).
Change-Id: I5e50bb5b6dd08d38974f8e7b46ba125e9a3f1922
Signed-off-by: Alex Waterman <alexw@nvidia.com>
Reviewed-on: http://git-master/r/1246586
(cherry picked from commit 14b7c380c74d2caeb04c47ad3e33332a423a84bb)
Reviewed-on: http://git-master/r/1261913
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
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); |