aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dsp/syslink/devh/devh.c
diff options
context:
space:
mode:
authorAngela Stegmaier <angelabaker@ti.com>2010-09-09 11:10:25 -0400
committerPaolo Pisati <paolo.pisati@canonical.com>2012-08-17 04:19:08 -0400
commit77508e0bdabffccd9106c79b74170a8a4a87f321 (patch)
tree1515220d899d78e1f58d20d61ed79564ba6a73c0 /drivers/dsp/syslink/devh/devh.c
parent2b09254c67d989214783096b140ff10c6dea0825 (diff)
SYSLINK:devh: adding devh to syslink tree
This patch adds devh to syslink tree Signed-off-by: Angela Stegmaier <angelabaker@ti.com> Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com> SYSLINK: Devh - Add device event handling and SYSERROR support for OMAP4 SYSLINK: Devh - Add event handling and SYSERROR support DSP exceptions that are unrecoverable need to be communicated to the host processor so that it can print debug information, do resource cleanup and ultimately reload DSP. The notification mechanism for sending events to the host processor has been consolidated in a new module named Device Error Handler on the remote processor. The notification mechanism relies on a NotifyShm event to know about error events on the remote cores. The support has been built into the existing Devh module which registers a call back for the previously agreed event id to be used for error events. Upon receving an error event, the module will notify other kernel modules which have registered with it. It will also notify userspace applicatios through an agreed fd event. This support will be built in a following patch. For now, the module uses event id 4 to receive notify messages from remote processor. Enhacements that will follow include using a reserved event for sending notify messages. Initialize the Device Error Handler functionality in Devh. Devh registers a callback for NotifyShm event to be triggered when an error occurs on the remote core. Devh module has the support for receiving notifications from remote cores about irrecoverble errors. Userspace processes need to be notified for such events as well in order to do cleanup and recovery. Besides, such notifications can also be used to output valuable debug information about error scenarios. [Suman A] Corrected err_event_id from 4 to use as err_event_id = (4 | (NOTIFY_SYSTEMKEY << 16)), Change-Id: I961d83e62e5ce21b32f5e2c461644e6f2bd8cb3c Signed-off-by: Wajahat Khan <w-khan@ti.com> Signed-off-by: Hari Kanigeri <h-kangieri2@ti.com> SYSLINK: devh - add possibility of register for specific events New paratemer is added to event register ioctl to allow users register for a specific event. Modified to register notifier for IPU_PM watch-dog timer [Hari K] Added the call to ipc_recover_schedule on sys error and watchdog timer Change-Id: I5fcfc28bc424a47f95c32104d2200ad946ef9027 Signed-off-by: Fernando Guzman Lugo <fernando.lugo@ti.com> Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com> SYSLINK: Devh - Add userspace events unregistration support Implement the unregister ioctl which lets an application unregister an fd it had registered with the module earlier. The call returns successfully even if no matching fd was present or duplicates were present. Also fixed traces because of addition of watch dog event. Change-Id: Idd075c6a96a5c5438e02cfc1efa19d3e3859c0af Signed-off-by: Wajahat Khan <w-khan@ti.com>
Diffstat (limited to 'drivers/dsp/syslink/devh/devh.c')
-rw-r--r--drivers/dsp/syslink/devh/devh.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/drivers/dsp/syslink/devh/devh.c b/drivers/dsp/syslink/devh/devh.c
new file mode 100644
index 00000000000..0e3cabe665f
--- /dev/null
+++ b/drivers/dsp/syslink/devh/devh.c
@@ -0,0 +1,273 @@
1/*
2 * OMAP Device Handler driver
3 *
4 * Copyright (C) 2010 Texas Instruments Inc.
5 *
6 * Written by Angela Stegmaier <angelabaker@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/interrupt.h>
27#include <linux/device.h>
28#include <linux/delay.h>
29#include <linux/file.h>
30#include <linux/poll.h>
31#include <linux/mm.h>
32#include <linux/slab.h>
33#include <linux/platform_device.h>
34
35#include "devh.h"
36
37#define OMAP_DEVH_NAME "omap-devh"
38#define DRV_NAME "omap-devicehandler"
39
40static struct class *omap_devh_class;
41static dev_t omap_devh_dev;
42static atomic_t num_of_devhs;
43static struct platform_driver omap_devh_driver;
44
45static int omap_devh_open(struct inode *inode, struct file *filp)
46{
47 int ret = 0;
48 struct omap_devh *devh;
49
50 devh = container_of(inode->i_cdev, struct omap_devh, cdev);
51 if (!devh->dev)
52 return -EINVAL;
53
54 filp->private_data = devh;
55
56 return ret;
57}
58
59static int omap_devh_release(struct inode *inode, struct file *filp)
60{
61 struct omap_devh *devh = filp->private_data;
62 if (!devh || !devh->dev)
63 return -EINVAL;
64
65 return 0;
66}
67
68static int omap_devh_ioctl(struct inode *inode, struct file *filp,
69 unsigned int cmd, unsigned long arg)
70{
71 int rc = 0;
72 struct omap_devh *devh = filp->private_data;
73 struct omap_devh_platform_data *pdata =
74 (struct omap_devh_platform_data *)devh->dev->platform_data;
75
76 if (!devh)
77 return -EINVAL;
78
79 if (_IOC_TYPE(cmd) != DEVH_IOC_MAGIC)
80 return -ENOTTY;
81 if (_IOC_NR(cmd) > DEVH_IOC_MAXNR)
82 return -ENOTTY;
83 if (_IOC_DIR(cmd) & _IOC_READ) {
84 if (!access_ok(VERIFY_WRITE, (void __user *)arg,
85 _IOC_SIZE(cmd)))
86 return -EFAULT;
87 } else if (_IOC_DIR(cmd) & _IOC_WRITE) {
88 if (!access_ok(VERIFY_READ, (void __user *)arg,
89 _IOC_SIZE(cmd)))
90 return -EFAULT;
91 }
92
93 switch (cmd) {
94
95 /*
96 * this will be updated to support user registering for event
97 * notifications.
98 */
99 case DEVH_IOCWAITONEVENTS:
100 /*rc = omap_devh_wait_on_events(devh);*/
101 break;
102 case DEVH_IOCEVENTREG:
103 rc = pdata->ops->register_event_notification(devh,
104 (const void __user *)arg);
105 break;
106 case DEVH_IOCEVENTUNREG:
107 rc = pdata->ops->unregister_event_notification(devh,
108 (const void __user *)arg);
109 break;
110 default:
111 return -ENOTTY;
112 }
113
114 return rc;
115}
116
117static const struct file_operations omap_devh_fops = {
118 .open = omap_devh_open,
119 .release = omap_devh_release,
120 .ioctl = omap_devh_ioctl,
121 .owner = THIS_MODULE,
122};
123
124static int omap_devh_probe(struct platform_device *pdev)
125{
126 int ret = 0, major, minor;
127 struct device *tmpdev;
128 struct device *dev = &pdev->dev;
129 struct omap_devh_platform_data *pdata = dev->platform_data;
130 struct omap_devh *devh;
131
132 if (!pdata || !pdata->name || !pdata->ops)
133 return -EINVAL;
134
135 dev_info(dev, "%s: adding devh %s\n", __func__, pdata->name);
136
137 devh = kzalloc(sizeof(struct omap_devh), GFP_KERNEL);
138 if (!devh) {
139 dev_err(dev, "%s: kzalloc failed\n", __func__);
140 ret = -ENOMEM;
141 goto out;
142 }
143
144 platform_set_drvdata(pdev, devh);
145 major = MAJOR(omap_devh_dev);
146 minor = atomic_read(&num_of_devhs);
147 atomic_inc(&num_of_devhs);
148
149 devh->dev = dev;
150 devh->minor = minor;
151 devh->name = pdata->name;
152
153 cdev_init(&devh->cdev, &omap_devh_fops);
154 devh->cdev.owner = THIS_MODULE;
155 ret = cdev_add(&devh->cdev, MKDEV(major, minor), 1);
156 if (ret) {
157 dev_err(dev, "%s: cdev_add failed: %d\n", __func__, ret);
158 goto free_devh;
159 }
160
161 tmpdev = device_create(omap_devh_class, NULL,
162 MKDEV(major, minor),
163 NULL,
164 OMAP_DEVH_NAME "%d", minor);
165 if (IS_ERR(tmpdev)) {
166 ret = PTR_ERR(tmpdev);
167 pr_err("%s: device_create failed: %d\n", __func__, ret);
168 goto clean_cdev;
169 }
170
171 pr_info("%s initialized %s, major: %d, base-minor: %d\n",
172 OMAP_DEVH_NAME,
173 pdata->name,
174 MAJOR(omap_devh_dev),
175 minor);
176
177 INIT_LIST_HEAD(&(devh->event_list));
178 spin_lock_init(&(devh->event_lock));
179 if (pdata->ops->register_notifiers)
180 pdata->ops->register_notifiers(devh);
181
182 return 0;
183
184clean_cdev:
185 cdev_del(&devh->cdev);
186free_devh:
187 kfree(devh);
188out:
189 return ret;
190}
191
192static int omap_devh_remove(struct platform_device *pdev)
193{
194 int major = MAJOR(omap_devh_dev);
195 struct device *dev = &pdev->dev;
196 struct omap_devh_platform_data *pdata = dev->platform_data;
197 struct omap_devh *devh = platform_get_drvdata(pdev);
198
199 if (!pdata || !devh)
200 return -EINVAL;
201
202 if (pdata->ops->unregister_notifiers)
203 pdata->ops->unregister_notifiers(devh);
204
205 dev_info(dev, "%s removing %s, major: %d, base-minor: %d\n",
206 OMAP_DEVH_NAME,
207 pdata->name,
208 major,
209 devh->minor);
210
211 device_destroy(omap_devh_class, MKDEV(major, devh->minor));
212 cdev_del(&devh->cdev);
213 kfree(devh);
214
215 return 0;
216}
217
218static struct platform_driver omap_devh_driver = {
219 .probe = omap_devh_probe,
220 .remove = omap_devh_remove,
221 .driver = {
222 .name = DRV_NAME,
223 .owner = THIS_MODULE,
224 },
225};
226
227static int __init omap_devh_init(void)
228{
229 int num = devh_get_plat_data_size();
230 int ret;
231
232 ret = alloc_chrdev_region(&omap_devh_dev, 0, num, OMAP_DEVH_NAME);
233 if (ret) {
234 pr_err("%s: alloc_chrdev_region failed: %d\n", __func__, ret);
235 goto out;
236 }
237
238 omap_devh_class = class_create(THIS_MODULE, OMAP_DEVH_NAME);
239 if (IS_ERR(omap_devh_class)) {
240 ret = PTR_ERR(omap_devh_class);
241 pr_err("%s: class_create failed: %d\n", __func__, ret);
242 goto unreg_region;
243 }
244
245 atomic_set(&num_of_devhs, 0);
246
247 ret = platform_driver_register(&omap_devh_driver);
248 if (ret) {
249 pr_err("%s: platform_driver_register failed: %d\n",
250 __func__, ret);
251 goto out;
252 }
253 return 0;
254unreg_region:
255 unregister_chrdev_region(omap_devh_dev, num);
256out:
257 return ret;
258}
259module_init(omap_devh_init);
260
261static void __exit omap_devh_exit(void)
262{
263 int num = devh_get_plat_data_size();
264 pr_info("%s\n", __func__);
265 platform_driver_unregister(&omap_devh_driver);
266 class_destroy(omap_devh_class);
267 unregister_chrdev_region(omap_devh_dev, num);
268}
269module_exit(omap_devh_exit);
270
271MODULE_LICENSE("GPL v2");
272MODULE_DESCRIPTION("OMAP Device Handler driver");
273MODULE_AUTHOR("Angela Stegmaier <angelabaker@ti.com>");