blob: a900d9745e7521799205a1de5a899089b7288ba9 [file] [log] [blame]
Shalabh Jain10f5f432012-01-11 11:45:44 +05301/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/slab.h>
14#include <linux/diagchar.h>
15#include <linux/platform_device.h>
Dixon Petersoncc0bea772012-04-11 20:45:37 -070016#include <linux/kmemleak.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070017#include "diagchar.h"
18#include "diagfwd.h"
19#include "diagfwd_cntl.h"
Shalabh Jain7b20eab2012-06-19 17:50:58 -070020/* tracks which peripheral is undergoing SSR */
21static uint16_t reg_dirty;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#define HDR_SIZ 8
23
Dixon Peterson66fb11b2012-12-04 20:30:54 -080024void diag_clean_reg_fn(struct work_struct *work)
Shalabh Jain7b20eab2012-06-19 17:50:58 -070025{
Dixon Peterson66fb11b2012-12-04 20:30:54 -080026 struct diag_smd_info *smd_info = container_of(work,
27 struct diag_smd_info,
28 diag_notify_update_smd_work);
29 if (!smd_info)
Shalabh Jain4e1bd312012-02-16 19:33:05 -080030 return;
31
Dixon Peterson66fb11b2012-12-04 20:30:54 -080032 pr_debug("diag: clean registration for peripheral: %d\n",
33 smd_info->peripheral);
34
35 reg_dirty |= smd_info->peripheral_mask;
36 diag_clear_reg(smd_info->peripheral);
37 reg_dirty ^= smd_info->peripheral_mask;
38
39 smd_info->notify_context = 0;
Shalabh Jain4e1bd312012-02-16 19:33:05 -080040}
41
Dixon Peterson66fb11b2012-12-04 20:30:54 -080042/* Process the data read from the smd control channel */
43int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
44 int total_recd)
Shalabh Jain4e1bd312012-02-16 19:33:05 -080045{
Dixon Peterson66fb11b2012-12-04 20:30:54 -080046 int data_len = 0, type = -1, count_bytes = 0, j, flag = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070047 struct bindpkt_params_per_process *pkt_params =
Dixon Peterson66fb11b2012-12-04 20:30:54 -080048 kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049 struct diag_ctrl_msg *msg;
50 struct cmd_code_range *range;
51 struct bindpkt_params *temp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052
Shalabh Jain4e1bd312012-02-16 19:33:05 -080053 if (pkt_params == NULL) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -080054 pr_alert("diag: In %s, Memory allocation failure\n",
55 __func__);
56 return 0;
Shalabh Jain4e1bd312012-02-16 19:33:05 -080057 }
58
Dixon Peterson66fb11b2012-12-04 20:30:54 -080059 if (!smd_info) {
60 pr_err("diag: In %s, No smd info. Not able to read.\n",
61 __func__);
Shalabh Jainf89c5462011-08-23 18:46:03 -070062 kfree(pkt_params);
Dixon Peterson66fb11b2012-12-04 20:30:54 -080063 return 0;
Shalabh Jainf89c5462011-08-23 18:46:03 -070064 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065
Dixon Peterson66fb11b2012-12-04 20:30:54 -080066 while (count_bytes + HDR_SIZ <= total_recd) {
67 type = *(uint32_t *)(buf);
68 data_len = *(uint32_t *)(buf + 4);
69 if (type < DIAG_CTRL_MSG_REG ||
70 type > DIAG_CTRL_MSG_F3_MASK_V2) {
71 pr_alert("diag: In %s, Invalid Msg type %d proc %d",
72 __func__, type, smd_info->peripheral);
73 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -080075 if (data_len < 0 || data_len > total_recd) {
76 pr_alert("diag: In %s, Invalid data len %d, total_recd: %d, proc %d",
77 __func__, data_len, total_recd,
78 smd_info->peripheral);
79 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070080 }
Dixon Peterson66fb11b2012-12-04 20:30:54 -080081 count_bytes = count_bytes+HDR_SIZ+data_len;
82 if (type == DIAG_CTRL_MSG_REG && total_recd >= count_bytes) {
83 msg = buf+HDR_SIZ;
84 range = buf+HDR_SIZ+
85 sizeof(struct diag_ctrl_msg);
86 pkt_params->count = msg->count_entries;
87 temp = kzalloc(pkt_params->count * sizeof(struct
88 bindpkt_params), GFP_KERNEL);
89 if (temp == NULL) {
90 pr_alert("diag: In %s, Memory alloc fail\n",
91 __func__);
92 kfree(pkt_params);
93 return flag;
94 }
95 for (j = 0; j < pkt_params->count; j++) {
96 temp->cmd_code = msg->cmd_code;
97 temp->subsys_id = msg->subsysid;
98 temp->client_id = smd_info->peripheral;
Dixon Petersoneecbadb2012-12-10 21:59:28 -080099 temp->proc_id = NON_APPS_PROC;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800100 temp->cmd_code_lo = range->cmd_code_lo;
101 temp->cmd_code_hi = range->cmd_code_hi;
102 range++;
103 temp++;
104 }
105 temp -= pkt_params->count;
106 pkt_params->params = temp;
107 flag = 1;
108 /* peripheral undergoing SSR should not
109 * record new registration
110 */
111 if (!(reg_dirty & smd_info->peripheral_mask))
112 diagchar_ioctl(NULL, DIAG_IOCTL_COMMAND_REG,
113 (unsigned long)pkt_params);
114 else
115 pr_err("diag: drop reg proc %d\n",
116 smd_info->peripheral);
117 kfree(temp);
118 } else if (type != DIAG_CTRL_MSG_REG) {
119 flag = 1;
120 }
121 buf = buf + HDR_SIZ + data_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 }
123 kfree(pkt_params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800125 return flag;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126}
127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128static int diag_smd_cntl_probe(struct platform_device *pdev)
129{
130 int r = 0;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800131 int index = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132
Shalabh Jain10f5f432012-01-11 11:45:44 +0530133 /* open control ports only on 8960 & newer targets */
Shalabh Jainfb8e3c12011-10-19 17:29:42 -0700134 if (chk_apps_only()) {
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800135 if (pdev->id == SMD_APPS_MODEM) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800136 index = MODEM_DATA;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800137 r = smd_open("DIAG_CNTL",
138 &driver->smd_cntl[index].ch,
139 &driver->smd_cntl[index],
140 diag_smd_notify);
141 driver->smd_cntl[index].ch_save =
142 driver->smd_cntl[index].ch;
143 } else if (pdev->id == SMD_APPS_QDSP) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800144 index = LPASS_DATA;
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800145 r = smd_named_open_on_edge("DIAG_CNTL",
146 SMD_APPS_QDSP,
147 &driver->smd_cntl[index].ch,
148 &driver->smd_cntl[index],
149 diag_smd_notify);
150 driver->smd_cntl[index].ch_save =
151 driver->smd_cntl[index].ch;
152 } else if (pdev->id == SMD_APPS_WCNSS) {
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800153 index = WCNSS_DATA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154 r = smd_named_open_on_edge("APPS_RIVA_CTRL",
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800155 SMD_APPS_WCNSS,
156 &driver->smd_cntl[index].ch,
157 &driver->smd_cntl[index],
158 diag_smd_notify);
159 driver->smd_cntl[index].ch_save =
160 driver->smd_cntl[index].ch;
161 }
162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700163 pr_debug("diag: open CNTL port, ID = %d,r = %d\n", pdev->id, r);
164 }
165 return 0;
166}
167
168static int diagfwd_cntl_runtime_suspend(struct device *dev)
169{
170 dev_dbg(dev, "pm_runtime: suspending...\n");
171 return 0;
172}
173
174static int diagfwd_cntl_runtime_resume(struct device *dev)
175{
176 dev_dbg(dev, "pm_runtime: resuming...\n");
177 return 0;
178}
179
180static const struct dev_pm_ops diagfwd_cntl_dev_pm_ops = {
181 .runtime_suspend = diagfwd_cntl_runtime_suspend,
182 .runtime_resume = diagfwd_cntl_runtime_resume,
183};
184
185static struct platform_driver msm_smd_ch1_cntl_driver = {
186
187 .probe = diag_smd_cntl_probe,
188 .driver = {
189 .name = "DIAG_CNTL",
190 .owner = THIS_MODULE,
191 .pm = &diagfwd_cntl_dev_pm_ops,
192 },
193};
194
195static struct platform_driver diag_smd_lite_cntl_driver = {
196
197 .probe = diag_smd_cntl_probe,
198 .driver = {
199 .name = "APPS_RIVA_CTRL",
200 .owner = THIS_MODULE,
201 .pm = &diagfwd_cntl_dev_pm_ops,
202 },
203};
204
205void diagfwd_cntl_init(void)
206{
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800207 int success;
208 int i;
209
Shalabh Jain7b20eab2012-06-19 17:50:58 -0700210 reg_dirty = 0;
Shalabh Jain3d29fc32012-02-09 17:15:59 -0800211 driver->polling_reg_flag = 0;
Shalabh Jain321c8b52012-02-22 12:37:06 -0800212 driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800213
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800214 success = diag_smd_constructor(&driver->smd_cntl[MODEM_DATA],
215 MODEM_DATA, SMD_CNTL_TYPE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800216 if (!success)
217 goto err;
218
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800219 success = diag_smd_constructor(&driver->smd_cntl[LPASS_DATA],
220 LPASS_DATA, SMD_CNTL_TYPE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800221 if (!success)
222 goto err;
223
Dixon Petersoneecbadb2012-12-10 21:59:28 -0800224 success = diag_smd_constructor(&driver->smd_cntl[WCNSS_DATA],
225 WCNSS_DATA, SMD_CNTL_TYPE);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800226 if (!success)
227 goto err;
228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 platform_driver_register(&msm_smd_ch1_cntl_driver);
230 platform_driver_register(&diag_smd_lite_cntl_driver);
231
232 return;
233err:
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800234 pr_err("diag: Could not initialize diag buffers");
235
236 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
237 diag_smd_destructor(&driver->smd_cntl[i]);
238
239 if (driver->diag_cntl_wq)
240 destroy_workqueue(driver->diag_cntl_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241}
242
243void diagfwd_cntl_exit(void)
244{
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800245 int i;
246
247 for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
248 diag_smd_destructor(&driver->smd_cntl[i]);
249
Shalabh Jain321c8b52012-02-22 12:37:06 -0800250 destroy_workqueue(driver->diag_cntl_wq);
Dixon Peterson66fb11b2012-12-04 20:30:54 -0800251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 platform_driver_unregister(&msm_smd_ch1_cntl_driver);
253 platform_driver_unregister(&diag_smd_lite_cntl_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254}