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 | |
| 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')
| -rw-r--r-- | drivers/dsp/syslink/devh/44xx/Kbuild | 7 | ||||
| -rw-r--r-- | drivers/dsp/syslink/devh/44xx/devh44xx.c | 956 | ||||
| -rw-r--r-- | drivers/dsp/syslink/devh/Kbuild | 7 | ||||
| -rw-r--r-- | drivers/dsp/syslink/devh/devh.c | 273 | ||||
| -rw-r--r-- | drivers/dsp/syslink/devh/devh.h | 87 |
5 files changed, 1330 insertions, 0 deletions
diff --git a/drivers/dsp/syslink/devh/44xx/Kbuild b/drivers/dsp/syslink/devh/44xx/Kbuild new file mode 100644 index 00000000000..1cc02051301 --- /dev/null +++ b/drivers/dsp/syslink/devh/44xx/Kbuild | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | |||
| 2 | obj-$(CONFIG_OMAP_DEVICE_HANDLER) += devh44xx.o | ||
| 3 | |||
| 4 | ccflags-y += -Wno-strict-prototypes | ||
| 5 | |||
| 6 | #Header files | ||
| 7 | ccflags-y += -Iarch/arm/plat-omap/include/syslink | ||
diff --git a/drivers/dsp/syslink/devh/44xx/devh44xx.c b/drivers/dsp/syslink/devh/44xx/devh44xx.c new file mode 100644 index 00000000000..f76f8922c8b --- /dev/null +++ b/drivers/dsp/syslink/devh/44xx/devh44xx.c | |||
| @@ -0,0 +1,956 @@ | |||
| 1 | /* | ||
| 2 | * Device Handler machine-specific module for OMAP4 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Texas Instruments Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * version 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301 USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/delay.h> | ||
| 23 | #include <linux/clk.h> | ||
| 24 | #include <linux/err.h> | ||
| 25 | #include <linux/platform_device.h> | ||
| 26 | #include <linux/io.h> | ||
| 27 | #include <linux/pm_runtime.h> | ||
| 28 | #include <linux/sched.h> | ||
| 29 | #include <linux/eventfd.h> | ||
| 30 | #include <mach/irqs.h> | ||
| 31 | #include <plat/omap_device.h> | ||
| 32 | #include <plat/iommu.h> | ||
| 33 | #include <plat/remoteproc.h> | ||
| 34 | #include <linux/slab.h> | ||
| 35 | #include <linux/pagemap.h> | ||
| 36 | #if defined(CONFIG_TILER_OMAP) | ||
| 37 | #include <mach/tiler.h> | ||
| 38 | #endif | ||
| 39 | |||
| 40 | #include <syslink/ipc.h> | ||
| 41 | |||
| 42 | #include "../devh.h" | ||
| 43 | #include "../../ipu_pm/ipu_pm.h" | ||
| 44 | |||
| 45 | static struct mutex local_gate; | ||
| 46 | |||
| 47 | struct omap_devh_runtime_info { | ||
| 48 | int brd_state; | ||
| 49 | struct iommu *iommu; | ||
| 50 | struct omap_rproc *rproc; | ||
| 51 | }; | ||
| 52 | |||
| 53 | enum { | ||
| 54 | DEVH_BRDST_RUNNING, | ||
| 55 | DEVH_BRDST_STOPPED, | ||
| 56 | DEVH_BRDST_ERROR, | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct deh_event_ntfy { | ||
| 60 | u32 fd; | ||
| 61 | u32 event; | ||
| 62 | struct eventfd_ctx *evt_ctx; | ||
| 63 | struct list_head list; | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct omap_devh *devh_get_obj(int dev_index); | ||
| 67 | |||
| 68 | static struct omap_devh_platform_data *devh_get_plat_data_by_name(char *name) | ||
| 69 | { | ||
| 70 | int i, j = devh_get_plat_data_size(); | ||
| 71 | struct omap_devh_platform_data *pdata = devh_get_plat_data(); | ||
| 72 | |||
| 73 | if (name) { | ||
| 74 | for (i = 0; i < j; i++) { | ||
| 75 | if (!(strcmp(name, pdata[i].name))) | ||
| 76 | return &pdata[i]; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | return NULL; | ||
| 80 | } | ||
| 81 | |||
| 82 | static int devh_notify_event(struct omap_devh *devh , u32 event) | ||
| 83 | { | ||
| 84 | struct deh_event_ntfy *fd_reg; | ||
| 85 | |||
| 86 | spin_lock_irq(&(devh->event_lock)); | ||
| 87 | list_for_each_entry(fd_reg, &(devh->event_list), list) | ||
| 88 | if (fd_reg->event == event) | ||
| 89 | eventfd_signal(fd_reg->evt_ctx, 1); | ||
| 90 | spin_unlock_irq(&(devh->event_lock)); | ||
| 91 | |||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | static void devh_notification_handler(u16 proc_id, u16 line_id, u32 event_id, | ||
| 96 | uint *arg, u32 payload) | ||
| 97 | { | ||
| 98 | pr_warning("Sys Error occured in Ducati for proc_id = %d\n", | ||
| 99 | proc_id); | ||
| 100 | |||
| 101 | /* schedule the recovery */ | ||
| 102 | ipc_recover_schedule(); | ||
| 103 | |||
| 104 | devh_notify_event((struct omap_devh *)arg, DEV_SYS_ERROR); | ||
| 105 | } | ||
| 106 | |||
| 107 | static int devh44xx_notifier_call(struct notifier_block *nb, | ||
| 108 | unsigned long val, void *v, | ||
| 109 | struct omap_devh_platform_data *pdata) | ||
| 110 | { | ||
| 111 | int err = 0; | ||
| 112 | pid_t my_pid = current->tgid; | ||
| 113 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 114 | struct omap_devh_platform_data *pdata2 = NULL; | ||
| 115 | |||
| 116 | if (pdata) | ||
| 117 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 118 | else | ||
| 119 | return -EINVAL; | ||
| 120 | |||
| 121 | if (pinfo->brd_state == DEVH_BRDST_RUNNING) { | ||
| 122 | err = mutex_lock_interruptible(&local_gate); | ||
| 123 | if (err) | ||
| 124 | goto exit; | ||
| 125 | err = ipu_pm_notifications(PM_PID_DEATH, (void *)my_pid); | ||
| 126 | if (err) { | ||
| 127 | pinfo->brd_state = DEVH_BRDST_ERROR; | ||
| 128 | if (!strcmp(pdata->name, "SysM3")) { | ||
| 129 | pdata2 = devh_get_plat_data_by_name("AppM3"); | ||
| 130 | if (pdata2) { | ||
| 131 | pinfo = | ||
| 132 | (struct omap_devh_runtime_info *) | ||
| 133 | pdata2->private_data; | ||
| 134 | pinfo->brd_state = DEVH_BRDST_ERROR; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | } | ||
| 138 | mutex_unlock(&local_gate); | ||
| 139 | } | ||
| 140 | |||
| 141 | exit: | ||
| 142 | return err; | ||
| 143 | } | ||
| 144 | |||
| 145 | static int devh44xx_sysm3_iommu_notifier_call(struct notifier_block *nb, | ||
| 146 | unsigned long val, void *v) | ||
| 147 | { | ||
| 148 | struct omap_devh_platform_data *pdata = | ||
| 149 | devh_get_plat_data_by_name("SysM3"); | ||
| 150 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 151 | |||
| 152 | if (!pdata) | ||
| 153 | return 0; | ||
| 154 | |||
| 155 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 156 | |||
| 157 | switch ((int)val) { | ||
| 158 | case IOMMU_CLOSE: | ||
| 159 | return devh44xx_notifier_call(nb, val, v, pdata); | ||
| 160 | case IOMMU_FAULT: | ||
| 161 | pinfo->brd_state = DEVH_BRDST_ERROR; | ||
| 162 | return 0; | ||
| 163 | default: | ||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | static int devh44xx_appm3_iommu_notifier_call(struct notifier_block *nb, | ||
| 169 | unsigned long val, void *v) | ||
| 170 | { | ||
| 171 | struct omap_devh_platform_data *pdata = | ||
| 172 | devh_get_plat_data_by_name("AppM3"); | ||
| 173 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 174 | |||
| 175 | if (!pdata) | ||
| 176 | return 0; | ||
| 177 | |||
| 178 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 179 | |||
| 180 | switch ((int)val) { | ||
| 181 | case IOMMU_CLOSE: | ||
| 182 | return devh44xx_notifier_call(nb, val, v, pdata); | ||
| 183 | case IOMMU_FAULT: | ||
| 184 | pinfo->brd_state = DEVH_BRDST_ERROR; | ||
| 185 | return 0; | ||
| 186 | default: | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | static int devh44xx_tesla_iommu_notifier_call(struct notifier_block *nb, | ||
| 192 | unsigned long val, void *v) | ||
| 193 | { | ||
| 194 | struct omap_devh_platform_data *pdata = | ||
| 195 | devh_get_plat_data_by_name("Tesla"); | ||
| 196 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 197 | |||
| 198 | if (!pdata) | ||
| 199 | return 0; | ||
| 200 | |||
| 201 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 202 | |||
| 203 | switch ((int)val) { | ||
| 204 | case IOMMU_CLOSE: | ||
| 205 | return devh44xx_notifier_call(nb, val, v, pdata); | ||
| 206 | case IOMMU_FAULT: | ||
| 207 | pinfo->brd_state = DEVH_BRDST_ERROR; | ||
| 208 | return 0; | ||
| 209 | default: | ||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | static struct notifier_block devh_notify_nb_iommu_tesla = { | ||
| 215 | .notifier_call = devh44xx_tesla_iommu_notifier_call, | ||
| 216 | }; | ||
| 217 | static struct notifier_block devh_notify_nb_iommu_ducati0 = { | ||
| 218 | .notifier_call = devh44xx_sysm3_iommu_notifier_call, | ||
| 219 | }; | ||
| 220 | static struct notifier_block devh_notify_nb_iommu_ducati1 = { | ||
| 221 | .notifier_call = devh44xx_appm3_iommu_notifier_call, | ||
| 222 | }; | ||
| 223 | |||
| 224 | static int devh44xx_wdt_ipc_notifier_call(struct notifier_block *nb, | ||
| 225 | unsigned long val, void *v) | ||
| 226 | { | ||
| 227 | struct omap_devh *obj; | ||
| 228 | int i = devh_get_plat_data_size(); | ||
| 229 | |||
| 230 | pr_warning("Ducati Watch Dog fired\n"); | ||
| 231 | |||
| 232 | /* schedule the recovery */ | ||
| 233 | ipc_recover_schedule(); | ||
| 234 | |||
| 235 | while (i--) { | ||
| 236 | obj = devh_get_obj(i); | ||
| 237 | devh_notify_event(obj, DEV_WATCHDOG_ERROR); | ||
| 238 | } | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static struct notifier_block devh_notify_nb_ipc_wdt = { | ||
| 244 | .notifier_call = devh44xx_wdt_ipc_notifier_call, | ||
| 245 | }; | ||
| 246 | |||
| 247 | static int devh44xx_sysm3_ipc_notifier_call(struct notifier_block *nb, | ||
| 248 | unsigned long val, void *v) | ||
| 249 | { | ||
| 250 | struct omap_devh_platform_data *pdata = | ||
| 251 | devh_get_plat_data_by_name("SysM3"); | ||
| 252 | u16 *proc_id = (u16 *)v; | ||
| 253 | struct omap_devh *obj; | ||
| 254 | int status; | ||
| 255 | |||
| 256 | switch ((int)val) { | ||
| 257 | case IPC_CLOSE: | ||
| 258 | return devh44xx_notifier_call(nb, val, v, pdata); | ||
| 259 | case IPC_START: | ||
| 260 | /* | ||
| 261 | * TODO - hack hack - clean this up to use a define proc id | ||
| 262 | * and use this to get the devh object | ||
| 263 | */ | ||
| 264 | if (*proc_id == multiproc_get_id("SysM3")) { | ||
| 265 | obj = devh_get_obj(1); | ||
| 266 | if (WARN_ON(obj == NULL)) { | ||
| 267 | status = -1; | ||
| 268 | pr_err("devh_44xx_notifier_call: cannot grab " | ||
| 269 | "device devh1 instance\n"); | ||
| 270 | } else { | ||
| 271 | status = notify_register_event(pdata->proc_id, | ||
| 272 | pdata->line_id, | ||
| 273 | pdata->err_event_id, | ||
| 274 | (notify_fn_notify_cbck) \ | ||
| 275 | devh_notification_handler, | ||
| 276 | (void *)obj); | ||
| 277 | } | ||
| 278 | if (status == 0) | ||
| 279 | status = ipu_pm_register_notifier( | ||
| 280 | &devh_notify_nb_ipc_wdt); | ||
| 281 | } else { | ||
| 282 | status = 0; | ||
| 283 | } | ||
| 284 | return status; | ||
| 285 | case IPC_STOP: | ||
| 286 | if (*proc_id == multiproc_get_id("SysM3")) { | ||
| 287 | ipu_pm_unregister_notifier(&devh_notify_nb_ipc_wdt); | ||
| 288 | obj = devh_get_obj(1); | ||
| 289 | if (WARN_ON(obj == NULL)) { | ||
| 290 | status = -1; | ||
| 291 | pr_err("devh_44xx_notifier_call: cannot grab " | ||
| 292 | "device devh1 instance\n"); | ||
| 293 | } else { | ||
| 294 | status = notify_unregister_event(pdata->proc_id, | ||
| 295 | pdata->line_id, | ||
| 296 | pdata->err_event_id, | ||
| 297 | (notify_fn_notify_cbck) \ | ||
| 298 | devh_notification_handler, | ||
| 299 | (void *)obj); | ||
| 300 | } | ||
| 301 | } else { | ||
| 302 | status = 0; | ||
| 303 | } | ||
| 304 | return status; | ||
| 305 | default: | ||
| 306 | return 0; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | static int devh44xx_appm3_ipc_notifier_call(struct notifier_block *nb, | ||
| 311 | unsigned long val, void *v) | ||
| 312 | { | ||
| 313 | struct omap_devh_platform_data *pdata = | ||
| 314 | devh_get_plat_data_by_name("AppM3"); | ||
| 315 | struct omap_devh *obj; | ||
| 316 | |||
| 317 | u16* proc_id = (u16 *)v; | ||
| 318 | int status; | ||
| 319 | switch ((int)val) { | ||
| 320 | case IPC_CLOSE: | ||
| 321 | return devh44xx_notifier_call(nb, val, v, pdata); | ||
| 322 | case IPC_START: | ||
| 323 | /* | ||
| 324 | * TODO - hack hack - clean this up to use a define proc id | ||
| 325 | * and use this to get the devh object | ||
| 326 | */ | ||
| 327 | if (*proc_id == multiproc_get_id("AppM3")) { | ||
| 328 | obj = devh_get_obj(2); | ||
| 329 | if (WARN_ON(obj == NULL)) { | ||
| 330 | status = -1; | ||
| 331 | pr_err("devh_44xx_notifier_call: cannot grab " | ||
| 332 | "device devh2 instance\n"); | ||
| 333 | } else { | ||
| 334 | status = notify_register_event(pdata->proc_id, | ||
| 335 | pdata->line_id, | ||
| 336 | pdata->err_event_id, | ||
| 337 | (notify_fn_notify_cbck) \ | ||
| 338 | devh_notification_handler, | ||
| 339 | (void *)obj); | ||
| 340 | } | ||
| 341 | } else { | ||
| 342 | status = 0; | ||
| 343 | } | ||
| 344 | return status; | ||
| 345 | case IPC_STOP: | ||
| 346 | if (*proc_id == multiproc_get_id("AppM3")) { | ||
| 347 | obj = devh_get_obj(2); | ||
| 348 | if (WARN_ON(obj == NULL)) { | ||
| 349 | status = -1; | ||
| 350 | pr_err("devh_44xx_notifier_call: cannot grab " | ||
| 351 | "device devh2 instance\n"); | ||
| 352 | } else { | ||
| 353 | status = notify_unregister_event(pdata->proc_id, | ||
| 354 | pdata->line_id, | ||
| 355 | pdata->err_event_id, | ||
| 356 | (notify_fn_notify_cbck) \ | ||
| 357 | devh_notification_handler, | ||
| 358 | (void *)obj); | ||
| 359 | } | ||
| 360 | } else { | ||
| 361 | status = 0; | ||
| 362 | } | ||
| 363 | return status; | ||
| 364 | default: | ||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 369 | static int devh44xx_tesla_ipc_notifier_call(struct notifier_block *nb, | ||
| 370 | unsigned long val, void *v) | ||
| 371 | { | ||
| 372 | struct omap_devh_platform_data *pdata = | ||
| 373 | devh_get_plat_data_by_name("Tesla"); | ||
| 374 | |||
| 375 | switch ((int)val) { | ||
| 376 | case IPC_CLOSE: | ||
| 377 | return devh44xx_notifier_call(nb, val, v, pdata); | ||
| 378 | default: | ||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | static struct notifier_block devh_notify_nb_ipc_tesla = { | ||
| 384 | .notifier_call = devh44xx_tesla_ipc_notifier_call, | ||
| 385 | }; | ||
| 386 | static struct notifier_block devh_notify_nb_ipc_ducati1 = { | ||
| 387 | .notifier_call = devh44xx_appm3_ipc_notifier_call, | ||
| 388 | }; | ||
| 389 | static struct notifier_block devh_notify_nb_ipc_ducati0 = { | ||
| 390 | .notifier_call = devh44xx_sysm3_ipc_notifier_call, | ||
| 391 | }; | ||
| 392 | |||
| 393 | static int devh44xx_sysm3_rproc_notifier_call(struct notifier_block *nb, | ||
| 394 | unsigned long val, void *v) | ||
| 395 | { | ||
| 396 | struct omap_devh_platform_data *pdata = | ||
| 397 | devh_get_plat_data_by_name("SysM3"); | ||
| 398 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 399 | |||
| 400 | if (pdata) | ||
| 401 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 402 | else | ||
| 403 | return -EINVAL; | ||
| 404 | |||
| 405 | switch ((int)val) { | ||
| 406 | case OMAP_RPROC_START: | ||
| 407 | pinfo->brd_state = DEVH_BRDST_RUNNING; | ||
| 408 | pinfo->iommu = iommu_get("ducati"); | ||
| 409 | if (pinfo->iommu != ERR_PTR(-ENODEV) && | ||
| 410 | pinfo->iommu != ERR_PTR(-EINVAL)) | ||
| 411 | iommu_register_notifier(pinfo->iommu, | ||
| 412 | &devh_notify_nb_iommu_ducati0); | ||
| 413 | else | ||
| 414 | pinfo->iommu = NULL; | ||
| 415 | return 0; | ||
| 416 | case OMAP_RPROC_STOP: | ||
| 417 | pinfo->brd_state = DEVH_BRDST_STOPPED; | ||
| 418 | if (pinfo->iommu != NULL) { | ||
| 419 | iommu_unregister_notifier(pinfo->iommu, | ||
| 420 | &devh_notify_nb_iommu_ducati0); | ||
| 421 | iommu_put(pinfo->iommu); | ||
| 422 | pinfo->iommu = NULL; | ||
| 423 | } | ||
| 424 | return 0; | ||
| 425 | default: | ||
| 426 | return 0; | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | static int devh44xx_appm3_rproc_notifier_call(struct notifier_block *nb, | ||
| 431 | unsigned long val, void *v) | ||
| 432 | { | ||
| 433 | struct omap_devh_platform_data *pdata = | ||
| 434 | devh_get_plat_data_by_name("AppM3"); | ||
| 435 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 436 | |||
| 437 | if (pdata) | ||
| 438 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 439 | else | ||
| 440 | return -EINVAL; | ||
| 441 | |||
| 442 | switch ((int)val) { | ||
| 443 | case OMAP_RPROC_START: | ||
| 444 | pinfo->brd_state = DEVH_BRDST_RUNNING; | ||
| 445 | pinfo->iommu = iommu_get("ducati"); | ||
| 446 | if (pinfo->iommu != ERR_PTR(-ENODEV) && | ||
| 447 | pinfo->iommu != ERR_PTR(-EINVAL)) | ||
| 448 | iommu_register_notifier(pinfo->iommu, | ||
| 449 | &devh_notify_nb_iommu_ducati1); | ||
| 450 | else | ||
| 451 | pinfo->iommu = NULL; | ||
| 452 | return 0; | ||
| 453 | case OMAP_RPROC_STOP: | ||
| 454 | pinfo->brd_state = DEVH_BRDST_STOPPED; | ||
| 455 | if (pinfo->iommu != NULL) { | ||
| 456 | iommu_unregister_notifier(pinfo->iommu, | ||
| 457 | &devh_notify_nb_iommu_ducati1); | ||
| 458 | iommu_put(pinfo->iommu); | ||
| 459 | pinfo->iommu = NULL; | ||
| 460 | } | ||
| 461 | return 0; | ||
| 462 | default: | ||
| 463 | return 0; | ||
| 464 | } | ||
| 465 | } | ||
| 466 | |||
| 467 | static int devh44xx_tesla_rproc_notifier_call(struct notifier_block *nb, | ||
| 468 | unsigned long val, void *v) | ||
| 469 | { | ||
| 470 | struct omap_devh_platform_data *pdata = | ||
| 471 | devh_get_plat_data_by_name("Tesla"); | ||
| 472 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 473 | |||
| 474 | if (pdata) | ||
| 475 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 476 | else | ||
| 477 | return -EINVAL; | ||
| 478 | |||
| 479 | switch ((int)val) { | ||
| 480 | case OMAP_RPROC_START: | ||
| 481 | pinfo->brd_state = DEVH_BRDST_RUNNING; | ||
| 482 | pinfo->iommu = iommu_get("tesla"); | ||
| 483 | if (pinfo->iommu != ERR_PTR(-ENODEV) && | ||
| 484 | pinfo->iommu != ERR_PTR(-EINVAL)) | ||
| 485 | iommu_register_notifier(pinfo->iommu, | ||
| 486 | &devh_notify_nb_iommu_tesla); | ||
| 487 | else | ||
| 488 | pinfo->iommu = NULL; | ||
| 489 | return 0; | ||
| 490 | case OMAP_RPROC_STOP: | ||
| 491 | pinfo->brd_state = DEVH_BRDST_STOPPED; | ||
| 492 | if (pinfo->iommu != NULL) { | ||
| 493 | iommu_unregister_notifier(pinfo->iommu, | ||
| 494 | &devh_notify_nb_iommu_tesla); | ||
| 495 | iommu_put(pinfo->iommu); | ||
| 496 | pinfo->iommu = NULL; | ||
| 497 | } | ||
| 498 | return 0; | ||
| 499 | default: | ||
| 500 | return 0; | ||
| 501 | } | ||
| 502 | } | ||
| 503 | |||
| 504 | static struct notifier_block devh_notify_nb_rproc_tesla = { | ||
| 505 | .notifier_call = devh44xx_tesla_rproc_notifier_call, | ||
| 506 | }; | ||
| 507 | static struct notifier_block devh_notify_nb_rproc_ducati0 = { | ||
| 508 | .notifier_call = devh44xx_sysm3_rproc_notifier_call, | ||
| 509 | }; | ||
| 510 | static struct notifier_block devh_notify_nb_rproc_ducati1 = { | ||
| 511 | .notifier_call = devh44xx_appm3_rproc_notifier_call, | ||
| 512 | }; | ||
| 513 | |||
| 514 | #if defined(CONFIG_TILER_OMAP) | ||
| 515 | static int devh44xx_sysm3_tiler_notifier_call(struct notifier_block *nb, | ||
| 516 | unsigned long val, void *v) | ||
| 517 | { | ||
| 518 | struct omap_devh_platform_data *pdata = | ||
| 519 | devh_get_plat_data_by_name("SysM3"); | ||
| 520 | |||
| 521 | switch ((int)val) { | ||
| 522 | case TILER_DEVICE_CLOSE: | ||
| 523 | return devh44xx_notifier_call(nb, val, v, pdata); | ||
| 524 | default: | ||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | } | ||
| 528 | |||
| 529 | static int devh44xx_appm3_tiler_notifier_call(struct notifier_block *nb, | ||
| 530 | unsigned long val, void *v) | ||
| 531 | { | ||
| 532 | struct omap_devh_platform_data *pdata = | ||
| 533 | devh_get_plat_data_by_name("AppM3"); | ||
| 534 | |||
| 535 | switch ((int)val) { | ||
| 536 | case TILER_DEVICE_CLOSE: | ||
| 537 | return devh44xx_notifier_call(nb, val, v, pdata); | ||
| 538 | default: | ||
| 539 | return 0; | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | static int devh44xx_tesla_tiler_notifier_call(struct notifier_block *nb, | ||
| 544 | unsigned long val, void *v) | ||
| 545 | { | ||
| 546 | struct omap_devh_platform_data *pdata = | ||
| 547 | devh_get_plat_data_by_name("Tesla"); | ||
| 548 | |||
| 549 | switch ((int)val) { | ||
| 550 | case TILER_DEVICE_CLOSE: | ||
| 551 | return devh44xx_notifier_call(nb, val, v, pdata); | ||
| 552 | default: | ||
| 553 | return 0; | ||
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 | static struct notifier_block devh_notify_nb_tiler_tesla = { | ||
| 558 | .notifier_call = devh44xx_tesla_tiler_notifier_call, | ||
| 559 | }; | ||
| 560 | static struct notifier_block devh_notify_nb_tiler_ducati0 = { | ||
| 561 | .notifier_call = devh44xx_sysm3_tiler_notifier_call, | ||
| 562 | }; | ||
| 563 | static struct notifier_block devh_notify_nb_tiler_ducati1 = { | ||
| 564 | .notifier_call = devh44xx_appm3_tiler_notifier_call, | ||
| 565 | }; | ||
| 566 | #endif | ||
| 567 | |||
| 568 | static inline int devh44xx_sysm3_register(struct omap_devh *devh) | ||
| 569 | { | ||
| 570 | int retval = 0; | ||
| 571 | struct omap_devh_platform_data *pdata = NULL; | ||
| 572 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 573 | if (!devh->dev) | ||
| 574 | return -EINVAL; | ||
| 575 | |||
| 576 | pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; | ||
| 577 | |||
| 578 | if (!pdata) | ||
| 579 | return -EINVAL; | ||
| 580 | |||
| 581 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 582 | |||
| 583 | /* register will kernel modules for event notifications. */ | ||
| 584 | ipc_register_notifier(&devh_notify_nb_ipc_ducati0); | ||
| 585 | pinfo->rproc = omap_rproc_get("ducati-proc0"); | ||
| 586 | if (pinfo->rproc != ERR_PTR(-ENODEV)) | ||
| 587 | omap_rproc_register_notifier(pinfo->rproc, | ||
| 588 | &devh_notify_nb_rproc_ducati0); | ||
| 589 | else | ||
| 590 | pinfo->rproc = NULL; | ||
| 591 | #if defined(CONFIG_TILER_OMAP) | ||
| 592 | tiler_reg_notifier(&devh_notify_nb_tiler_ducati0); | ||
| 593 | #endif | ||
| 594 | |||
| 595 | return retval; | ||
| 596 | } | ||
| 597 | |||
| 598 | static inline int devh44xx_appm3_register(struct omap_devh *devh) | ||
| 599 | { | ||
| 600 | int retval = 0; | ||
| 601 | struct omap_devh_platform_data *pdata = NULL; | ||
| 602 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 603 | if (!devh->dev) | ||
| 604 | return -EINVAL; | ||
| 605 | |||
| 606 | pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; | ||
| 607 | |||
| 608 | if (!pdata) | ||
| 609 | return -EINVAL; | ||
| 610 | |||
| 611 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 612 | |||
| 613 | /* register will kernel modules for event notifications. */ | ||
| 614 | ipc_register_notifier(&devh_notify_nb_ipc_ducati1); | ||
| 615 | pinfo->rproc = omap_rproc_get("ducati-proc1"); | ||
| 616 | if (pinfo->rproc != ERR_PTR(-ENODEV)) | ||
| 617 | omap_rproc_register_notifier(pinfo->rproc, | ||
| 618 | &devh_notify_nb_rproc_ducati1); | ||
| 619 | else | ||
| 620 | pinfo->rproc = NULL; | ||
| 621 | #if defined(CONFIG_TILER_OMAP) | ||
| 622 | tiler_reg_notifier(&devh_notify_nb_tiler_ducati1); | ||
| 623 | #endif | ||
| 624 | |||
| 625 | return retval; | ||
| 626 | } | ||
| 627 | |||
| 628 | static inline int devh44xx_tesla_register(struct omap_devh *devh) | ||
| 629 | { | ||
| 630 | int retval = 0; | ||
| 631 | struct omap_devh_platform_data *pdata = NULL; | ||
| 632 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 633 | if (!devh->dev) | ||
| 634 | return -EINVAL; | ||
| 635 | |||
| 636 | pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; | ||
| 637 | |||
| 638 | if (!pdata) | ||
| 639 | return -EINVAL; | ||
| 640 | |||
| 641 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 642 | |||
| 643 | /* register will kernel modules for event notifications. */ | ||
| 644 | ipc_register_notifier(&devh_notify_nb_ipc_tesla); | ||
| 645 | pinfo->rproc = omap_rproc_get("tesla"); | ||
| 646 | if (pinfo->rproc != ERR_PTR(-ENODEV)) | ||
| 647 | omap_rproc_register_notifier(pinfo->rproc, | ||
| 648 | &devh_notify_nb_rproc_tesla); | ||
| 649 | else | ||
| 650 | pinfo->rproc = NULL; | ||
| 651 | #if defined(CONFIG_TILER_OMAP) | ||
| 652 | tiler_reg_notifier(&devh_notify_nb_tiler_tesla); | ||
| 653 | #endif | ||
| 654 | |||
| 655 | return retval; | ||
| 656 | } | ||
| 657 | |||
| 658 | static inline int devh44xx_sysm3_unregister(struct omap_devh *devh) | ||
| 659 | { | ||
| 660 | int retval = 0; | ||
| 661 | struct omap_devh_platform_data *pdata = NULL; | ||
| 662 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 663 | |||
| 664 | if (!devh->dev) | ||
| 665 | return -EINVAL; | ||
| 666 | |||
| 667 | pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; | ||
| 668 | |||
| 669 | if (!pdata) | ||
| 670 | return -EINVAL; | ||
| 671 | |||
| 672 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 673 | |||
| 674 | /* un-register will kernel modules for event notifications. */ | ||
| 675 | ipc_unregister_notifier(&devh_notify_nb_ipc_ducati0); | ||
| 676 | if (pinfo->rproc) { | ||
| 677 | omap_rproc_unregister_notifier(pinfo->rproc, | ||
| 678 | &devh_notify_nb_rproc_ducati0); | ||
| 679 | omap_rproc_put(pinfo->rproc); | ||
| 680 | } | ||
| 681 | if (pinfo->iommu) { | ||
| 682 | iommu_unregister_notifier(pinfo->iommu, | ||
| 683 | &devh_notify_nb_iommu_ducati0); | ||
| 684 | iommu_put(pinfo->iommu); | ||
| 685 | } | ||
| 686 | #if defined(CONFIG_TILER_OMAP) | ||
| 687 | tiler_unreg_notifier(&devh_notify_nb_tiler_ducati0); | ||
| 688 | #endif | ||
| 689 | |||
| 690 | return retval; | ||
| 691 | } | ||
| 692 | |||
| 693 | static inline int devh44xx_appm3_unregister(struct omap_devh *devh) | ||
| 694 | { | ||
| 695 | int retval = 0; | ||
| 696 | struct omap_devh_platform_data *pdata = NULL; | ||
| 697 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 698 | |||
| 699 | if (!devh->dev) | ||
| 700 | return -EINVAL; | ||
| 701 | |||
| 702 | pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; | ||
| 703 | |||
| 704 | if (!pdata) | ||
| 705 | return -EINVAL; | ||
| 706 | |||
| 707 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 708 | |||
| 709 | /* un-register will kernel modules for event notifications. */ | ||
| 710 | ipc_unregister_notifier(&devh_notify_nb_ipc_ducati1); | ||
| 711 | if (pinfo->rproc) { | ||
| 712 | omap_rproc_unregister_notifier(pinfo->rproc, | ||
| 713 | &devh_notify_nb_rproc_ducati1); | ||
| 714 | omap_rproc_put(pinfo->rproc); | ||
| 715 | } | ||
| 716 | if (pinfo->iommu) { | ||
| 717 | iommu_unregister_notifier(pinfo->iommu, | ||
| 718 | &devh_notify_nb_iommu_ducati1); | ||
| 719 | iommu_put(pinfo->iommu); | ||
| 720 | } | ||
| 721 | #if defined(CONFIG_TILER_OMAP) | ||
| 722 | tiler_unreg_notifier(&devh_notify_nb_tiler_ducati1); | ||
| 723 | #endif | ||
| 724 | |||
| 725 | return retval; | ||
| 726 | } | ||
| 727 | |||
| 728 | static inline int devh44xx_tesla_unregister(struct omap_devh *devh) | ||
| 729 | { | ||
| 730 | int retval = 0; | ||
| 731 | struct omap_devh_platform_data *pdata = NULL; | ||
| 732 | struct omap_devh_runtime_info *pinfo = NULL; | ||
| 733 | |||
| 734 | if (!devh->dev) | ||
| 735 | return -EINVAL; | ||
| 736 | |||
| 737 | pdata = (struct omap_devh_platform_data *)devh->dev->platform_data; | ||
| 738 | |||
| 739 | if (!pdata) | ||
| 740 | return -EINVAL; | ||
| 741 | |||
| 742 | pinfo = (struct omap_devh_runtime_info *)pdata->private_data; | ||
| 743 | |||
| 744 | /* un-register will kernel modules for event notifications. */ | ||
| 745 | ipc_unregister_notifier(&devh_notify_nb_ipc_tesla); | ||
| 746 | if (pinfo->rproc) { | ||
| 747 | omap_rproc_unregister_notifier(pinfo->rproc, | ||
| 748 | &devh_notify_nb_rproc_tesla); | ||
| 749 | omap_rproc_put(pinfo->rproc); | ||
| 750 | } | ||
| 751 | if (pinfo->iommu) { | ||
| 752 | iommu_unregister_notifier(pinfo->iommu, | ||
| 753 | &devh_notify_nb_iommu_tesla); | ||
| 754 | iommu_put(pinfo->iommu); | ||
| 755 | } | ||
| 756 | #if defined(CONFIG_TILER_OMAP) | ||
| 757 | tiler_unreg_notifier(&devh_notify_nb_tiler_tesla); | ||
| 758 | #endif | ||
| 759 | return retval; | ||
| 760 | } | ||
| 761 | |||
| 762 | static struct omap_devh_runtime_info omap4_sysm3_runtime_info = { | ||
| 763 | .brd_state = DEVH_BRDST_STOPPED, | ||
| 764 | .iommu = NULL, | ||
| 765 | .rproc = NULL, | ||
| 766 | }; | ||
| 767 | |||
| 768 | static struct omap_devh_runtime_info omap4_appm3_runtime_info = { | ||
| 769 | .brd_state = DEVH_BRDST_STOPPED, | ||
| 770 | .iommu = NULL, | ||
| 771 | .rproc = NULL, | ||
| 772 | }; | ||
| 773 | |||
| 774 | static struct omap_devh_runtime_info omap4_tesla_runtime_info = { | ||
| 775 | .brd_state = DEVH_BRDST_STOPPED, | ||
| 776 | .iommu = NULL, | ||
| 777 | .rproc = NULL, | ||
| 778 | }; | ||
| 779 | |||
| 780 | static inline int devh44xx_register_event | ||
| 781 | (struct omap_devh *devh, const void __user *args) | ||
| 782 | { | ||
| 783 | struct deh_event_ntfy *fd_reg; | ||
| 784 | struct deh_reg_event_args re_args; | ||
| 785 | |||
| 786 | if (copy_from_user(&re_args, args, sizeof(re_args))) | ||
| 787 | return -EFAULT; | ||
| 788 | |||
| 789 | fd_reg = kzalloc(sizeof(struct deh_event_ntfy), GFP_KERNEL); | ||
| 790 | if (!fd_reg) { | ||
| 791 | dev_err(devh->dev, "%s: kzalloc failed\n", __func__); | ||
| 792 | return -ENOMEM; | ||
| 793 | } | ||
| 794 | |||
| 795 | fd_reg->fd = re_args.fd; | ||
| 796 | fd_reg->event = re_args.event; | ||
| 797 | fd_reg->evt_ctx = eventfd_ctx_fdget(re_args.fd); | ||
| 798 | |||
| 799 | INIT_LIST_HEAD(&fd_reg->list); | ||
| 800 | |||
| 801 | spin_lock_irq(&(devh->event_lock)); | ||
| 802 | list_add_tail(&fd_reg->list, &(devh->event_list)); | ||
| 803 | spin_unlock_irq(&(devh->event_lock)); | ||
| 804 | |||
| 805 | pr_info("Registered user-space process for %s event in %s\n", | ||
| 806 | (re_args.event == 1 ? "DEV_SYS_ERROR" : | ||
| 807 | (re_args.event == 2 ? "DEV_WATCHDOG_ERROR" : "UNKNOWN EVENT")), | ||
| 808 | devh->name); | ||
| 809 | return 0; | ||
| 810 | } | ||
| 811 | |||
| 812 | static inline int devh44xx_unregister_event(struct omap_devh *devh, | ||
| 813 | const void __user *args) | ||
| 814 | { | ||
| 815 | struct deh_event_ntfy *fd_reg, *tmp_reg; | ||
| 816 | struct deh_reg_event_args re_args; | ||
| 817 | if (copy_from_user(&re_args, args, sizeof(re_args))) | ||
| 818 | return -EFAULT; | ||
| 819 | |||
| 820 | spin_lock_irq(&(devh->event_lock)); | ||
| 821 | list_for_each_entry_safe(fd_reg, tmp_reg, &(devh->event_list), list) | ||
| 822 | { | ||
| 823 | if (fd_reg->fd == re_args.fd) { | ||
| 824 | list_del(&fd_reg->list); | ||
| 825 | kfree(fd_reg); | ||
| 826 | } | ||
| 827 | } | ||
| 828 | spin_unlock_irq(&(devh->event_lock)); | ||
| 829 | return 0; | ||
| 830 | } | ||
| 831 | |||
| 832 | static struct omap_devh_ops omap4_sysm3_ops = { | ||
| 833 | .register_notifiers = devh44xx_sysm3_register, | ||
| 834 | .unregister_notifiers = devh44xx_sysm3_unregister, | ||
| 835 | .register_event_notification = devh44xx_register_event, | ||
| 836 | .unregister_event_notification = devh44xx_unregister_event, | ||
| 837 | }; | ||
| 838 | |||
| 839 | static struct omap_devh_ops omap4_appm3_ops = { | ||
| 840 | .register_notifiers = devh44xx_appm3_register, | ||
| 841 | .unregister_notifiers = devh44xx_appm3_unregister, | ||
| 842 | .register_event_notification = devh44xx_register_event, | ||
| 843 | .unregister_event_notification = devh44xx_unregister_event, | ||
| 844 | }; | ||
| 845 | |||
| 846 | static struct omap_devh_ops omap4_tesla_ops = { | ||
| 847 | .register_notifiers = devh44xx_tesla_register, | ||
| 848 | .unregister_notifiers = devh44xx_tesla_unregister, | ||
| 849 | }; | ||
| 850 | |||
| 851 | static struct omap_devh_platform_data omap4_devh_data[] = { | ||
| 852 | { | ||
| 853 | .name = "Tesla", | ||
| 854 | .ops = &omap4_tesla_ops, | ||
| 855 | .proc_id = 0, | ||
| 856 | .err_event_id = -1, | ||
| 857 | .line_id = -1, | ||
| 858 | .private_data = &omap4_tesla_runtime_info, | ||
| 859 | }, | ||
| 860 | { | ||
| 861 | .name = "SysM3", | ||
| 862 | .ops = &omap4_sysm3_ops, | ||
| 863 | .proc_id = 2, | ||
| 864 | .err_event_id = (4 | (NOTIFY_SYSTEMKEY << 16)), | ||
| 865 | .line_id = 0, | ||
| 866 | .private_data = &omap4_sysm3_runtime_info, | ||
| 867 | }, | ||
| 868 | { | ||
| 869 | .name = "AppM3", | ||
| 870 | .ops = &omap4_appm3_ops, | ||
| 871 | .proc_id = 1, | ||
| 872 | .err_event_id = (4 | (NOTIFY_SYSTEMKEY << 16)), | ||
| 873 | .line_id = 0, | ||
| 874 | .private_data = &omap4_appm3_runtime_info, | ||
| 875 | }, | ||
| 876 | }; | ||
| 877 | |||
| 878 | int devh_get_plat_data_size(void) | ||
| 879 | { | ||
| 880 | return ARRAY_SIZE(omap4_devh_data); | ||
| 881 | } | ||
| 882 | EXPORT_SYMBOL(devh_get_plat_data_size); | ||
| 883 | |||
| 884 | |||
| 885 | #define NR_DEVH_DEVICES ARRAY_SIZE(omap4_devh_data) | ||
| 886 | |||
| 887 | static struct platform_device *omap4_devh_pdev[NR_DEVH_DEVICES]; | ||
| 888 | |||
| 889 | struct omap_devh_platform_data *devh_get_plat_data(void) | ||
| 890 | { | ||
| 891 | return omap4_devh_data; | ||
| 892 | } | ||
| 893 | |||
| 894 | /* returns devh object based on the device index */ | ||
| 895 | struct omap_devh *devh_get_obj(int dev_index) | ||
| 896 | { | ||
| 897 | struct platform_device *pdev; | ||
| 898 | struct omap_devh *obj = NULL; | ||
| 899 | int max_num_devices; | ||
| 900 | |||
| 901 | max_num_devices = devh_get_plat_data_size(); | ||
| 902 | |||
| 903 | if (WARN_ON((dev_index > (max_num_devices - 1)))) | ||
| 904 | return NULL; | ||
| 905 | |||
| 906 | pdev = omap4_devh_pdev[dev_index]; | ||
| 907 | |||
| 908 | if (pdev) | ||
| 909 | obj = (struct omap_devh *)platform_get_drvdata(pdev); | ||
| 910 | |||
| 911 | return obj; | ||
| 912 | } | ||
| 913 | |||
| 914 | static int __init omap4_devh_init(void) | ||
| 915 | { | ||
| 916 | int i, err; | ||
| 917 | |||
| 918 | mutex_init(&local_gate); | ||
| 919 | for (i = 0; i < NR_DEVH_DEVICES; i++) { | ||
| 920 | struct platform_device *pdev; | ||
| 921 | |||
| 922 | pdev = platform_device_alloc("omap-devicehandler", i); | ||
| 923 | if (!pdev) { | ||
| 924 | err = -ENOMEM; | ||
| 925 | goto err_out; | ||
| 926 | } | ||
| 927 | |||
| 928 | err = platform_device_add_data(pdev, &omap4_devh_data[i], | ||
| 929 | sizeof(omap4_devh_data[0])); | ||
| 930 | sema_init(&(omap4_devh_data[i].sem_handle), 0); | ||
| 931 | err = platform_device_add(pdev); | ||
| 932 | if (err) | ||
| 933 | goto err_out; | ||
| 934 | omap4_devh_pdev[i] = pdev; | ||
| 935 | } | ||
| 936 | return 0; | ||
| 937 | |||
| 938 | err_out: | ||
| 939 | while (i--) | ||
| 940 | platform_device_put(omap4_devh_pdev[i]); | ||
| 941 | return err; | ||
| 942 | } | ||
| 943 | module_init(omap4_devh_init); | ||
| 944 | |||
| 945 | static void __exit omap4_devh_exit(void) | ||
| 946 | { | ||
| 947 | int i; | ||
| 948 | |||
| 949 | for (i = 0; i < NR_DEVH_DEVICES; i++) | ||
| 950 | platform_device_unregister(omap4_devh_pdev[i]); | ||
| 951 | } | ||
| 952 | module_exit(omap4_devh_exit); | ||
| 953 | |||
| 954 | MODULE_LICENSE("GPL v2"); | ||
| 955 | MODULE_DESCRIPTION("OMAP4 Device Handler module"); | ||
| 956 | MODULE_AUTHOR("Angela Stegmaier <angelabaker@ti.com>"); | ||
diff --git a/drivers/dsp/syslink/devh/Kbuild b/drivers/dsp/syslink/devh/Kbuild new file mode 100644 index 00000000000..65184bd3b59 --- /dev/null +++ b/drivers/dsp/syslink/devh/Kbuild | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | |||
| 2 | obj-$(CONFIG_OMAP_DEVICE_HANDLER) += devh.o | ||
| 3 | |||
| 4 | ccflags-y += -Wno-strict-prototypes | ||
| 5 | |||
| 6 | #Header files | ||
| 7 | ccflags-y += -Iarch/arm/plat-omap/include/syslink | ||
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>"); | ||
diff --git a/drivers/dsp/syslink/devh/devh.h b/drivers/dsp/syslink/devh/devh.h new file mode 100644 index 00000000000..a77af52184e --- /dev/null +++ b/drivers/dsp/syslink/devh/devh.h | |||
| @@ -0,0 +1,87 @@ | |||
| 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 | #ifndef DEVH_H | ||
| 25 | #define DEVH_H | ||
| 26 | |||
| 27 | #include <linux/ioctl.h> | ||
| 28 | #include <linux/cdev.h> | ||
| 29 | #include <linux/semaphore.h> | ||
| 30 | |||
| 31 | #define DEVH_IOC_MAGIC 'E' | ||
| 32 | |||
| 33 | #define DEVH_IOCWAITONEVENTS _IO(DEVH_IOC_MAGIC, 0) | ||
| 34 | #define DEVH_IOCEVENTREG _IOW(DEVH_IOC_MAGIC, 1, \ | ||
| 35 | struct deh_reg_event_args) | ||
| 36 | #define DEVH_IOCEVENTUNREG _IOW(DEVH_IOC_MAGIC, 2, \ | ||
| 37 | struct deh_reg_event_args) | ||
| 38 | |||
| 39 | #define DEVH_IOC_MAXNR (2) | ||
| 40 | |||
| 41 | /* Device error types */ | ||
| 42 | enum { | ||
| 43 | DEV_SYS_ERROR = 1, | ||
| 44 | DEV_WATCHDOG_ERROR, | ||
| 45 | }; | ||
| 46 | |||
| 47 | struct omap_devh; | ||
| 48 | |||
| 49 | struct omap_devh_ops { | ||
| 50 | int (*register_notifiers)(struct omap_devh *devh); | ||
| 51 | int (*unregister_notifiers)(struct omap_devh *devh); | ||
| 52 | int (*register_event_notification)(struct omap_devh *devh, | ||
| 53 | const void __user *args); | ||
| 54 | int (*unregister_event_notification)(struct omap_devh *devh, | ||
| 55 | const void __user *args); | ||
| 56 | }; | ||
| 57 | |||
| 58 | struct omap_devh_platform_data { | ||
| 59 | struct omap_devh_ops *ops; | ||
| 60 | char *name; | ||
| 61 | int proc_id; | ||
| 62 | int err_event_id; | ||
| 63 | int line_id; | ||
| 64 | struct semaphore sem_handle; | ||
| 65 | void *private_data; | ||
| 66 | }; | ||
| 67 | |||
| 68 | struct omap_devh { | ||
| 69 | struct device *dev; | ||
| 70 | struct cdev cdev; | ||
| 71 | atomic_t count; | ||
| 72 | int state; | ||
| 73 | int minor; | ||
| 74 | char *name; | ||
| 75 | struct list_head event_list; | ||
| 76 | spinlock_t event_lock; | ||
| 77 | }; | ||
| 78 | |||
| 79 | struct deh_reg_event_args { | ||
| 80 | int fd; | ||
| 81 | u32 event; | ||
| 82 | }; | ||
| 83 | |||
| 84 | extern struct omap_devh_platform_data *devh_get_plat_data(void); | ||
| 85 | extern int devh_get_plat_data_size(void); | ||
| 86 | |||
| 87 | #endif /* DEVH_H */ | ||
