PageRenderTime 66ms CodeModel.GetById 11ms app.highlight 49ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/omap_hsi/hsi_protocol_cmd.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2
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, &param);
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}