diff options
| author | Angela Stegmaier <angelabaker@ti.com> | 2010-09-09 11:10:25 -0400 |
|---|---|---|
| committer | Paolo Pisati <paolo.pisati@canonical.com> | 2012-08-17 04:19:08 -0400 |
| commit | 77508e0bdabffccd9106c79b74170a8a4a87f321 (patch) | |
| tree | 1515220d899d78e1f58d20d61ed79564ba6a73c0 /drivers/dsp/syslink/devh/devh.c | |
| parent | 2b09254c67d989214783096b140ff10c6dea0825 (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.c | 273 |
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 | |||
| 40 | static struct class *omap_devh_class; | ||
| 41 | static dev_t omap_devh_dev; | ||
| 42 | static atomic_t num_of_devhs; | ||
| 43 | static struct platform_driver omap_devh_driver; | ||
| 44 | |||
| 45 | static 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 | |||
| 59 | static 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 | |||
| 68 | static 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 | |||
| 117 | static 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 | |||
| 124 | static 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 | |||
| 184 | clean_cdev: | ||
| 185 | cdev_del(&devh->cdev); | ||
| 186 | free_devh: | ||
| 187 | kfree(devh); | ||
| 188 | out: | ||
| 189 | return ret; | ||
| 190 | } | ||
| 191 | |||
| 192 | static 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 | |||
| 218 | static 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 | |||
| 227 | static 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; | ||
| 254 | unreg_region: | ||
| 255 | unregister_chrdev_region(omap_devh_dev, num); | ||
| 256 | out: | ||
| 257 | return ret; | ||
| 258 | } | ||
| 259 | module_init(omap_devh_init); | ||
| 260 | |||
| 261 | static 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 | } | ||
| 269 | module_exit(omap_devh_exit); | ||
| 270 | |||
| 271 | MODULE_LICENSE("GPL v2"); | ||
| 272 | MODULE_DESCRIPTION("OMAP Device Handler driver"); | ||
| 273 | MODULE_AUTHOR("Angela Stegmaier <angelabaker@ti.com>"); | ||
