/drivers/omap_hsi/hsi_protocol_cmd.c
C | 429 lines | 319 code | 75 blank | 35 comment | 29 complexity | 56c6e891ba1679c20ddebab668a7626a MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
1/*
2 * File - hsi_protocol_if_cmd.c
3 *
4 * Implements HSI protocol for Infineon Modem.
5 *
6 * Copyright (C) 2011 Samsung Electronics. All rights reserved.
7 *
8 * Author: Rupesh Gujare <rupesh.g@samsung.com>
9 *
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 */
18
19
20#include <linux/errno.h>
21#include <linux/module.h>
22#include <linux/types.h>
23#include <linux/init.h>
24#include <linux/device.h>
25#include <linux/err.h>
26#include <linux/delay.h>
27#include <linux/wait.h>
28#include <linux/sched.h>
29
30#include <linux/hsi_driver_if.h>
31#include "hsi-protocol-if.h"
32
33extern struct if_hsi_iface hsi_protocol_iface;
34extern wait_queue_head_t ipc_read_wait, ipc_write_wait;
35int if_hsi_openchannel(struct if_hsi_channel *channel);
36int if_hsi_closechannel(struct if_hsi_channel *channel);
37
38extern struct if_hsi_cmd hsi_cmd_history;
39extern int tx_cmd_history_p;
40extern int rx_cmd_history_p;
41
42/*Decode command from received PDU on channle 0*/
43int hsi_decode_cmd(u32 *cmd_data, u32 *cmd, u32 *ch, u32 *param)
44{
45 int ret = 0;
46 u32 data = *cmd_data;
47 u8 lrc_cal, lrc_act;
48 u8 val1, val2, val3;
49
50 *cmd = ((data & 0xF0000000) >> 28);
51
52 switch (*cmd) {
53 case HSI_LL_MSG_BREAK:
54 pr_err("Command MSG_BREAK Received.\n");
55 break;
56
57 case HSI_LL_MSG_OPEN_CONN:
58 *ch = ((data & 0x0F000000) >> 24);
59 *param = ((data & 0x00FFFF00) >> 8);
60 /*Check LRC*/
61 val1 = ((data & 0xFF000000) >> 24);
62 val2 = ((data & 0x00FF0000) >> 16);
63 val3 = ((data & 0x0000FF00) >> 8);
64 lrc_act = (data & 0x000000FF);
65 lrc_cal = val1 ^ val2 ^ val3;
66 if (lrc_cal != lrc_act)
67 ret = -1;
68 break;
69
70 case HSI_LL_MSG_CONN_READY:
71 case HSI_LL_MSG_CONN_CLOSED:
72 case HSI_LL_MSG_CANCEL_CONN:
73 case HSI_LL_MSG_NAK:
74 *ch = ((data & 0x0F000000) >> 24);
75 break;
76
77 case HSI_LL_MSG_ACK:
78 *ch = ((data & 0x0F000000) >> 24);
79 *param = (data & 0x00FFFFFF);
80 //printk(KERN_INFO "ACK Received ch=%d, param=%d\n",*ch, *param);
81 break;
82
83 case HSI_LL_MSG_CONF_RATE:
84 *ch = ((data & 0x0F000000) >> 24);
85 *param = ((data & 0x0F000000) >> 24);
86 break;
87
88 case HSI_LL_MSG_OPEN_CONN_OCTET:
89 *ch = ((data & 0x0F000000) >> 24);
90 *param = (data & 0x00FFFFFF);
91 break;
92
93 case HSI_LL_MSG_ECHO:
94 case HSI_LL_MSG_INFO_REQ:
95 case HSI_LL_MSG_INFO:
96 case HSI_LL_MSG_CONFIGURE:
97 case HSI_LL_MSG_ALLOCATE_CH:
98 case HSI_LL_MSG_RELEASE_CH:
99 case HSI_LL_MSG_INVALID:
100 *cmd = HSI_LL_MSG_INVALID;
101 *ch = HSI_LL_INVALID_CHANNEL;
102 ret = -1;
103 break;
104 }
105 return ret;
106}
107
108int protocol_create_cmd(int cmd_type, unsigned int channel, void *arg)
109{
110 unsigned int command = 0;
111 int ret = 0;
112
113 switch (cmd_type) {
114 case HSI_LL_MSG_BREAK:
115 {
116 command = 0;
117 }
118 break;
119
120 case HSI_LL_MSG_OPEN_CONN:
121 {
122 unsigned int size = *(unsigned int *)arg;
123 unsigned int lcr = 0;
124
125/* if(size > 4)
126 size = (size & 0x3) ? ((size >> 2) + 1):(size >> 2);
127 else
128 size = 1;*/
129
130 command = ((HSI_LL_MSG_OPEN_CONN & 0x0000000F) << 28) |
131 ((channel & 0x000000FF) << 24) |
132 ((size & 0x0000FFFF) << 8);
133
134 lcr = ((command & 0xFF000000) >> 24) ^
135 ((command & 0x00FF0000) >> 16) ^
136 ((command & 0x0000FF00) >> 8);
137
138 command = command | (lcr & 0x000000FF);
139 }
140 break;
141
142 case HSI_LL_MSG_CONN_READY:
143 {
144 command = ((HSI_LL_MSG_CONN_READY & 0x0000000F) << 28) |
145 ((channel & 0x000000FF) << 24);
146 }
147 break;
148
149 case HSI_LL_MSG_CONN_CLOSED:
150 {
151 command = ((HSI_LL_MSG_CONN_CLOSED & 0x0000000F) << 28) |
152 ((channel & 0x000000FF) << 24);
153 }
154 break;
155
156 case HSI_LL_MSG_CANCEL_CONN:
157 {
158 unsigned int role = *(unsigned int *)arg;
159
160 command = ((HSI_LL_MSG_CANCEL_CONN & 0x0000000F) << 28) |
161 ((channel & 0x000000FF) << 24) |
162 ((role & 0x000000FF) << 16);
163 }
164 break;
165
166 case HSI_LL_MSG_ACK:
167 {
168 unsigned int echo_params = *(unsigned int *)arg;
169
170 command = ((HSI_LL_MSG_ACK & 0x0000000F) << 28) |
171 ((channel & 0x000000FF) << 24) |
172 ((echo_params & 0x00FFFFFF));
173 }
174 break;
175
176 case HSI_LL_MSG_NAK:
177 {
178 command = ((HSI_LL_MSG_NAK & 0x0000000F) << 28) |
179 ((channel & 0x000000FF) << 24);
180 }
181 break;
182
183 case HSI_LL_MSG_CONF_RATE:
184 {
185 unsigned int baud_rate = *(unsigned int *)arg;
186
187 command = ((HSI_LL_MSG_CONF_RATE & 0x0000000F) << 28) |
188 ((channel & 0x000000FF) << 24) |
189 ((baud_rate & 0x00FFFFFF));
190 }
191 break;
192
193 case HSI_LL_MSG_OPEN_CONN_OCTET:
194 {
195 unsigned int size = *(unsigned int *)arg;
196
197 command = ((HSI_LL_MSG_OPEN_CONN_OCTET & 0x0000000F) << 28) |
198 ((channel & 0x000000FF) << 24) |
199 ((size & 0x00FFFFFF));
200
201 }
202 break;
203
204 case HSI_LL_MSG_ECHO:
205 case HSI_LL_MSG_INFO_REQ:
206 case HSI_LL_MSG_INFO:
207 case HSI_LL_MSG_CONFIGURE:
208 case HSI_LL_MSG_ALLOCATE_CH:
209 case HSI_LL_MSG_RELEASE_CH:
210 case HSI_LL_MSG_INVALID:
211 ret = -1;
212 break;
213 }
214 return command;
215}
216
217int set_tx_config(struct if_hsi_channel *ch, u32 mode, u32 max_channels)
218{
219 struct hst_ctx tx_config;
220 int ret;
221
222 hsi_ioctl(ch->dev, HSI_IOCTL_GET_TX, &tx_config);
223 tx_config.mode = mode;
224 tx_config.channels = max_channels;
225 ret = hsi_ioctl(ch->dev, HSI_IOCTL_SET_TX, &tx_config);
226 return ret;
227}
228
229static int saved_cmd_queue = 0;
230static u32 cmd_saved[5];
231int hsi_protocol_send_command(u32 cmd, u32 channel, u32 param)
232{
233 struct if_hsi_channel *channel_zero;
234 u32 cmd_array[4] = {0x00000000, 0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC}, ret = -1;
235
236 channel_zero = &hsi_protocol_iface.channels[0];
237 cmd_array[0] = protocol_create_cmd(cmd, channel, ¶m);
238 pr_debug("[%s] CMD = %08x\n",__func__, cmd_array[0]);
239 while (channel_zero->tx_state != HSI_LL_TX_STATE_IDLE) {
240 cmd_saved[saved_cmd_queue] = cmd_array[0];
241 saved_cmd_queue++;
242 pr_debug("(%s) cmd_saved : %x(%d)\n", __func__, cmd_array[0], saved_cmd_queue);
243
244 return 0;
245 }
246
247send_retry:
248
249 channel_zero->tx_state = HSI_LL_TX_STATE_TX;
250
251 // For es 2.1 ver.
252 ret = hsi_proto_write(0, cmd_array, 4);
253 if (ret < 0) {
254 pr_err("(%s) Command Write failed, CMD->%X\n", __func__, cmd_array[0]);
255 channel_zero->tx_state = HSI_LL_TX_STATE_IDLE;
256 return -1;
257 } else {
258 channel_zero->tx_state = HSI_LL_TX_STATE_IDLE;
259
260 pr_debug("[%s] CMD = %08x\n", __func__, cmd_array[0]);
261
262 hsi_cmd_history.tx_cmd[tx_cmd_history_p] = cmd_array[0];
263 hsi_cmd_history.tx_cmd_time[tx_cmd_history_p] = CURRENT_TIME;
264 tx_cmd_history_p++;
265 if (tx_cmd_history_p >= 50)
266 tx_cmd_history_p = 0;
267
268 if (saved_cmd_queue) {
269 saved_cmd_queue--;
270 cmd_array[0] = cmd_saved[saved_cmd_queue];
271
272 goto send_retry;
273 }
274
275 return 0;
276 }
277}
278
279void rx_stm(u32 cmd, u32 ch, u32 param)
280{
281 struct if_hsi_channel *channel;
282 u32 size = 0, tmp_cmd = 0, ret, i;
283 channel = &hsi_protocol_iface.channels[ch];
284
285 switch (cmd) {
286 case HSI_LL_MSG_OPEN_CONN:
287 pr_err("ERROR... OPEN_CONN Not supported. Should use OPEN_CONN_OCTECT instead.\n");
288 break;
289
290 case HSI_LL_MSG_ECHO:
291 pr_err("ERROR... HSI_LL_MSG_ECHO not supported.\n");
292 break;
293
294 case HSI_LL_MSG_CONN_CLOSED:
295 switch (channel->tx_state) {
296 case HSI_LL_TX_STATE_WAIT_FOR_CONN_CLOSED:
297 channel->tx_state = HSI_LL_TX_STATE_IDLE;
298
299 /* ACWAKE ->LOW */
300 ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_DOWN, NULL);
301 if (ret == 0)
302 pr_debug("ACWAKE pulled low in %s()\n", __func__);
303 else
304 pr_err("ACWAKE pulled low in %s() ERROR : %d\n", __func__, ret);
305
306 pr_debug("[%s] Received CONN_CLOSED. ch-> %d\n", __func__,ch);
307 break;
308
309 default:
310 pr_err("Wrong STATE for CONN_CLOSED\n");
311 }
312 break;
313
314 case HSI_LL_MSG_CANCEL_CONN:
315 pr_debug("Received CANCEL_CONN\n");
316 break;
317
318 case HSI_LL_MSG_ACK:
319 switch (channel->tx_state) {
320 case HSI_LL_TX_STATE_WAIT_FOR_ACK:
321 case HSI_LL_TX_STATE_SEND_OPEN_CONN:
322 //printk(KERN_INFO "ACK received %s()\n",__func__);
323
324 channel->tx_state = HSI_LL_TX_STATE_TX;
325 size = param;
326#if 0
327 // TEMP: send/read by 16 byte unit for v.11A(CP)
328 if ((size > 16) && (size % 16))
329 size += (16 - (size % 16));
330 else if (size < 16)
331 size = 16;
332#endif
333
334 // For es 2.1 ver.
335 if (size % 4)
336 size += (4 - (size % 4));
337
338 pr_debug("Writing %d bytes data on channel %d, tx_buf = %x, in %s()\n", size, ch, channel->tx_buf, __func__);
339 ret = hsi_proto_write(ch, channel->tx_buf, size);
340 channel->tx_state = HSI_LL_TX_STATE_WAIT_FOR_CONN_CLOSED;
341 wake_up_interruptible(&ipc_write_wait);
342 channel->tx_nak_count = 0;
343 break;
344
345 case HSI_LL_TX_STATE_CLOSED:/* ACK as response to CANCEL_CONN */
346 if (channel->rx_state == HSI_LL_RX_STATE_WAIT_FOR_CANCEL_CONN_ACK)
347 channel->rx_state = HSI_LL_RX_STATE_IDLE;
348 break;
349
350 case HSI_LL_TX_STATE_WAIT_FOR_CONF_ACK: /* ACK as response to CONF_RATE */
351 //TODO: SET CONF RATE
352 pr_debug("ACK Received for CONF_RATE\n");
353 break;
354
355 default:
356 pr_err("ACK Received for Unknown state\n");
357 }
358 break;
359
360 case HSI_LL_MSG_NAK:
361 switch (channel->tx_state) {
362 case HSI_LL_TX_STATE_WAIT_FOR_ACK:
363 printk(KERN_INFO "(%s) NAK received. ch->%d\n", __func__, ch);
364 //channel->tx_state = HSI_LL_TX_STATE_NACK;
365 if (channel->tx_nak_count < 10) {
366 msleep(10);
367
368 tmp_cmd = ((HSI_LL_MSG_OPEN_CONN_OCTET & 0x0000000F) << 28) |
369 ((ch & 0x000000FF) << 24);
370 for (i = 49; i >= 0; i--) {
371 if ((hsi_cmd_history.tx_cmd[i] & 0xFFF00000) == tmp_cmd)
372 break;
373 }
374 size = (hsi_cmd_history.tx_cmd[i] & 0x000FFFFF);
375
376 pr_debug("(%s) Re Send OPEN CONN ch->%d, size->%d, count->%d\n", __func__, ch, size, channel->tx_nak_count);
377
378 hsi_protocol_send_command(HSI_LL_MSG_OPEN_CONN_OCTET, ch, size);
379 channel->tx_nak_count++;
380 } else {
381 hsi_protocol_send_command(HSI_LL_MSG_BREAK, ch, size);
382 pr_debug("(%s) Sending MSG_BREAK. ch->%d\n", __func__, ch);
383 //TODO Reset All channels and inform IPC write about failure (Possibly by sending signal)
384 }
385 break;
386
387 case HSI_LL_TX_STATE_WAIT_FOR_CONF_ACK: /* NAK as response to CONF_RATE */
388 channel->tx_state = HSI_LL_TX_STATE_IDLE;
389 break;
390
391 default:
392 pr_err("ERROR - Received NAK in invalid state. state->%d\n", channel->tx_state);
393 }
394 break;
395
396 case HSI_LL_MSG_CONF_RATE:
397 //TODO: Set Conf Rate
398 pr_debug("CONF_RATE Received\n");
399 break;
400
401 case HSI_LL_MSG_OPEN_CONN_OCTET:
402 switch (channel->rx_state) {
403 /* case HSI_LL_RX_STATE_CLOSED: */
404 case HSI_LL_RX_STATE_IDLE:
405 pr_debug("OPEN_CONN_OCTET in %s(), ch-> %d\n", __func__, ch);
406 channel->rx_state = HSI_LL_RX_STATE_TO_ACK;
407 hsi_protocol_send_command(HSI_LL_MSG_ACK, ch, param);
408
409 channel->rx_count = param;
410 channel->rx_state = HSI_LL_RX_STATE_RX;
411 wake_up_interruptible(&ipc_read_wait);
412 break;
413
414 case HSI_LL_RX_STATE_BLOCKED:
415 /* TODO */
416 break;
417
418 default:
419 pr_err("OPEN_CONN_OCTET in invalid state, Current State -> %d\n", channel->rx_state);
420 pr_info("Sending NAK to channel-> %d\n", ch);
421 hsi_protocol_send_command(HSI_LL_MSG_NAK, ch, param);
422 }
423 break;
424
425 default:
426 pr_err("Invalid Command encountered in rx_state()\n");
427 }
428
429}