gpu: pvr: Disable driver if SGX HW recovery fails
[sgx.git] / pvr / module.c
1 /**********************************************************************
2  *
3  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful but, except
10  * as otherwise stated in writing, without any warranty; without even the
11  * implied warranty of merchantability or fitness for a particular purpose.
12  * See the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
24  *
25  ******************************************************************************/
26
27 #include <linux/init.h>
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/version.h>
31 #include <linux/fs.h>
32 #include <linux/proc_fs.h>
33 #include <linux/miscdevice.h>
34
35 #include <linux/platform_device.h>
36
37 #include "img_defs.h"
38 #include "services.h"
39 #include "kerneldisplay.h"
40 #include "kernelbuffer.h"
41 #include "syscommon.h"
42 #include "pvrmmap.h"
43 #include "mutils.h"
44 #include "mm.h"
45 #include "mmap.h"
46 #include "pvr_debug.h"
47 #include "srvkm.h"
48 #include "perproc.h"
49 #include "handle.h"
50 #include "pvr_bridge_km.h"
51 #include "sgx_bridge_km.h"
52 #include "proc.h"
53 #include "pvrmodule.h"
54 #include "private_data.h"
55 #include "pvr_events.h"
56
57 #define DRVNAME         "pvrsrvkm"
58
59 #ifdef CONFIG_PVR_DEBUG_EXTRA
60 static int debug = DBGPRIV_WARNING;
61 #include <linux/moduleparam.h>
62 module_param(debug, int, 0);
63 #endif
64
65 static int pvr_open(struct inode unref__ * inode, struct file *filp)
66 {
67         struct PVRSRV_FILE_PRIVATE_DATA *priv;
68         void *block_alloc;
69         int ret = -ENOMEM;
70         enum PVRSRV_ERROR err;
71         u32 pid;
72
73         pvr_lock();
74
75         if (pvr_is_disabled()) {
76                 ret = -ENODEV;
77                 goto err_unlock;
78         }
79
80         pid = OSGetCurrentProcessIDKM();
81
82         if (PVRSRVProcessConnect(pid) != PVRSRV_OK)
83                 goto err_unlock;
84
85         err = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
86                             sizeof(*priv),
87                             (void **)&priv, &block_alloc);
88
89         if (err != PVRSRV_OK)
90                 goto err_unlock;
91
92         priv->ui32OpenPID = pid;
93         priv->hBlockAlloc = block_alloc;
94         filp->private_data = priv;
95
96         INIT_LIST_HEAD(&priv->event_list);
97         init_waitqueue_head(&priv->event_wait);
98         priv->event_space = 4096; /* set aside 4k for event buffer */
99
100         ret = 0;
101 err_unlock:
102         pvr_unlock();
103
104         return ret;
105 }
106
107 static int pvr_release(struct inode unref__ * inode, struct file *filp)
108 {
109         struct PVRSRV_FILE_PRIVATE_DATA *priv;
110
111         pvr_lock();
112
113         priv = filp->private_data;
114
115         pvr_release_events(priv);
116
117         PVRSRVProcessDisconnect(priv->ui32OpenPID);
118
119         OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
120                   sizeof(*priv),
121                   priv, priv->hBlockAlloc);
122
123         pvr_unlock();
124
125         return 0;
126 }
127
128 static const struct file_operations pvr_fops = {
129         .owner          = THIS_MODULE,
130         .unlocked_ioctl = PVRSRV_BridgeDispatchKM,
131         .open           = pvr_open,
132         .release        = pvr_release,
133         .mmap           = PVRMMap,
134         .poll           = pvr_poll,
135         .read           = pvr_read,
136 };
137
138 static void pvr_shutdown(struct platform_device *pdev)
139 {
140         PVR_TRACE("pvr_shutdown(pdev=%p)", pdev);
141
142         (void)PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3);
143 }
144
145 static int pvr_suspend(struct platform_device *pdev, pm_message_t state)
146 {
147         PVR_TRACE("pvr_suspend(pdev=%p)", pdev);
148
149         if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3) != PVRSRV_OK)
150                 return -EINVAL;
151         return 0;
152 }
153
154 static int pvr_resume(struct platform_device *pdev)
155 {
156         PVR_TRACE("pvr_resume(pdev=%p)", pdev);
157
158         if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) != PVRSRV_OK)
159                 return -EINVAL;
160         return 0;
161 }
162
163 static struct miscdevice pvr_miscdevice = {
164         .minor = MISC_DYNAMIC_MINOR,
165         .name = DRVNAME,
166         .fops = &pvr_fops,
167 };
168
169 static int __devinit pvr_probe(struct platform_device *pdev)
170 {
171         struct SYS_DATA *sysdata;
172         int ret;
173
174         PVR_TRACE("pvr_probe(pdev=%p)", pdev);
175
176         if (SysAcquireData(&sysdata) != PVRSRV_OK &&
177             SysInitialise(pdev) != PVRSRV_OK) {
178                 ret = -ENODEV;
179                 goto err_exit;
180         }
181
182         ret = misc_register(&pvr_miscdevice);
183         if (ret < 0)
184                 goto err_exit;
185
186         return 0;
187
188 err_exit:
189         dev_err(&pdev->dev, "probe failed (%d)\n", ret);
190
191         return ret;
192 }
193
194 static int __devexit pvr_remove(struct platform_device *pdev)
195 {
196         struct SYS_DATA *sysdata;
197         int ret;
198
199         PVR_TRACE("pvr_remove(pdev=%p)", pdev);
200
201         ret = misc_deregister(&pvr_miscdevice);
202         if (ret < 0) {
203                 dev_err(&pdev->dev, "remove failed (%d)\n", ret);
204                 return ret;
205         }
206
207         if (SysAcquireData(&sysdata) == PVRSRV_OK)
208                 SysDeinitialise(sysdata);
209
210         return 0;
211 }
212
213
214 static struct platform_driver pvr_driver = {
215         .driver = {
216                    .name = DRVNAME,
217         },
218         .probe          = pvr_probe,
219         .remove         = __devexit_p(pvr_remove),
220         .suspend        = pvr_suspend,
221         .resume         = pvr_resume,
222         .shutdown       = pvr_shutdown,
223 };
224
225 static int __init pvr_init(void)
226 {
227         int error;
228
229         pvr_dbg_init();
230
231         PVR_TRACE("pvr_init");
232
233 #ifdef CONFIG_PVR_DEBUG_EXTRA
234         PVRDebugSetLevel(debug);
235 #endif
236
237         error = CreateProcEntries();
238         if (error < 0)
239                 goto err1;
240
241         error = -ENOMEM;
242         if (LinuxMMInit() != PVRSRV_OK)
243                 goto err2;
244
245         if (LinuxBridgeInit() != PVRSRV_OK)
246                 goto err3;
247
248         PVRMMapInit();
249
250         error = platform_driver_register(&pvr_driver);
251         if (error < 0)
252                 goto err4;
253
254         pvr_init_events();
255
256         return 0;
257
258 err4:
259         PVRMMapCleanup();
260         LinuxBridgeDeInit();
261 err3:
262         LinuxMMCleanup();
263 err2:
264         RemoveProcEntries();
265 err1:
266         pr_err("%s: failed (%d)\n", __func__, error);
267
268         return error;
269 }
270
271 static void __exit pvr_cleanup(void)
272 {
273         struct SYS_DATA *sysdata;
274
275         PVR_TRACE("pvr_cleanup");
276
277         SysAcquireData(&sysdata);
278
279         platform_driver_unregister(&pvr_driver);
280
281         PVRMMapCleanup();
282         LinuxMMCleanup();
283         LinuxBridgeDeInit();
284         RemoveProcEntries();
285
286         PVR_TRACE("pvr_cleanup: unloading");
287
288         pvr_dbg_cleanup();
289 }
290
291 module_init(pvr_init);
292 module_exit(pvr_cleanup);
293
294 MODULE_SUPPORTED_DEVICE(DRVNAME);
295 MODULE_ALIAS("platform:" DRVNAME);
296