blob: bcfc556cad39dd1f591e1853e2f4094d0a507ca5 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2010-2011, The Linux Foundation. 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/*
14 * SDIO-Abstraction-Layer Module.
15 *
16 * To be used with Qualcomm's SDIO-Client connected to this host.
17 */
Alhad Purnapatred0d12e72011-10-26 14:04:42 -070018#include "sdio_al_private.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070019
20#include <linux/module.h>
21#include <linux/scatterlist.h>
22#include <linux/workqueue.h>
23#include <linux/wait.h>
24#include <linux/delay.h>
25#include <linux/fs.h>
26#include <linux/slab.h>
27#include <linux/wakelock.h>
28#include <linux/mmc/core.h>
29#include <linux/mmc/card.h>
30#include <linux/mmc/host.h>
31#include <linux/mmc/mmc.h>
32#include <linux/mmc/sdio.h>
33#include <linux/mmc/sdio_func.h>
34#include <linux/mmc/sdio_ids.h>
35#include <linux/gpio.h>
36#include <linux/dma-mapping.h>
37#include <linux/earlysuspend.h>
38#include <linux/debugfs.h>
39#include <linux/uaccess.h>
40#include <linux/syscalls.h>
Krishna Kondaa7af6062011-09-01 18:34:38 -070041#include <linux/time.h>
42#include <linux/spinlock.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070043
44#include <mach/dma.h>
45#include <mach/gpio.h>
46#include <mach/subsystem_notif.h>
47
48#include "../../../drivers/mmc/host/msm_sdcc.h"
49
50/**
51 * Func#0 has SDIO standard registers
52 * Func#1 is for Mailbox.
53 * Functions 2..7 are for channels.
54 * Currently only functions 2..5 are active due to SDIO-Client
55 * number of pipes.
56 *
57 */
58#define SDIO_AL_MAX_CHANNELS 6
59
60/** Func 1..5 */
61#define SDIO_AL_MAX_FUNCS (SDIO_AL_MAX_CHANNELS+1)
62#define SDIO_AL_WAKEUP_FUNC 6
63
64/** Number of SDIO-Client pipes */
65#define SDIO_AL_MAX_PIPES 16
66#define SDIO_AL_ACTIVE_PIPES 8
67
68/** CMD53/CMD54 Block size */
Yaniv Gardie5370b82011-07-27 11:46:51 +030069#define SDIO_AL_BLOCK_SIZE 256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070
71/** Func#1 hardware Mailbox base address */
72#define HW_MAILBOX_ADDR 0x1000
73
74/** Func#1 peer sdioc software version.
75 * The header is duplicated also to the mailbox of the other
76 * functions. It can be used before other functions are enabled. */
77#define SDIOC_SW_HEADER_ADDR 0x0400
78
79/** Func#2..7 software Mailbox base address at 16K */
80#define SDIOC_SW_MAILBOX_ADDR 0x4000
81
82/** Some Mailbox registers address, written by host for
83 control */
84#define PIPES_THRESHOLD_ADDR 0x01000
85
86#define PIPES_0_7_IRQ_MASK_ADDR 0x01048
87
88#define PIPES_8_15_IRQ_MASK_ADDR 0x0104C
89
90#define FUNC_1_4_MASK_IRQ_ADDR 0x01040
91#define FUNC_5_7_MASK_IRQ_ADDR 0x01044
92#define FUNC_1_4_USER_IRQ_ADDR 0x01050
93#define FUNC_5_7_USER_IRQ_ADDR 0x01054
94
95#define EOT_PIPES_ENABLE 0x00
96
97/** Maximum read/write data available is SDIO-Client limitation */
98#define MAX_DATA_AVAILABLE (16*1024)
99#define INVALID_DATA_AVAILABLE (0x8000)
100
101/** SDIO-Client HW threshold to generate interrupt to the
102 * SDIO-Host on write available bytes.
103 */
104#define DEFAULT_WRITE_THRESHOLD (1024)
105
106/** SDIO-Client HW threshold to generate interrupt to the
107 * SDIO-Host on read available bytes, for streaming (non
108 * packet) rx data.
109 */
110#define DEFAULT_READ_THRESHOLD (1024)
Maya Erez3eb7d4c2011-10-17 15:08:42 +0200111#define LOW_LATENCY_THRESHOLD (1)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112
Maya Erez8ed0a9a2011-07-19 14:46:53 +0300113/* Extra bytes to ensure getting the rx threshold interrupt on stream channels
114 when restoring the threshold after sleep */
115#define THRESHOLD_CHANGE_EXTRA_BYTES (100)
116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117/** SW threshold to trigger reading the mailbox. */
118#define DEFAULT_MIN_WRITE_THRESHOLD (1024)
119#define DEFAULT_MIN_WRITE_THRESHOLD_STREAMING (1600)
120
121#define THRESHOLD_DISABLE_VAL (0xFFFFFFFF)
122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123/** Mailbox polling time for packet channels */
124#define DEFAULT_POLL_DELAY_MSEC 10
125/** Mailbox polling time for streaming channels */
126#define DEFAULT_POLL_DELAY_NOPACKET_MSEC 30
127
128/** The SDIO-Client prepares N buffers of size X per Tx pipe.
129 * Even when the transfer fills a partial buffer,
130 * that buffer becomes unusable for the next transfer. */
131#define DEFAULT_PEER_TX_BUF_SIZE (128)
132
133#define ROUND_UP(x, n) (((x + n - 1) / n) * n)
134
135/** Func#2..7 FIFOs are r/w via
136 sdio_readsb() & sdio_writesb(),when inc_addr=0 */
137#define PIPE_RX_FIFO_ADDR 0x00
138#define PIPE_TX_FIFO_ADDR 0x00
139
140/** Inactivity time to go to sleep in mseconds */
141#define INACTIVITY_TIME_MSEC 30
142#define INITIAL_INACTIVITY_TIME_MSEC 5000
143
144/** Context validity check */
145#define SDIO_AL_SIGNATURE 0xAABBCCDD
146
147/* Vendor Specific Command */
148#define SD_IO_RW_EXTENDED_QCOM 54
149
150#define TIME_TO_WAIT_US 500
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +0300151#define SDIO_CLOSE_FLUSH_TIMEOUT_MSEC (10000)
Maya Erez5795e0d2011-09-12 20:20:06 +0300152#define RX_FLUSH_BUFFER_SIZE (16*1024)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153
154#define SDIO_TEST_POSTFIX "_TEST"
155
Krishna Kondaa7af6062011-09-01 18:34:38 -0700156#define DATA_DEBUG(x, y...) \
157 do { \
158 if (sdio_al->debug.debug_data_on) \
159 pr_info(y); \
160 sdio_al_log(x, y); \
161 } while (0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162
Krishna Kondaa7af6062011-09-01 18:34:38 -0700163#define LPM_DEBUG(x, y...) \
164 do { \
165 if (sdio_al->debug.debug_lpm_on) \
166 pr_info(y); \
167 sdio_al_log(x, y); \
168 } while (0)
169
170#define sdio_al_loge(x, y...) \
171 do { \
172 pr_err(y); \
173 sdio_al_log(x, y); \
174 } while (0)
175
176#define sdio_al_logi(x, y...) \
177 do { \
178 pr_info(y); \
179 sdio_al_log(x, y); \
180 } while (0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700181
Maya Erez7ad06d82011-10-02 15:47:57 +0200182#define CLOSE_DEBUG(x, y...) \
183 do { \
184 if (sdio_al->debug.debug_close_on) \
185 pr_info(y); \
186 sdio_al_log(x, y); \
187 } while (0)
188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189/* The index of the SDIO card used for the sdio_al_dloader */
190#define SDIO_BOOTLOADER_CARD_INDEX 1
191
192
193/* SDIO card state machine */
194enum sdio_al_device_state {
195 CARD_INSERTED,
196 CARD_REMOVED,
197 MODEM_RESTART
198};
199
200struct sdio_al_debug {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 u8 debug_lpm_on;
202 u8 debug_data_on;
Maya Erez7ad06d82011-10-02 15:47:57 +0200203 u8 debug_close_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 struct dentry *sdio_al_debug_root;
205 struct dentry *sdio_al_debug_lpm_on;
206 struct dentry *sdio_al_debug_data_on;
Maya Erez7ad06d82011-10-02 15:47:57 +0200207 struct dentry *sdio_al_debug_close_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 struct dentry *sdio_al_debug_info;
Krishna Kondaa7af6062011-09-01 18:34:38 -0700209 struct dentry *sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210};
211
212/* Polling time for the inactivity timer for devices that doesn't have
213 * a streaming channel
214 */
215#define SDIO_AL_POLL_TIME_NO_STREAMING 30
216
217#define CHAN_TO_FUNC(x) ((x) + 2 - 1)
218
219/**
220 * Mailbox structure.
221 * The Mailbox is located on the SDIO-Client Function#1.
222 * The mailbox size is 128 bytes, which is one block.
223 * The mailbox allows the host ton:
224 * 1. Get the number of available bytes on the pipes.
225 * 2. Enable/Disable SDIO-Client interrupt, related to pipes.
226 * 3. Set the Threshold for generating interrupt.
227 *
228 */
229struct sdio_mailbox {
230 u32 pipe_bytes_threshold[SDIO_AL_MAX_PIPES]; /* Addr 0x1000 */
231
232 /* Mask USER interrupts generated towards host - Addr 0x1040 */
233 u32 mask_irq_func_1:8; /* LSB */
234 u32 mask_irq_func_2:8;
235 u32 mask_irq_func_3:8;
236 u32 mask_irq_func_4:8;
237
238 u32 mask_irq_func_5:8;
239 u32 mask_irq_func_6:8;
240 u32 mask_irq_func_7:8;
241 u32 mask_mutex_irq:8;
242
243 /* Mask PIPE interrupts generated towards host - Addr 0x1048 */
244 u32 mask_eot_pipe_0_7:8;
245 u32 mask_thresh_above_limit_pipe_0_7:8;
246 u32 mask_overflow_pipe_0_7:8;
247 u32 mask_underflow_pipe_0_7:8;
248
249 u32 mask_eot_pipe_8_15:8;
250 u32 mask_thresh_above_limit_pipe_8_15:8;
251 u32 mask_overflow_pipe_8_15:8;
252 u32 mask_underflow_pipe_8_15:8;
253
254 /* Status of User interrupts generated towards host - Addr 0x1050 */
255 u32 user_irq_func_1:8;
256 u32 user_irq_func_2:8;
257 u32 user_irq_func_3:8;
258 u32 user_irq_func_4:8;
259
260 u32 user_irq_func_5:8;
261 u32 user_irq_func_6:8;
262 u32 user_irq_func_7:8;
263 u32 user_mutex_irq:8;
264
265 /* Status of PIPE interrupts generated towards host */
266 /* Note: All sources are cleared once they read. - Addr 0x1058 */
267 u32 eot_pipe_0_7:8;
268 u32 thresh_above_limit_pipe_0_7:8;
269 u32 overflow_pipe_0_7:8;
270 u32 underflow_pipe_0_7:8;
271
272 u32 eot_pipe_8_15:8;
273 u32 thresh_above_limit_pipe_8_15:8;
274 u32 overflow_pipe_8_15:8;
275 u32 underflow_pipe_8_15:8;
276
277 u16 pipe_bytes_avail[SDIO_AL_MAX_PIPES];
278};
279
280/** Track pending Rx Packet size */
281struct rx_packet_size {
282 u32 size; /* in bytes */
283 struct list_head list;
284};
285
286#define PEER_SDIOC_SW_MAILBOX_SIGNATURE 0xFACECAFE
287#define PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE 0x5D107E57
288#define PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE 0xDEADBEEF
289
290/* Allow support in old sdio version */
291#define PEER_SDIOC_OLD_VERSION_MAJOR 0x0002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292#define INVALID_SDIO_CHAN 0xFF
293
294/**
295 * Peer SDIO-Client software header.
296 */
297struct peer_sdioc_sw_header {
298 u32 signature;
299 u32 version;
300 u32 max_channels;
301 char channel_names[SDIO_AL_MAX_CHANNELS][PEER_CHANNEL_NAME_SIZE];
302 u32 reserved[23];
303};
304
305struct peer_sdioc_boot_sw_header {
306 u32 signature;
307 u32 version;
308 u32 boot_ch_num;
309 u32 reserved[29]; /* 32 - previous fields */
310};
311
312/**
313 * Peer SDIO-Client software mailbox.
314 */
315struct peer_sdioc_sw_mailbox {
316 struct peer_sdioc_sw_header sw_header;
317 struct peer_sdioc_channel_config ch_config[SDIO_AL_MAX_CHANNELS];
318};
319
Krishna Kondaa7af6062011-09-01 18:34:38 -0700320#define SDIO_AL_DEBUG_LOG_SIZE 3000
321struct sdio_al_local_log {
322 char buffer[SDIO_AL_DEBUG_LOG_SIZE];
323 unsigned int buf_cur_pos;
324 spinlock_t log_lock;
325};
326
327#define SDIO_AL_DEBUG_TMP_LOG_SIZE 250
328static int sdio_al_log(struct sdio_al_local_log *, const char *fmt, ...);
329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330/**
331 * SDIO Abstraction Layer driver context.
332 *
333 * @pdata -
334 * @debug -
335 * @devices - an array of the the devices claimed by sdio_al
336 * @unittest_mode - a flag to indicate if sdio_al is in
337 * unittest mode
338 * @bootloader_dev - the device which is used for the
339 * bootloader
340 * @subsys_notif_handle - handle for modem restart
341 * notifications
342 *
343 */
344struct sdio_al {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700345 struct sdio_al_local_log gen_log;
346 struct sdio_al_local_log device_log[MAX_NUM_OF_SDIO_DEVICES];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 struct sdio_al_platform_data *pdata;
348 struct sdio_al_debug debug;
349 struct sdio_al_device *devices[MAX_NUM_OF_SDIO_DEVICES];
350 int unittest_mode;
351 struct sdio_al_device *bootloader_dev;
352 void *subsys_notif_handle;
353 int sdioc_major;
Maya Erezc7f63282011-10-11 12:15:23 +0200354 int skip_print_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355};
356
357struct sdio_al_work {
358 struct work_struct work;
359 struct sdio_al_device *sdio_al_dev;
360};
361
362
363/**
364 * SDIO Abstraction Layer device context.
365 *
366 * @card - card claimed.
367 *
368 * @mailbox - A shadow of the SDIO-Client mailbox.
369 *
370 * @channel - Channels context.
371 *
372 * @workqueue - workqueue to read the mailbox and handle
373 * pending requests. Reading the mailbox should not happen
374 * in interrupt context.
375 *
376 * @work - work to submit to workqueue.
377 *
378 * @is_ready - driver is ready.
379 *
380 * @ask_mbox - Flag to request reading the mailbox,
381 * for different reasons.
382 *
383 * @wake_lock - Lock when can't sleep.
384 *
385 * @lpm_chan - Channel to use for LPM (low power mode)
386 * communication.
387 *
388 * @is_ok_to_sleep - Mark if driver is OK with going to sleep
389 * (no pending transactions).
390 *
391 * @inactivity_time - time allowed to be in inactivity before
392 * going to sleep
393 *
394 * @timer - timer to use for polling the mailbox.
395 *
396 * @poll_delay_msec - timer delay for polling the mailbox.
397 *
398 * @is_err - error detected.
399 *
400 * @signature - Context Validity Check.
401 *
402 * @flashless_boot_on - flag to indicate if sdio_al is in
403 * flshless boot mode
404 *
405 */
406struct sdio_al_device {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700407 struct sdio_al_local_log *dev_log;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 struct mmc_card *card;
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200409 struct mmc_host *host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410 struct sdio_mailbox *mailbox;
411 struct sdio_channel channel[SDIO_AL_MAX_CHANNELS];
412
413 struct peer_sdioc_sw_header *sdioc_sw_header;
414 struct peer_sdioc_boot_sw_header *sdioc_boot_sw_header;
415
416 struct workqueue_struct *workqueue;
417 struct sdio_al_work sdio_al_work;
418 struct sdio_al_work boot_work;
419
420 int is_ready;
421
422 wait_queue_head_t wait_mbox;
423 int ask_mbox;
424 int bootloader_done;
425
426 struct wake_lock wake_lock;
427 int lpm_chan;
428 int is_ok_to_sleep;
429 unsigned long inactivity_time;
430
431 struct timer_list timer;
432 u32 poll_delay_msec;
433 int is_timer_initialized;
434
435 int is_err;
436
437 u32 signature;
438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439 unsigned int is_suspended;
440
441 int flashless_boot_on;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +0300442 int ch_close_supported;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 int state;
444 int (*lpm_callback)(void *, int);
Maya Erez7b1ebd22011-08-20 20:53:24 +0300445
446 int print_after_interrupt;
Maya Erez5795e0d2011-09-12 20:20:06 +0300447
448 u8 *rx_flush_buf;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449};
450
451/*
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +0300452 * Host operation:
453 * lower 16bits are operation code
454 * upper 16bits are operation state
455 */
456#define PEER_OPERATION(op_code , op_state) ((op_code) | ((op_state) << 16))
457#define GET_PEER_OPERATION_CODE(op) ((op) & 0xffff)
458#define GET_PEER_OPERATION_STATE(op) ((op) >> 16)
459
460enum peer_op_code {
461 PEER_OP_CODE_CLOSE = 1
462};
463
464enum peer_op_state {
465 PEER_OP_STATE_INIT = 0,
466 PEER_OP_STATE_START = 1
467};
468
469
470/*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 * On the kernel command line specify
472 * sdio_al.debug_lpm_on=1 to enable the LPM debug messages
473 * By default the LPM debug messages are turned off
474 */
475static int debug_lpm_on;
476module_param(debug_lpm_on, int, 0);
477
478/*
479 * On the kernel command line specify
480 * sdio_al.debug_data_on=1 to enable the DATA debug messages
481 * By default the DATA debug messages are turned off
482 */
483static int debug_data_on;
484module_param(debug_data_on, int, 0);
485
Maya Erez7ad06d82011-10-02 15:47:57 +0200486/*
487 * Enables / disables open close debug messages
488 */
489static int debug_close_on = 1;
490module_param(debug_close_on, int, 0);
491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492/** The driver context */
493static struct sdio_al *sdio_al;
494
495/* Static functions declaration */
496static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
497 int pipe_index, int enable);
498static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
499 int pipe_index, int enable);
500static void sdio_func_irq(struct sdio_func *func);
501static void sdio_al_timer_handler(unsigned long data);
502static int get_min_poll_time_msec(struct sdio_al_device *sdio_al_dev);
503static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot);
504static u32 remove_handled_rx_packet(struct sdio_channel *ch);
505static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
506 int pipe_index, int threshold);
507static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
Maya Erez7b1ebd22011-08-20 20:53:24 +0300508 u32 not_from_int, struct sdio_channel *ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev);
510static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
511 int func_num, int enable, u8 bit_offset);
512static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name);
513static void sdio_al_print_info(void);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +0300514static int sdio_read_internal(struct sdio_channel *ch, void *data, int len);
Maya Erez5795e0d2011-09-12 20:20:06 +0300515static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len);
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200516static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517
518#define SDIO_AL_ERR(func) \
519 do { \
520 printk_once(KERN_ERR MODULE_NAME \
521 ":In Error state, ignore %s\n", \
522 func); \
523 sdio_al_print_info(); \
524 } while (0)
525
526#ifdef CONFIG_DEBUG_FS
527static int debug_info_open(struct inode *inode, struct file *file)
528{
529 file->private_data = inode->i_private;
530 return 0;
531}
532
533static ssize_t debug_info_write(struct file *file,
534 const char __user *buf, size_t count, loff_t *ppos)
535{
536 sdio_al_print_info();
537 return 1;
538}
539
540const struct file_operations debug_info_ops = {
541 .open = debug_info_open,
542 .write = debug_info_write,
543};
544
Krishna Kondaa7af6062011-09-01 18:34:38 -0700545struct debugfs_blob_wrapper sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES + 1];
546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547/*
548*
549* Trigger on/off for debug messages
550* for trigger off the data messages debug level use:
551* echo 0 > /sys/kernel/debugfs/sdio_al/debug_data_on
552* for trigger on the data messages debug level use:
553* echo 1 > /sys/kernel/debugfs/sdio_al/debug_data_on
554* for trigger off the lpm messages debug level use:
555* echo 0 > /sys/kernel/debugfs/sdio_al/debug_lpm_on
556* for trigger on the lpm messages debug level use:
557* echo 1 > /sys/kernel/debugfs/sdio_al/debug_lpm_on
558*/
559static int sdio_al_debugfs_init(void)
560{
Krishna Kondaa7af6062011-09-01 18:34:38 -0700561 int i, blob_errs = 0;
562
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 sdio_al->debug.sdio_al_debug_root = debugfs_create_dir("sdio_al", NULL);
564 if (!sdio_al->debug.sdio_al_debug_root)
565 return -ENOENT;
566
567 sdio_al->debug.sdio_al_debug_lpm_on = debugfs_create_u8("debug_lpm_on",
568 S_IRUGO | S_IWUGO,
569 sdio_al->debug.sdio_al_debug_root,
570 &sdio_al->debug.debug_lpm_on);
571
572 sdio_al->debug.sdio_al_debug_data_on = debugfs_create_u8(
573 "debug_data_on",
574 S_IRUGO | S_IWUGO,
575 sdio_al->debug.sdio_al_debug_root,
576 &sdio_al->debug.debug_data_on);
577
Maya Erez7ad06d82011-10-02 15:47:57 +0200578 sdio_al->debug.sdio_al_debug_close_on = debugfs_create_u8(
579 "debug_close_on",
580 S_IRUGO | S_IWUGO,
581 sdio_al->debug.sdio_al_debug_root,
582 &sdio_al->debug.debug_close_on);
583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584 sdio_al->debug.sdio_al_debug_info = debugfs_create_file(
585 "sdio_debug_info",
586 S_IRUGO | S_IWUGO,
587 sdio_al->debug.sdio_al_debug_root,
588 NULL,
589 &debug_info_ops);
590
Krishna Kondaa7af6062011-09-01 18:34:38 -0700591 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
592 char temp[18];
593
594 scnprintf(temp, 18, "sdio_al_log_dev_%d", i + 1);
595 sdio_al->debug.sdio_al_debug_log_buffers[i] =
596 debugfs_create_blob(temp,
597 S_IRUGO | S_IWUGO,
598 sdio_al->debug.sdio_al_debug_root,
599 &sdio_al_dbgfs_log[i]);
600 }
601
602 sdio_al->debug.sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES] =
603 debugfs_create_blob("sdio_al_gen_log",
604 S_IRUGO | S_IWUGO,
605 sdio_al->debug.sdio_al_debug_root,
606 &sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES]);
607
608 for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i) {
609 if (!sdio_al->debug.sdio_al_debug_log_buffers[i]) {
610 pr_err(MODULE_NAME ": Failed to create debugfs buffer"
611 " entry for "
612 "sdio_al->debug.sdio_al_debug_log_buffers[%d]",
613 i);
614 blob_errs = 1;
615 }
616 }
617
618 if (blob_errs) {
619 for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i)
620 if (sdio_al->debug.sdio_al_debug_log_buffers[i])
621 debugfs_remove(
622 sdio_al->
623 debug.sdio_al_debug_log_buffers[i]);
624 }
625
626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700627 if ((!sdio_al->debug.sdio_al_debug_data_on) &&
628 (!sdio_al->debug.sdio_al_debug_lpm_on) &&
Maya Erez7ad06d82011-10-02 15:47:57 +0200629 (!sdio_al->debug.sdio_al_debug_close_on) &&
Krishna Kondaa7af6062011-09-01 18:34:38 -0700630 (!sdio_al->debug.sdio_al_debug_info) &&
631 blob_errs) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 debugfs_remove(sdio_al->debug.sdio_al_debug_root);
633 sdio_al->debug.sdio_al_debug_root = NULL;
634 return -ENOENT;
635 }
Krishna Kondaa7af6062011-09-01 18:34:38 -0700636
637 sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].data =
638 sdio_al->gen_log.buffer;
639 sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].size =
640 SDIO_AL_DEBUG_LOG_SIZE;
641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642 return 0;
643}
644
645static void sdio_al_debugfs_cleanup(void)
646{
Krishna Kondaa7af6062011-09-01 18:34:38 -0700647 int i;
648
649 debugfs_remove(sdio_al->debug.sdio_al_debug_lpm_on);
650 debugfs_remove(sdio_al->debug.sdio_al_debug_data_on);
Maya Erez7ad06d82011-10-02 15:47:57 +0200651 debugfs_remove(sdio_al->debug.sdio_al_debug_close_on);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652 debugfs_remove(sdio_al->debug.sdio_al_debug_info);
Krishna Kondaa7af6062011-09-01 18:34:38 -0700653
654 for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i)
655 debugfs_remove(sdio_al->debug.sdio_al_debug_log_buffers[i]);
656
657 debugfs_remove(sdio_al->debug.sdio_al_debug_root);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658}
659#endif
660
Krishna Kondaa7af6062011-09-01 18:34:38 -0700661static int sdio_al_log(struct sdio_al_local_log *log, const char *fmt, ...)
662{
663 va_list args;
664 int r;
665 char *tp, *log_buf;
666 unsigned int *log_cur_pos;
667 struct timeval kt;
668 unsigned long flags;
669 static char sdio_al_log_tmp[SDIO_AL_DEBUG_TMP_LOG_SIZE];
670
671 spin_lock_irqsave(&log->log_lock, flags);
672
673 kt = ktime_to_timeval(ktime_get());
674 r = scnprintf(sdio_al_log_tmp, SDIO_AL_DEBUG_TMP_LOG_SIZE,
675 "[%8ld.%6ld] ", kt.tv_sec, kt.tv_usec);
676
677 va_start(args, fmt);
678 r += vscnprintf(&sdio_al_log_tmp[r], (SDIO_AL_DEBUG_TMP_LOG_SIZE - r),
679 fmt, args);
680 va_end(args);
681
682 log_buf = log->buffer;
683 log_cur_pos = &(log->buf_cur_pos);
684
685 for (tp = sdio_al_log_tmp; tp < (sdio_al_log_tmp + r); tp++) {
686 log_buf[(*log_cur_pos)++] = *tp;
687 if ((*log_cur_pos) == SDIO_AL_DEBUG_LOG_SIZE)
688 *log_cur_pos = 0;
689 }
690
691 spin_unlock_irqrestore(&log->log_lock, flags);
692
693 return r;
694}
695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696static int sdio_al_verify_func1(struct sdio_al_device *sdio_al_dev,
697 char const *func)
698{
699 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700700 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
701 "sdio_al_dev\n", func);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702 return -ENODEV;
703 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200704
705 if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
706 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
707 "signature\n", func);
708 return -ENODEV;
709 }
710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700711 if (!sdio_al_dev->card) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700712 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
713 "card\n", func);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700714 return -ENODEV;
715 }
716 if (!sdio_al_dev->card->sdio_func[0]) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700717 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
718 "func1\n", func);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719 return -ENODEV;
720 }
721 return 0;
722}
723
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200724static int sdio_al_claim_mutex(struct sdio_al_device *sdio_al_dev,
725 char const *func)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726{
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200727 if (!sdio_al_dev) {
728 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
729 "device\n", func);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730 return -ENODEV;
731 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200732
733 if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
734 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
735 "device signature\n", func);
736 return -ENODEV;
737 }
738
739 if (!sdio_al_dev->host) {
740 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
741 "host\n", func);
742 return -ENODEV;
743 }
744
745 mmc_claim_host(sdio_al_dev->host);
746
747 return 0;
748}
749
750static int sdio_al_release_mutex(struct sdio_al_device *sdio_al_dev,
751 char const *func)
752{
753 if (!sdio_al_dev) {
754 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
755 "device\n", func);
756 return -ENODEV;
757 }
758
759 if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
760 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
761 "device signature\n", func);
762 return -ENODEV;
763 }
764
765 if (!sdio_al_dev->host) {
766 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
767 "host\n", func);
768 return -ENODEV;
769 }
770
771 mmc_release_host(sdio_al_dev->host);
772
773 return 0;
774}
775
776static int sdio_al_claim_mutex_and_verify_dev(
777 struct sdio_al_device *sdio_al_dev,
778 char const *func)
779{
780 if (sdio_al_claim_mutex(sdio_al_dev, __func__))
781 return -ENODEV;
782
783 if (sdio_al_dev->state != CARD_INSERTED) {
784 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
785 "device state %d\n", func, sdio_al_dev->state);
786 sdio_al_release_mutex(sdio_al_dev, __func__);
787 return -ENODEV;
788 }
789
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790 return 0;
791}
792
793static void sdio_al_get_into_err_state(struct sdio_al_device *sdio_al_dev)
794{
795 if ((!sdio_al) || (!sdio_al_dev))
796 return;
797
798 sdio_al_dev->is_err = true;
799 sdio_al->debug.debug_data_on = 0;
800 sdio_al->debug.debug_lpm_on = 0;
801 sdio_al_print_info();
802}
803
804void sdio_al_register_lpm_cb(void *device_handle,
805 int(*lpm_callback)(void *, int))
806{
807 struct sdio_al_device *sdio_al_dev =
808 (struct sdio_al_device *) device_handle;
809
810 if (!sdio_al_dev) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700811 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - "
812 "device_handle is NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700813 return;
814 }
815
816 if (lpm_callback) {
817 sdio_al_dev->lpm_callback = lpm_callback;
818 lpm_callback((void *)sdio_al_dev,
819 sdio_al_dev->is_ok_to_sleep);
820 }
Krishna Kondaa7af6062011-09-01 18:34:38 -0700821
822 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
823 "registered for wakeup callback\n", __func__,
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200824 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825}
826
827void sdio_al_unregister_lpm_cb(void *device_handle)
828{
829 struct sdio_al_device *sdio_al_dev =
830 (struct sdio_al_device *) device_handle;
831
832 if (!sdio_al_dev) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700833 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - "
834 "device_handle is NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835 return;
836 }
837
838 sdio_al_dev->lpm_callback = NULL;
Krishna Kondaa7af6062011-09-01 18:34:38 -0700839 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
840 "unregister for wakeup callback\n", __func__,
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200841 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700842}
843
844static void sdio_al_vote_for_sleep(struct sdio_al_device *sdio_al_dev,
845 int is_vote_for_sleep)
846{
847 pr_debug(MODULE_NAME ": %s()", __func__);
848
Yaniv Gardi3e327762011-07-27 11:11:04 +0300849 if (!sdio_al_dev) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700850 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - sdio_al_dev"
851 " is NULL\n", __func__);
Yaniv Gardi3e327762011-07-27 11:11:04 +0300852 return;
853 }
854
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700855 if (is_vote_for_sleep) {
Maya Erez7b1ebd22011-08-20 20:53:24 +0300856 pr_debug(MODULE_NAME ": %s - sdio vote for Sleep", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700857 wake_unlock(&sdio_al_dev->wake_lock);
858 } else {
Maya Erez7b1ebd22011-08-20 20:53:24 +0300859 pr_debug(MODULE_NAME ": %s - sdio vote against sleep",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860 __func__);
861 wake_lock(&sdio_al_dev->wake_lock);
862 }
863
864 if (sdio_al_dev->lpm_callback != NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700865 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - "
866 "is_vote_for_sleep=%d for card#%d, "
867 "calling callback...", __func__,
868 is_vote_for_sleep,
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200869 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870 sdio_al_dev->lpm_callback((void *)sdio_al_dev,
871 is_vote_for_sleep);
872 }
873}
874
875/**
876 * Write SDIO-Client lpm information
877 * Should only be called with host claimed.
878 */
879static int write_lpm_info(struct sdio_al_device *sdio_al_dev)
880{
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -0700881 struct sdio_func *lpm_func = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700882 int offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
883 sizeof(struct peer_sdioc_channel_config) *
884 sdio_al_dev->lpm_chan+
885 offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
886 int ret;
887
888 if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700889 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
890 "lpm_chan for card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200891 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 return -EINVAL;
893 }
894
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -0700895 if (!sdio_al_dev->card ||
896 !sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1]) {
897 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
898 ": NULL card or lpm_func\n");
899 return -ENODEV;
900 }
901 lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1];
902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 pr_debug(MODULE_NAME ":write_lpm_info is_ok_to_sleep=%d, device %d\n",
904 sdio_al_dev->is_ok_to_sleep,
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200905 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906
907 ret = sdio_memcpy_toio(lpm_func, SDIOC_SW_MAILBOX_ADDR+offset,
908 &sdio_al_dev->is_ok_to_sleep, sizeof(u32));
909 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700910 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
911 "write lpm info for card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200912 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913 return ret;
914 }
915
916 return 0;
917}
918
919/* Set inactivity counter to intial value to allow clients come up */
920static inline void start_inactive_time(struct sdio_al_device *sdio_al_dev)
921{
922 sdio_al_dev->inactivity_time = jiffies +
923 msecs_to_jiffies(INITIAL_INACTIVITY_TIME_MSEC);
924}
925
926static inline void restart_inactive_time(struct sdio_al_device *sdio_al_dev)
927{
928 sdio_al_dev->inactivity_time = jiffies +
929 msecs_to_jiffies(INACTIVITY_TIME_MSEC);
930}
931
932static inline int is_inactive_time_expired(struct sdio_al_device *sdio_al_dev)
933{
934 return time_after(jiffies, sdio_al_dev->inactivity_time);
935}
936
937
938static int is_user_irq_enabled(struct sdio_al_device *sdio_al_dev,
939 int func_num)
940{
941 int ret = 0;
942 struct sdio_func *func1;
943 u32 user_irq = 0;
944 u32 addr = 0;
945 u32 offset = 0;
946 u32 masked_user_irq = 0;
947
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200948 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700949 return 0;
950 func1 = sdio_al_dev->card->sdio_func[0];
951
952 if (func_num < 4) {
953 addr = FUNC_1_4_USER_IRQ_ADDR;
954 offset = func_num * 8;
955 } else {
956 addr = FUNC_5_7_USER_IRQ_ADDR;
957 offset = (func_num - 4) * 8;
958 }
959
960 user_irq = sdio_readl(func1, addr, &ret);
961 if (ret) {
962 pr_debug(MODULE_NAME ":read_user_irq fail\n");
963 return 0;
964 }
965
966 masked_user_irq = (user_irq >> offset) && 0xFF;
967 if (masked_user_irq == 0x1) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700968 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":user_irq "
969 "enabled\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970 return 1;
971 }
972
973 return 0;
974}
975
976static void sdio_al_sleep(struct sdio_al_device *sdio_al_dev,
977 struct mmc_host *host)
978{
979 int i;
980
981 /* Go to sleep */
Maya Erez7b1ebd22011-08-20 20:53:24 +0300982 pr_debug(MODULE_NAME ":Inactivity timer expired."
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700983 " Going to sleep\n");
984 /* Stop mailbox timer */
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200985 stop_and_del_timer(sdio_al_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 /* Make sure we get interrupt for non-packet-mode right away */
987 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
988 struct sdio_channel *ch = &sdio_al_dev->channel[i];
Maya Erez5795e0d2011-09-12 20:20:06 +0300989 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
990 (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +0300991 pr_debug(MODULE_NAME ":continue for channel %s in"
992 " state %d\n", ch->name, ch->state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 continue;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +0300994 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 if (ch->is_packet_mode == false) {
Maya Erez3eb7d4c2011-10-17 15:08:42 +0200996 ch->read_threshold = LOW_LATENCY_THRESHOLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 set_pipe_threshold(sdio_al_dev,
998 ch->rx_pipe_index,
999 ch->read_threshold);
1000 }
1001 }
Maya Erezfd915312011-07-14 13:45:34 +03001002 /* Prevent modem to go to sleep until we get the PROG_DONE on
1003 the dummy CMD52 */
Maya Erez86cebda2011-10-11 11:13:40 +02001004 msmsdcc_set_pwrsave(sdio_al_dev->host, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 /* Mark HOST_OK_TOSLEEP */
1006 sdio_al_dev->is_ok_to_sleep = 1;
1007 write_lpm_info(sdio_al_dev);
1008
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 msmsdcc_lpm_enable(host);
Krishna Kondaa7af6062011-09-01 18:34:38 -07001010 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Finished sleep sequence"
1011 " for card %d. Sleep now.\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001012 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 /* Release wakelock */
1014 sdio_al_vote_for_sleep(sdio_al_dev, 1);
1015}
1016
1017
1018/**
1019 * Read SDIO-Client Mailbox from Function#1.thresh_pipe
1020 *
1021 * The mailbox contain the bytes available per pipe,
1022 * and the End-Of-Transfer indication per pipe (if available).
1023 *
1024 * WARNING: Each time the Mailbox is read from the client, the
1025 * read_bytes_avail is incremented with another pending
1026 * transfer. Therefore, a pending rx-packet should be added to a
1027 * list before the next read of the mailbox.
1028 *
1029 * This function should run from a workqueue context since it
1030 * notifies the clients.
1031 *
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001032 * This function assumes that sdio_al_claim_mutex was called before
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 * calling it.
1034 *
1035 */
1036static int read_mailbox(struct sdio_al_device *sdio_al_dev, int from_isr)
1037{
1038 int ret;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001039 struct sdio_func *func1 = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040 struct sdio_mailbox *mailbox = sdio_al_dev->mailbox;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001041 struct mmc_host *host = sdio_al_dev->host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 u32 new_write_avail = 0;
1043 u32 old_write_avail = 0;
1044 u32 any_read_avail = 0;
1045 u32 any_write_pending = 0;
1046 int i;
1047 u32 rx_notify_bitmask = 0;
1048 u32 tx_notify_bitmask = 0;
1049 u32 eot_pipe = 0;
1050 u32 thresh_pipe = 0;
1051 u32 overflow_pipe = 0;
1052 u32 underflow_pipe = 0;
1053 u32 thresh_intr_mask = 0;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001054 int is_closing = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055
1056 if (sdio_al_dev->is_err) {
1057 SDIO_AL_ERR(__func__);
1058 return 0;
1059 }
1060
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001061 if (sdio_al_verify_func1(sdio_al_dev, __func__))
1062 return -ENODEV;
1063 func1 = sdio_al_dev->card->sdio_func[0];
1064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065 pr_debug(MODULE_NAME ":start %s from_isr = %d for card %d.\n"
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001066 , __func__, from_isr, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067
1068 pr_debug(MODULE_NAME ":before sdio_memcpy_fromio.\n");
Maya Erez320a7ca2011-08-03 09:41:27 +03001069 memset(mailbox, 0, sizeof(struct sdio_mailbox));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070 ret = sdio_memcpy_fromio(func1, mailbox,
1071 HW_MAILBOX_ADDR, sizeof(*mailbox));
1072 pr_debug(MODULE_NAME ":after sdio_memcpy_fromio.\n");
Maya Erez320a7ca2011-08-03 09:41:27 +03001073 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001074 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to read "
1075 "Mailbox for card %d, goto error state\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001076 sdio_al_dev->host->index);
Maya Erez320a7ca2011-08-03 09:41:27 +03001077 sdio_al_get_into_err_state(sdio_al_dev);
Maya Erez320a7ca2011-08-03 09:41:27 +03001078 goto exit_err;
1079 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001080
1081 eot_pipe = (mailbox->eot_pipe_0_7) |
1082 (mailbox->eot_pipe_8_15<<8);
1083 thresh_pipe = (mailbox->thresh_above_limit_pipe_0_7) |
1084 (mailbox->thresh_above_limit_pipe_8_15<<8);
1085
1086 overflow_pipe = (mailbox->overflow_pipe_0_7) |
1087 (mailbox->overflow_pipe_8_15<<8);
1088 underflow_pipe = mailbox->underflow_pipe_0_7 |
1089 (mailbox->underflow_pipe_8_15<<8);
1090 thresh_intr_mask =
1091 (mailbox->mask_thresh_above_limit_pipe_0_7) |
1092 (mailbox->mask_thresh_above_limit_pipe_8_15<<8);
1093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 if (overflow_pipe || underflow_pipe)
Krishna Kondaa7af6062011-09-01 18:34:38 -07001095 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Mailbox ERROR "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096 "overflow=0x%x, underflow=0x%x\n",
1097 overflow_pipe, underflow_pipe);
1098
1099 /* In case of modem reset we would like to read the daya from the modem
1100 to clear the interrupts but do not process it */
1101 if (sdio_al_dev->state != CARD_INSERTED) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001102 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_device"
1103 " (card %d) is in invalid state %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001104 sdio_al_dev->host->index,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 sdio_al_dev->state);
1106 return -ENODEV;
1107 }
1108
1109 pr_debug(MODULE_NAME ":card %d: eot=0x%x, thresh=0x%x\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001110 sdio_al_dev->host->index,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111 eot_pipe, thresh_pipe);
1112
1113 /* Scan for Rx Packets available and update read available bytes */
1114 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
1115 struct sdio_channel *ch = &sdio_al_dev->channel[i];
1116 u32 old_read_avail;
1117 u32 read_avail;
1118 u32 new_packet_size = 0;
1119
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001120 if (ch->state == SDIO_CHANNEL_STATE_CLOSING)
1121 is_closing = true; /* used to prevent sleep */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122
1123 old_read_avail = ch->read_avail;
1124 read_avail = mailbox->pipe_bytes_avail[ch->rx_pipe_index];
1125
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001126 if ((ch->state == SDIO_CHANNEL_STATE_CLOSED) &&
1127 (read_avail > 0)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001128 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1129 ":%s: Invalid read_avail 0x%x, for CLOSED ch %s\n",
Maya Erez5795e0d2011-09-12 20:20:06 +03001130 __func__, read_avail, ch->name);
1131 sdio_read_from_closed_ch(ch, read_avail);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001132 }
1133 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
1134 (ch->state != SDIO_CHANNEL_STATE_CLOSING))
1135 continue;
1136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 if (read_avail > INVALID_DATA_AVAILABLE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001138 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 ":Invalid read_avail 0x%x for pipe %d\n",
1140 read_avail, ch->rx_pipe_index);
1141 continue;
1142 }
1143 any_read_avail |= read_avail | old_read_avail;
1144 ch->statistics.last_any_read_avail = any_read_avail;
1145 ch->statistics.last_read_avail = read_avail;
1146 ch->statistics.last_old_read_avail = old_read_avail;
1147
Maya Erez8ed0a9a2011-07-19 14:46:53 +03001148 if (ch->is_packet_mode) {
Maya Erez7b1ebd22011-08-20 20:53:24 +03001149 if ((eot_pipe & (1<<ch->rx_pipe_index)) &&
1150 sdio_al_dev->print_after_interrupt) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001151 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
1152 ":Interrupt on ch %s, "
1153 "card %d", ch->name,
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001154 sdio_al_dev->host->index);
Maya Erez7b1ebd22011-08-20 20:53:24 +03001155 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156 new_packet_size = check_pending_rx_packet(ch, eot_pipe);
Maya Erez8ed0a9a2011-07-19 14:46:53 +03001157 } else {
Maya Erez7b1ebd22011-08-20 20:53:24 +03001158 if ((thresh_pipe & (1<<ch->rx_pipe_index)) &&
1159 sdio_al_dev->print_after_interrupt) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001160 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
1161 ":Interrupt on ch %s, "
1162 "card %d", ch->name,
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001163 sdio_al_dev->host->index);
Maya Erez7b1ebd22011-08-20 20:53:24 +03001164 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165 ch->read_avail = read_avail;
Maya Erez3eb7d4c2011-10-17 15:08:42 +02001166
1167 /*
1168 * Restore default thresh for non packet channels.
1169 * in case it IS low latency channel then read_threshold
1170 * and def_read_threshold are both
1171 * LOW_LATENCY_THRESHOLD
1172 */
Maya Erez8ed0a9a2011-07-19 14:46:53 +03001173 if ((ch->read_threshold != ch->def_read_threshold) &&
1174 (read_avail >= ch->threshold_change_cnt)) {
Maya Erez3eb7d4c2011-10-17 15:08:42 +02001175 if (!ch->is_low_latency_ch) {
1176 ch->read_threshold =
1177 ch->def_read_threshold;
1178 set_pipe_threshold(sdio_al_dev,
1179 ch->rx_pipe_index,
1180 ch->read_threshold);
1181 }
Maya Erez8ed0a9a2011-07-19 14:46:53 +03001182 }
1183 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184
1185 if ((ch->is_packet_mode) && (new_packet_size > 0)) {
1186 rx_notify_bitmask |= (1<<ch->num);
1187 ch->statistics.total_notifs++;
1188 }
1189
1190 if ((!ch->is_packet_mode) && (ch->read_avail > 0) &&
1191 (old_read_avail == 0)) {
1192 rx_notify_bitmask |= (1<<ch->num);
1193 ch->statistics.total_notifs++;
1194 }
1195 }
Maya Erez7b1ebd22011-08-20 20:53:24 +03001196 sdio_al_dev->print_after_interrupt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197
1198 /* Update Write available */
1199 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
1200 struct sdio_channel *ch = &sdio_al_dev->channel[i];
1201
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001202 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
1203 (ch->state != SDIO_CHANNEL_STATE_CLOSING))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204 continue;
1205
1206 new_write_avail = mailbox->pipe_bytes_avail[ch->tx_pipe_index];
1207
1208 if (new_write_avail > INVALID_DATA_AVAILABLE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001209 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210 ":Invalid write_avail 0x%x for pipe %d\n",
1211 new_write_avail, ch->tx_pipe_index);
1212 continue;
1213 }
1214
1215 old_write_avail = ch->write_avail;
1216 ch->write_avail = new_write_avail;
1217
1218 if ((old_write_avail <= ch->min_write_avail) &&
1219 (new_write_avail >= ch->min_write_avail))
1220 tx_notify_bitmask |= (1<<ch->num);
1221
1222 /* There is not enough write avail for this channel.
1223 We need to keep reading mailbox to wait for the appropriate
1224 write avail and cannot sleep. Ignore SMEM channel that has
1225 only one direction. */
Venkat Gopalakrishnan16eec752011-11-11 16:32:54 -08001226 if (strncmp(ch->name, "SDIO_SMEM", CHANNEL_NAME_SIZE))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 any_write_pending |=
1228 (new_write_avail < ch->ch_config.max_tx_threshold);
1229 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001230 /* notify clients */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001231 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
1232 struct sdio_channel *ch = &sdio_al_dev->channel[i];
1233
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001234 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) ||
1235 (ch->notify == NULL))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 continue;
1237
1238 if (rx_notify_bitmask & (1<<ch->num))
1239 ch->notify(ch->priv,
1240 SDIO_EVENT_DATA_READ_AVAIL);
1241
1242 if (tx_notify_bitmask & (1<<ch->num))
1243 ch->notify(ch->priv,
1244 SDIO_EVENT_DATA_WRITE_AVAIL);
1245 }
1246
1247
1248 if ((rx_notify_bitmask == 0) && (tx_notify_bitmask == 0) &&
1249 !any_read_avail && !any_write_pending) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001250 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Nothing to "
1251 "Notify for card %d, is_closing=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001252 sdio_al_dev->host->index, is_closing);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001253 if (is_closing)
1254 restart_inactive_time(sdio_al_dev);
1255 else if (is_inactive_time_expired(sdio_al_dev))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 sdio_al_sleep(sdio_al_dev, host);
1257 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001258 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Notify bitmask"
1259 " for card %d rx=0x%x, tx=0x%x.\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001260 sdio_al_dev->host->index,
Krishna Kondaa7af6062011-09-01 18:34:38 -07001261 rx_notify_bitmask, tx_notify_bitmask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 /* Restart inactivity timer if any activity on the channel */
1263 restart_inactive_time(sdio_al_dev);
1264 }
1265
1266 pr_debug(MODULE_NAME ":end %s.\n", __func__);
1267
1268exit_err:
1269 return ret;
1270}
1271
1272/**
1273 * Check pending rx packet when reading the mailbox.
1274 */
1275static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot)
1276{
1277 u32 rx_pending;
1278 u32 rx_avail;
1279 u32 new_packet_size = 0;
1280 struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
1281
1282
1283 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001284 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
1285 " for channel %s\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 return -EINVAL;
1287 }
1288
1289 mutex_lock(&ch->ch_lock);
1290
1291 rx_pending = ch->rx_pending_bytes;
1292 rx_avail = sdio_al_dev->mailbox->pipe_bytes_avail[ch->rx_pipe_index];
1293
1294 pr_debug(MODULE_NAME ":pipe %d of card %d rx_avail=0x%x, "
1295 "rx_pending=0x%x\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001296 ch->rx_pipe_index, sdio_al_dev->host->index, rx_avail,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297 rx_pending);
1298
1299
1300 /* new packet detected */
1301 if (eot & (1<<ch->rx_pipe_index)) {
1302 struct rx_packet_size *p = NULL;
1303 new_packet_size = rx_avail - rx_pending;
1304
1305 if ((rx_avail <= rx_pending)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001306 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1307 ": Invalid new packet size."
1308 " rx_avail=%d.\n", rx_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 new_packet_size = 0;
1310 goto exit_err;
1311 }
1312
1313 p = kzalloc(sizeof(*p), GFP_KERNEL);
Maya Erezd9cc2292011-08-04 09:20:31 +03001314 if (p == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001315 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1316 ": failed to allocate item for "
1317 "rx_pending list. rx_avail=%d, "
1318 "rx_pending=%d.\n",
1319 rx_avail, rx_pending);
Maya Erezd9cc2292011-08-04 09:20:31 +03001320 new_packet_size = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321 goto exit_err;
Maya Erezd9cc2292011-08-04 09:20:31 +03001322 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001323 p->size = new_packet_size;
1324 /* Add new packet as last */
1325 list_add_tail(&p->list, &ch->rx_size_list_head);
1326 ch->rx_pending_bytes += new_packet_size;
1327
1328 if (ch->read_avail == 0)
1329 ch->read_avail = new_packet_size;
1330 }
1331
1332exit_err:
1333 mutex_unlock(&ch->ch_lock);
1334
1335 return new_packet_size;
1336}
1337
1338
1339
1340/**
1341 * Remove first pending packet from the list.
1342 */
1343static u32 remove_handled_rx_packet(struct sdio_channel *ch)
1344{
1345 struct rx_packet_size *p = NULL;
1346
1347 mutex_lock(&ch->ch_lock);
1348
1349 ch->rx_pending_bytes -= ch->read_avail;
1350
1351 if (!list_empty(&ch->rx_size_list_head)) {
1352 p = list_first_entry(&ch->rx_size_list_head,
1353 struct rx_packet_size, list);
1354 list_del(&p->list);
1355 kfree(p);
Maya Erezd9cc2292011-08-04 09:20:31 +03001356 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001357 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: ch "
1358 "%s: unexpected empty list!!\n",
1359 __func__, ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360 }
1361
1362 if (list_empty(&ch->rx_size_list_head)) {
1363 ch->read_avail = 0;
1364 } else {
1365 p = list_first_entry(&ch->rx_size_list_head,
1366 struct rx_packet_size, list);
1367 ch->read_avail = p->size;
1368 }
1369
1370 mutex_unlock(&ch->ch_lock);
1371
1372 return ch->read_avail;
1373}
1374
1375
1376/**
1377 * Bootloader worker function.
1378 *
1379 * @note: clear the bootloader_done flag only after reading the
1380 * mailbox, to ignore more requests while reading the mailbox.
1381 */
1382static void boot_worker(struct work_struct *work)
1383{
1384 int ret = 0;
1385 int func_num = 0;
1386 int i;
1387 struct sdio_al_device *sdio_al_dev = NULL;
1388 struct sdio_al_work *sdio_al_work = container_of(work,
1389 struct sdio_al_work,
1390 work);
1391
1392 if (sdio_al_work == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001393 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
1394 "sdio_al_work\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 return;
1396 }
1397
1398 sdio_al_dev = sdio_al_work->sdio_al_dev;
1399 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001400 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
1401 "sdio_al_dev\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 return;
1403 }
Krishna Kondaa7af6062011-09-01 18:34:38 -07001404 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Bootloader Worker Started"
1405 ", wait for bootloader_done event..\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406 wait_event(sdio_al_dev->wait_mbox,
1407 sdio_al_dev->bootloader_done);
Krishna Kondaa7af6062011-09-01 18:34:38 -07001408 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Got bootloader_done "
1409 "event..\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410 /* Do polling until MDM is up */
1411 for (i = 0; i < 5000; ++i) {
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001412 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001414 if (is_user_irq_enabled(sdio_al_dev, func_num)) {
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001415 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416 sdio_al_dev->bootloader_done = 0;
1417 ret = sdio_al_client_setup(sdio_al_dev);
1418 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001419 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1420 ": sdio_al_client_setup failed, "
1421 "for card %d ret=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001422 sdio_al_dev->host->index, ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423 sdio_al_get_into_err_state(sdio_al_dev);
1424 }
1425 goto done;
1426 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001427 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 msleep(100);
1429 }
Krishna Kondaa7af6062011-09-01 18:34:38 -07001430 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Timeout waiting for "
1431 "user_irq for card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001432 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433 sdio_al_get_into_err_state(sdio_al_dev);
1434
1435done:
1436 pr_debug(MODULE_NAME ":Boot Worker for card %d Exit!\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001437 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438}
1439
1440/**
1441 * Worker function.
1442 *
1443 * @note: clear the ask_mbox flag only after
1444 * reading the mailbox, to ignore more requests while
1445 * reading the mailbox.
1446 */
1447static void worker(struct work_struct *work)
1448{
1449 int ret = 0;
1450 struct sdio_al_device *sdio_al_dev = NULL;
1451 struct sdio_al_work *sdio_al_work = container_of(work,
1452 struct sdio_al_work,
1453 work);
1454 if (sdio_al_work == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001455 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
1456 "sdio_al_work\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 return;
1458 }
1459
1460 sdio_al_dev = sdio_al_work->sdio_al_dev;
1461 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001462 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
1463 "sdio_al_dev\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464 return;
1465 }
1466 pr_debug(MODULE_NAME ":Worker Started..\n");
1467 while ((sdio_al_dev->is_ready) && (ret == 0)) {
1468 pr_debug(MODULE_NAME ":Wait for read mailbox request..\n");
1469 wait_event(sdio_al_dev->wait_mbox, sdio_al_dev->ask_mbox);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470 if (!sdio_al_dev->is_ready)
1471 break;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001472 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
1473 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001474 if (sdio_al_dev->is_ok_to_sleep) {
Maya Erez7b1ebd22011-08-20 20:53:24 +03001475 ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476 if (ret) {
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001477 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478 return;
1479 }
1480 }
1481 ret = read_mailbox(sdio_al_dev, false);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001482 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483 sdio_al_dev->ask_mbox = false;
1484 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486 pr_debug(MODULE_NAME ":Worker Exit!\n");
1487}
1488
1489/**
1490 * Write command using CMD54 rather than CMD53.
1491 * Writing with CMD54 generate EOT interrupt at the
1492 * SDIO-Client.
1493 * Based on mmc_io_rw_extended()
1494 */
1495static int sdio_write_cmd54(struct mmc_card *card, unsigned fn,
1496 unsigned addr, const u8 *buf,
1497 unsigned blocks, unsigned blksz)
1498{
1499 struct mmc_request mrq;
1500 struct mmc_command cmd;
1501 struct mmc_data data;
1502 struct scatterlist sg;
1503 int incr_addr = 1; /* MUST */
1504 int write = 1;
1505
1506 BUG_ON(!card);
1507 BUG_ON(fn > 7);
1508 BUG_ON(blocks == 1 && blksz > 512);
1509 WARN_ON(blocks == 0);
1510 WARN_ON(blksz == 0);
1511
1512 write = true;
1513 pr_debug(MODULE_NAME ":sdio_write_cmd54()"
1514 "fn=%d,buf=0x%x,blocks=%d,blksz=%d\n",
1515 fn, (u32) buf, blocks, blksz);
1516
1517 memset(&mrq, 0, sizeof(struct mmc_request));
1518 memset(&cmd, 0, sizeof(struct mmc_command));
1519 memset(&data, 0, sizeof(struct mmc_data));
1520
1521 mrq.cmd = &cmd;
1522 mrq.data = &data;
1523
1524 cmd.opcode = SD_IO_RW_EXTENDED_QCOM;
1525
1526 cmd.arg = write ? 0x80000000 : 0x00000000;
1527 cmd.arg |= fn << 28;
1528 cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
1529 cmd.arg |= addr << 9;
1530 if (blocks == 1 && blksz <= 512)
1531 cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
1532 else
1533 cmd.arg |= 0x08000000 | blocks; /* block mode */
1534 cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
1535
1536 data.blksz = blksz;
1537 data.blocks = blocks;
1538 data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
1539 data.sg = &sg;
1540 data.sg_len = 1;
1541
1542 sg_init_one(&sg, buf, blksz * blocks);
1543
1544 mmc_set_data_timeout(&data, card);
1545
1546 mmc_wait_for_req(card->host, &mrq);
1547
1548 if (cmd.error)
1549 return cmd.error;
1550 if (data.error)
1551 return data.error;
1552
1553 if (mmc_host_is_spi(card->host)) {
1554 /* host driver already reported errors */
1555 } else {
1556 if (cmd.resp[0] & R5_ERROR) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001557 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
1558 ":%s: R5_ERROR for card %d",
1559 __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 return -EIO;
1561 }
1562 if (cmd.resp[0] & R5_FUNCTION_NUMBER) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001563 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
1564 ":%s: R5_FUNCTION_NUMBER for card %d",
1565 __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 return -EINVAL;
1567 }
1568 if (cmd.resp[0] & R5_OUT_OF_RANGE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001569 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
1570 ":%s: R5_OUT_OF_RANGE for card %d",
1571 __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572 return -ERANGE;
1573 }
1574 }
1575
1576 return 0;
1577}
1578
1579
1580/**
1581 * Write data to channel.
1582 * Handle different data size types.
1583 *
1584 */
1585static int sdio_ch_write(struct sdio_channel *ch, const u8 *buf, u32 len)
1586{
1587 int ret = 0;
1588 unsigned blksz = ch->func->cur_blksize;
1589 int blocks = len / blksz;
1590 int remain_bytes = len % blksz;
1591 struct mmc_card *card = NULL;
1592 u32 fn = ch->func->num;
1593
Krishna Kondaa7af6062011-09-01 18:34:38 -07001594 if (!ch) {
1595 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
1596 "channel\n", __func__);
1597 return -ENODEV;
1598 }
1599
1600 if (!ch->sdio_al_dev) {
1601 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
1602 "sdio_al_dev\n", __func__);
1603 return -ENODEV;
1604 }
1605
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 if (len == 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001607 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":channel "
1608 "%s trying to write 0 bytes\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 return -EINVAL;
1610 }
1611
1612 card = ch->func->card;
1613
1614 if (remain_bytes) {
1615 /* CMD53 */
1616 if (blocks) {
1617 ret = sdio_memcpy_toio(ch->func, PIPE_TX_FIFO_ADDR,
1618 (void *) buf, blocks*blksz);
1619 if (ret != 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001620 sdio_al_loge(ch->sdio_al_dev->dev_log,
1621 MODULE_NAME ":%s: sdio_memcpy_toio "
1622 "failed for channel %s\n",
1623 __func__, ch->name);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001624 sdio_al_get_into_err_state(ch->sdio_al_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001625 return ret;
1626 }
1627 }
1628
1629 buf += (blocks*blksz);
1630
1631 ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
1632 buf, 1, remain_bytes);
1633 } else {
1634 ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
1635 buf, blocks, blksz);
1636 }
1637
1638 if (ret != 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001639 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
1640 "sdio_write_cmd54 failed for channel %s\n",
1641 __func__, ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 ch->sdio_al_dev->is_err = true;
1643 return ret;
1644 }
1645
1646 return ret;
1647}
1648
1649static int sdio_al_bootloader_completed(void)
1650{
1651 int i;
1652
1653 pr_debug(MODULE_NAME ":sdio_al_bootloader_completed was called\n");
1654
1655 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
1656 struct sdio_al_device *dev = NULL;
1657 if (sdio_al->devices[i] == NULL)
1658 continue;
1659 dev = sdio_al->devices[i];
1660 dev->bootloader_done = 1;
1661 wake_up(&dev->wait_mbox);
1662 }
1663
1664 return 0;
1665}
1666
1667static int sdio_al_wait_for_bootloader_comp(struct sdio_al_device *sdio_al_dev)
1668{
1669 int ret = 0;
1670
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001671 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674 /*
1675 * Enable function 0 interrupt mask to allow 9k to raise this interrupt
1676 * in power-up. When sdio_downloader will notify its completion
1677 * we will poll on this interrupt to wait for 9k power-up
1678 */
1679 ret = enable_mask_irq(sdio_al_dev, 0, 1, 0);
1680 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001681 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1682 ": Enable_mask_irq for card %d failed, "
1683 "ret=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001684 sdio_al_dev->host->index, ret);
1685 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 return ret;
1687 }
1688
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001689 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001690
1691 /*
1692 * Start bootloader worker that will wait for the bootloader
1693 * completion
1694 */
1695 sdio_al_dev->boot_work.sdio_al_dev = sdio_al_dev;
1696 INIT_WORK(&sdio_al_dev->boot_work.work, boot_worker);
1697 sdio_al_dev->bootloader_done = 0;
1698 queue_work(sdio_al_dev->workqueue, &sdio_al_dev->boot_work.work);
1699
1700 return 0;
1701}
1702
1703static int sdio_al_bootloader_setup(void)
1704{
1705 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001706 struct sdio_al_device *bootloader_dev = sdio_al->bootloader_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001707 struct sdio_func *func1 = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001708
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001709 if (sdio_al_claim_mutex_and_verify_dev(bootloader_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001710 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 if (bootloader_dev->flashless_boot_on) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001713 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":Already "
1714 "in boot process.\n");
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001715 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001716 return 0;
1717 }
1718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719 bootloader_dev->sdioc_boot_sw_header
1720 = kzalloc(sizeof(*bootloader_dev->sdioc_boot_sw_header),
1721 GFP_KERNEL);
1722 if (bootloader_dev->sdioc_boot_sw_header == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001723 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
1724 "allocate sdioc boot sw header.\n");
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001725 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001726 return -ENOMEM;
1727 }
1728
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001729 if (sdio_al_verify_func1(bootloader_dev, __func__)) {
1730 sdio_al_release_mutex(bootloader_dev, __func__);
1731 goto exit_err;
1732 }
1733 func1 = bootloader_dev->card->sdio_func[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734
1735 ret = sdio_memcpy_fromio(func1,
1736 bootloader_dev->sdioc_boot_sw_header,
1737 SDIOC_SW_HEADER_ADDR,
1738 sizeof(struct peer_sdioc_boot_sw_header));
1739 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001740 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
1741 "read sdioc boot sw header.\n");
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001742 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743 goto exit_err;
1744 }
1745
1746 if (bootloader_dev->sdioc_boot_sw_header->signature !=
1747 (u32) PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001748 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":invalid "
1749 "mailbox signature 0x%x.\n",
1750 bootloader_dev->sdioc_boot_sw_header->signature);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001751 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752 ret = -EINVAL;
1753 goto exit_err;
1754 }
1755
1756 /* Upper byte has to be equal - no backward compatibility for unequal */
1757 if ((bootloader_dev->sdioc_boot_sw_header->version >> 16) !=
1758 (sdio_al->pdata->peer_sdioc_boot_version_major)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001759 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ": HOST(0x%x)"
1760 " and CLIENT(0x%x) SDIO_AL BOOT VERSION don't match\n",
1761 ((sdio_al->pdata->peer_sdioc_boot_version_major<<16)+
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 sdio_al->pdata->peer_sdioc_boot_version_minor),
Krishna Kondaa7af6062011-09-01 18:34:38 -07001763 bootloader_dev->sdioc_boot_sw_header->version);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001764 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001765 ret = -EIO;
1766 goto exit_err;
1767 }
1768
Krishna Kondaa7af6062011-09-01 18:34:38 -07001769 sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ": SDIOC BOOT SW "
1770 "version 0x%x\n",
1771 bootloader_dev->sdioc_boot_sw_header->version);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772
1773 bootloader_dev->flashless_boot_on = true;
1774
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001775 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776
1777 ret = sdio_al_wait_for_bootloader_comp(bootloader_dev);
1778 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001779 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
1780 ": sdio_al_wait_for_bootloader_comp failed, "
1781 "err=%d\n", ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001782 goto exit_err;
1783 }
1784
1785 ret = sdio_downloader_setup(bootloader_dev->card, 1,
1786 bootloader_dev->sdioc_boot_sw_header->boot_ch_num,
1787 sdio_al_bootloader_completed);
1788
1789 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001790 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
1791 ": sdio_downloader_setup failed, err=%d\n", ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 goto exit_err;
1793 }
1794
Krishna Kondaa7af6062011-09-01 18:34:38 -07001795 sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ":In Flashless boot,"
1796 " waiting for its completion\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001797
1798
1799exit_err:
Krishna Kondaa7af6062011-09-01 18:34:38 -07001800 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":free "
1801 "sdioc_boot_sw_header.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 kfree(bootloader_dev->sdioc_boot_sw_header);
1803 bootloader_dev->sdioc_boot_sw_header = NULL;
1804 bootloader_dev = NULL;
1805
1806 return ret;
1807}
1808
1809
1810/**
1811 * Read SDIO-Client software header
1812 *
1813 */
1814static int read_sdioc_software_header(struct sdio_al_device *sdio_al_dev,
1815 struct peer_sdioc_sw_header *header)
1816{
1817 int ret;
1818 int i;
1819 int test_version = 0;
1820 int sdioc_test_version = 0;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001821 struct sdio_func *func1 = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001822
1823 pr_debug(MODULE_NAME ":reading sdioc sw header.\n");
1824
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001825 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826 return -ENODEV;
1827
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001828 func1 = sdio_al_dev->card->sdio_func[0];
1829
1830 ret = sdio_memcpy_fromio(func1, header,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001831 SDIOC_SW_HEADER_ADDR, sizeof(*header));
1832 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001833 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
1834 "sdioc sw header.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835 goto exit_err;
1836 }
1837
1838 if (header->signature == (u32)PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001839 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
1840 "unittest signature. 0x%x\n",
1841 header->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 sdio_al->unittest_mode = true;
1843 /* Verify test code compatibility with the modem */
1844 sdioc_test_version = (header->version & 0xFF00) >> 8;
1845 test_version = sdio_al->pdata->peer_sdioc_version_minor >> 8;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001846 if (test_version != sdioc_test_version) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001847 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1848 ": HOST(0x%x) and CLIENT(0x%x) "
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001849 "testing VERSION don't match\n",
Krishna Kondaa7af6062011-09-01 18:34:38 -07001850 test_version,
1851 sdioc_test_version);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001852 msleep(500);
1853 BUG();
1854 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855 }
1856
1857 if ((header->signature != (u32) PEER_SDIOC_SW_MAILBOX_SIGNATURE) &&
1858 (header->signature != (u32) PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001859 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
1860 "invalid signature. 0x%x\n", header->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001861 goto exit_err;
1862 }
1863 /* Upper byte has to be equal - no backward compatibility for unequal */
1864 sdio_al->sdioc_major = header->version >> 16;
1865 if (sdio_al->pdata->allow_sdioc_version_major_2) {
1866 if ((sdio_al->sdioc_major !=
1867 sdio_al->pdata->peer_sdioc_version_major) &&
1868 (sdio_al->sdioc_major != PEER_SDIOC_OLD_VERSION_MAJOR)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001869 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1870 ": HOST(0x%x) and CLIENT(0x%x) "
1871 "SDIO_AL VERSION don't match\n",
1872 ((sdio_al->pdata->peer_sdioc_version_major<<16)+
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001873 sdio_al->pdata->peer_sdioc_version_minor),
Krishna Kondaa7af6062011-09-01 18:34:38 -07001874 header->version);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875 goto exit_err;
1876 }
1877 } else {
1878 if (sdio_al->sdioc_major !=
1879 sdio_al->pdata->peer_sdioc_version_major) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001880 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1881 ": HOST(0x%x) and CLIENT(0x%x) "
1882 "SDIO_AL VERSION don't match\n",
1883 ((sdio_al->pdata->peer_sdioc_version_major<<16)+
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001884 sdio_al->pdata->peer_sdioc_version_minor),
Krishna Kondaa7af6062011-09-01 18:34:38 -07001885 header->version);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886 goto exit_err;
1887 }
1888 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001889 sdio_al_dev->ch_close_supported = (header->version & 0x000F) >=
1890 (sdio_al->pdata->peer_sdioc_version_minor & 0xF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001891
Krishna Kondaa7af6062011-09-01 18:34:38 -07001892 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW version 0x%x,"
1893 " sdio_al major 0x%x minor 0x%x\n", header->version,
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001894 sdio_al->sdioc_major,
1895 sdio_al->pdata->peer_sdioc_version_minor);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001896
1897 sdio_al_dev->flashless_boot_on = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
1899 struct sdio_channel *ch = &sdio_al_dev->channel[i];
1900
1901 /* Set default values */
1902 ch->read_threshold = DEFAULT_READ_THRESHOLD;
1903 ch->write_threshold = DEFAULT_WRITE_THRESHOLD;
1904 ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD;
1905 ch->is_packet_mode = true;
1906 ch->peer_tx_buf_size = DEFAULT_PEER_TX_BUF_SIZE;
1907 ch->poll_delay_msec = 0;
1908
1909 ch->num = i;
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07001910 ch->func = NULL;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001911 ch->rx_pipe_index = ch->num*2;
1912 ch->tx_pipe_index = ch->num*2+1;
1913
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914 memset(ch->name, 0, sizeof(ch->name));
1915
1916 if (header->channel_names[i][0]) {
1917 memcpy(ch->name, SDIO_PREFIX,
1918 strlen(SDIO_PREFIX));
1919 memcpy(ch->name + strlen(SDIO_PREFIX),
1920 header->channel_names[i],
1921 PEER_CHANNEL_NAME_SIZE);
1922
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001923 ch->state = SDIO_CHANNEL_STATE_IDLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924 ch->sdio_al_dev = sdio_al_dev;
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07001925 if (sdio_al_dev->card->sdio_func[ch->num+1]) {
1926 ch->func =
1927 sdio_al_dev->card->sdio_func[ch->num+1];
1928 } else {
1929 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1930 ": NULL func for channel %s\n",
1931 ch->name);
1932 goto exit_err;
1933 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001934 } else {
1935 ch->state = SDIO_CHANNEL_STATE_INVALID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001936 }
1937
Krishna Kondaa7af6062011-09-01 18:34:38 -07001938 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Channel=%s, "
1939 "state=%d\n", ch->name, ch->state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001940 }
1941
1942 return 0;
1943
1944exit_err:
1945 sdio_al_get_into_err_state(sdio_al_dev);
1946 memset(header, 0, sizeof(*header));
1947
1948 return -EIO;
1949}
1950
1951/**
1952 * Read SDIO-Client channel configuration
1953 *
1954 */
1955static int read_sdioc_channel_config(struct sdio_channel *ch)
1956{
1957 int ret;
1958 struct peer_sdioc_sw_mailbox *sw_mailbox = NULL;
1959 struct peer_sdioc_channel_config *ch_config = NULL;
1960 struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
1961
1962 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001963 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
1964 " for channel %s\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965 return -EINVAL;
1966 }
1967
1968 if (sdio_al_dev->sdioc_sw_header->version == 0)
1969 return -1;
1970
1971 pr_debug(MODULE_NAME ":reading sw mailbox %s channel.\n", ch->name);
1972
1973 sw_mailbox = kzalloc(sizeof(*sw_mailbox), GFP_KERNEL);
1974 if (sw_mailbox == NULL)
1975 return -ENOMEM;
1976
1977 ret = sdio_memcpy_fromio(ch->func, sw_mailbox,
1978 SDIOC_SW_MAILBOX_ADDR, sizeof(*sw_mailbox));
1979 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001980 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
1981 "sw mailbox.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 goto exit_err;
1983 }
1984
1985 ch_config = &sw_mailbox->ch_config[ch->num];
1986 memcpy(&ch->ch_config, ch_config,
1987 sizeof(struct peer_sdioc_channel_config));
1988
1989 if (!ch_config->is_ready) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001990 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sw mailbox "
1991 "channel not ready.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001992 goto exit_err;
1993 }
1994
Maya Erez3eb7d4c2011-10-17 15:08:42 +02001995 ch->read_threshold = LOW_LATENCY_THRESHOLD;
1996 ch->is_low_latency_ch = ch_config->is_low_latency_ch;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997 /* Threshold on 50% of the maximum size , sdioc uses double-buffer */
1998 ch->write_threshold = (ch_config->max_tx_threshold * 5) / 10;
Maya Erez8ed0a9a2011-07-19 14:46:53 +03001999 ch->threshold_change_cnt = ch->ch_config.max_rx_threshold -
2000 ch->read_threshold + THRESHOLD_CHANGE_EXTRA_BYTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001
Maya Erez3eb7d4c2011-10-17 15:08:42 +02002002 if (ch->is_low_latency_ch)
2003 ch->def_read_threshold = LOW_LATENCY_THRESHOLD;
2004 else /* Aggregation up to 90% of the maximum size */
2005 ch->def_read_threshold = (ch_config->max_rx_threshold * 9) / 10;
2006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 ch->is_packet_mode = ch_config->is_packet_mode;
2008 if (!ch->is_packet_mode) {
2009 ch->poll_delay_msec = DEFAULT_POLL_DELAY_NOPACKET_MSEC;
2010 ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD_STREAMING;
2011 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012 /* The max_packet_size is set by the modem in version 3 and on */
2013 if (sdio_al->sdioc_major > PEER_SDIOC_OLD_VERSION_MAJOR)
2014 ch->min_write_avail = ch_config->max_packet_size;
2015
2016 if (ch->min_write_avail > ch->write_threshold)
2017 ch->min_write_avail = ch->write_threshold;
2018
Maya Erez7ad06d82011-10-02 15:47:57 +02002019 CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":ch %s "
Krishna Kondaa7af6062011-09-01 18:34:38 -07002020 "read_threshold=%d, write_threshold=%d,"
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002021 " min_write_avail=%d, max_rx_threshold=%d,"
2022 " max_tx_threshold=%d\n", ch->name, ch->read_threshold,
2023 ch->write_threshold, ch->min_write_avail,
2024 ch_config->max_rx_threshold,
2025 ch_config->max_tx_threshold);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026
2027 ch->peer_tx_buf_size = ch_config->tx_buf_size;
2028
2029 kfree(sw_mailbox);
2030
2031 return 0;
2032
2033exit_err:
Krishna Kondaa7af6062011-09-01 18:34:38 -07002034 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Reading SW Mailbox "
2035 "error.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002036 kfree(sw_mailbox);
2037
2038 return -1;
2039}
2040
2041
2042/**
2043 * Enable/Disable EOT interrupt of a pipe.
2044 *
2045 */
2046static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
2047 int pipe_index, int enable)
2048{
2049 int ret = 0;
2050 struct sdio_func *func1;
2051 u32 mask;
2052 u32 pipe_mask;
2053 u32 addr;
2054
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002055 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 return -ENODEV;
2057 func1 = sdio_al_dev->card->sdio_func[0];
2058
2059 if (pipe_index < 8) {
2060 addr = PIPES_0_7_IRQ_MASK_ADDR;
2061 pipe_mask = (1<<pipe_index);
2062 } else {
2063 addr = PIPES_8_15_IRQ_MASK_ADDR;
2064 pipe_mask = (1<<(pipe_index-8));
2065 }
2066
2067 mask = sdio_readl(func1, addr, &ret);
2068 if (ret) {
2069 pr_debug(MODULE_NAME ":enable_eot_interrupt fail\n");
2070 goto exit_err;
2071 }
2072
2073 if (enable)
2074 mask &= (~pipe_mask); /* 0 = enable */
2075 else
2076 mask |= (pipe_mask); /* 1 = disable */
2077
2078 sdio_writel(func1, mask, addr, &ret);
2079
2080exit_err:
2081 return ret;
2082}
2083
2084
2085/**
2086 * Enable/Disable mask interrupt of a function.
2087 *
2088 */
2089static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
2090 int func_num, int enable, u8 bit_offset)
2091{
2092 int ret = 0;
2093 struct sdio_func *func1 = NULL;
2094 u32 mask = 0;
2095 u32 func_mask = 0;
2096 u32 addr = 0;
2097 u32 offset = 0;
2098
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002099 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100 return -ENODEV;
2101 func1 = sdio_al_dev->card->sdio_func[0];
2102
2103 if (func_num < 4) {
2104 addr = FUNC_1_4_MASK_IRQ_ADDR;
2105 offset = func_num * 8 + bit_offset;
2106 } else {
2107 addr = FUNC_5_7_MASK_IRQ_ADDR;
2108 offset = (func_num - 4) * 8 + bit_offset;
2109 }
2110
2111 func_mask = 1<<offset;
2112
2113 mask = sdio_readl(func1, addr, &ret);
2114 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002115 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2116 "enable_mask_irq fail\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002117 goto exit_err;
2118 }
2119
2120 if (enable)
2121 mask &= (~func_mask); /* 0 = enable */
2122 else
2123 mask |= (func_mask); /* 1 = disable */
2124
2125 pr_debug(MODULE_NAME ":enable_mask_irq, writing mask = 0x%x\n", mask);
2126
2127 sdio_writel(func1, mask, addr, &ret);
2128
2129exit_err:
2130 return ret;
2131}
2132
2133/**
2134 * Enable/Disable Threshold interrupt of a pipe.
2135 *
2136 */
2137static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
2138 int pipe_index, int enable)
2139{
2140 int ret = 0;
2141 struct sdio_func *func1;
2142 u32 mask;
2143 u32 pipe_mask;
2144 u32 addr;
2145
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002146 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002147 return -ENODEV;
2148 func1 = sdio_al_dev->card->sdio_func[0];
2149
2150 if (pipe_index < 8) {
2151 addr = PIPES_0_7_IRQ_MASK_ADDR;
2152 pipe_mask = (1<<pipe_index);
2153 } else {
2154 addr = PIPES_8_15_IRQ_MASK_ADDR;
2155 pipe_mask = (1<<(pipe_index-8));
2156 }
2157
2158 mask = sdio_readl(func1, addr, &ret);
2159 if (ret) {
2160 pr_debug(MODULE_NAME ":enable_threshold_interrupt fail\n");
2161 goto exit_err;
2162 }
2163
2164 pipe_mask = pipe_mask<<8; /* Threshold bits 8..15 */
2165 if (enable)
2166 mask &= (~pipe_mask); /* 0 = enable */
2167 else
2168 mask |= (pipe_mask); /* 1 = disable */
2169
2170 sdio_writel(func1, mask, addr, &ret);
2171
2172exit_err:
2173 return ret;
2174}
2175
2176/**
2177 * Set the threshold to trigger interrupt from SDIO-Card on
2178 * pipe available bytes.
2179 *
2180 */
2181static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
2182 int pipe_index, int threshold)
2183{
2184 int ret = 0;
2185 struct sdio_func *func1;
2186
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002187 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002188 return -ENODEV;
2189 func1 = sdio_al_dev->card->sdio_func[0];
2190
2191 sdio_writel(func1, threshold,
2192 PIPES_THRESHOLD_ADDR+pipe_index*4, &ret);
2193 if (ret)
Krishna Kondaa7af6062011-09-01 18:34:38 -07002194 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2195 "set_pipe_threshold err=%d\n", -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002196
2197 return ret;
2198}
2199
2200/**
2201 * Enable func w/ retries
2202 *
2203 */
2204static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name)
2205{
2206 int ret, i;
2207 for (i = 0; i < 200; i++) {
2208 ret = sdio_enable_func(func);
2209 if (ret) {
2210 pr_debug(MODULE_NAME ":retry enable %s func#%d "
2211 "ret=%d\n",
2212 name, func->num, ret);
2213 msleep(10);
2214 } else
2215 break;
2216 }
2217
2218 return ret;
2219}
2220
2221/**
2222 * Open Channel
2223 *
2224 * 1. Init Channel Context.
2225 * 2. Init the Channel SDIO-Function.
2226 * 3. Init the Channel Pipes on Mailbox.
2227 */
2228static int open_channel(struct sdio_channel *ch)
2229{
2230 int ret = 0;
2231 struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
2232
2233 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002234 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL "
2235 "sdio_al_dev for channel %s\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002236 return -EINVAL;
2237 }
2238
2239 /* Init channel Context */
2240 /** Func#1 is reserved for mailbox */
2241 ch->func = sdio_al_dev->card->sdio_func[ch->num+1];
2242 ch->rx_pipe_index = ch->num*2;
2243 ch->tx_pipe_index = ch->num*2+1;
2244 ch->signature = SDIO_AL_SIGNATURE;
2245
2246 ch->total_rx_bytes = 0;
2247 ch->total_tx_bytes = 0;
2248
2249 ch->write_avail = 0;
2250 ch->read_avail = 0;
2251 ch->rx_pending_bytes = 0;
2252
2253 mutex_init(&ch->ch_lock);
2254
2255 pr_debug(MODULE_NAME ":open_channel %s func#%d\n",
2256 ch->name, ch->func->num);
2257
2258 INIT_LIST_HEAD(&(ch->rx_size_list_head));
2259
2260 /* Init SDIO Function */
2261 ret = sdio_al_enable_func_retry(ch->func, ch->name);
2262 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002263 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2264 "sdio_enable_func() err=%d\n", -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265 goto exit_err;
2266 }
2267
2268 /* Note: Patch Func CIS tuple issue */
2269 ret = sdio_set_block_size(ch->func, SDIO_AL_BLOCK_SIZE);
2270 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002271 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2272 "sdio_set_block_size()failed, err=%d\n", -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 goto exit_err;
2274 }
2275
2276 ch->func->max_blksize = SDIO_AL_BLOCK_SIZE;
2277
2278 sdio_set_drvdata(ch->func, ch);
2279
2280 /* Get channel parameters from the peer SDIO-Client */
2281 read_sdioc_channel_config(ch);
2282
2283 /* Set Pipes Threshold on Mailbox */
2284 ret = set_pipe_threshold(sdio_al_dev,
2285 ch->rx_pipe_index, ch->read_threshold);
2286 if (ret)
2287 goto exit_err;
2288 ret = set_pipe_threshold(sdio_al_dev,
2289 ch->tx_pipe_index, ch->write_threshold);
2290 if (ret)
2291 goto exit_err;
2292
2293 /* Set flag before interrupts are enabled to allow notify */
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002294 ch->state = SDIO_CHANNEL_STATE_OPEN;
2295 pr_debug(MODULE_NAME ":channel %s is in OPEN state now\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296
2297 sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
2298
2299 /* lpm mechanism lives under the assumption there is always a timer */
2300 /* Check if need to start the timer */
2301 if ((sdio_al_dev->poll_delay_msec) &&
2302 (sdio_al_dev->is_timer_initialized == false)) {
2303
2304 init_timer(&sdio_al_dev->timer);
2305 sdio_al_dev->timer.data = (unsigned long) sdio_al_dev;
2306 sdio_al_dev->timer.function = sdio_al_timer_handler;
2307 sdio_al_dev->timer.expires = jiffies +
2308 msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
2309 add_timer(&sdio_al_dev->timer);
2310 sdio_al_dev->is_timer_initialized = true;
2311 }
2312
2313 /* Enable Pipes Interrupts */
2314 enable_eot_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
2315 enable_eot_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
2316
2317 enable_threshold_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
2318 enable_threshold_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
2319
2320exit_err:
2321
2322 return ret;
2323}
2324
2325/**
2326 * Ask the worker to read the mailbox.
2327 */
2328static void ask_reading_mailbox(struct sdio_al_device *sdio_al_dev)
2329{
2330 if (!sdio_al_dev->ask_mbox) {
2331 pr_debug(MODULE_NAME ":ask_reading_mailbox for card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002332 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002333 sdio_al_dev->ask_mbox = true;
2334 wake_up(&sdio_al_dev->wait_mbox);
2335 }
2336}
2337
2338/**
2339 * Start the timer
2340 */
2341static void start_timer(struct sdio_al_device *sdio_al_dev)
2342{
2343 if ((sdio_al_dev->poll_delay_msec) &&
2344 (sdio_al_dev->state == CARD_INSERTED)) {
2345 sdio_al_dev->timer.expires = jiffies +
2346 msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
2347 add_timer(&sdio_al_dev->timer);
2348 }
2349}
2350
2351/**
2352 * Restart(postpone) the already working timer
2353 */
2354static void restart_timer(struct sdio_al_device *sdio_al_dev)
2355{
2356 if ((sdio_al_dev->poll_delay_msec) &&
2357 (sdio_al_dev->state == CARD_INSERTED)) {
2358 ulong expires = jiffies +
2359 msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
2360 mod_timer(&sdio_al_dev->timer, expires);
2361 }
2362}
2363
2364/**
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002365 * Stop and delete the timer
2366 */
2367static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev)
2368{
2369 if (sdio_al_dev->is_timer_initialized) {
2370 sdio_al_dev->poll_delay_msec = 0;
2371 del_timer_sync(&sdio_al_dev->timer);
2372 }
2373}
2374
2375/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002376 * Do the wakup sequence.
2377 * This function should be called after claiming the host!
2378 * The caller is responsible for releasing the host.
2379 *
2380 * Wake up sequence
2381 * 1. Get lock
2382 * 2. Enable wake up function if needed
2383 * 3. Mark NOT OK to sleep and write it
2384 * 4. Restore default thresholds
2385 * 5. Start the mailbox and inactivity timer again
2386 */
2387static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
Maya Erez7b1ebd22011-08-20 20:53:24 +03002388 u32 not_from_int, struct sdio_channel *ch)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002389{
Maya Erez8ed0a9a2011-07-19 14:46:53 +03002390 int ret = 0;
Maya Erez86cebda2011-10-11 11:13:40 +02002391 struct sdio_func *wk_func = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392 unsigned long time_to_wait;
Maya Erez86cebda2011-10-11 11:13:40 +02002393 struct mmc_host *host = sdio_al_dev->host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394
2395 if (sdio_al_dev->is_err) {
2396 SDIO_AL_ERR(__func__);
2397 return -ENODEV;
2398 }
2399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002400 if (!sdio_al_dev->is_ok_to_sleep) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002401 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":card %d "
2402 "already awake, no need to wake up\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002403 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404 return 0;
2405 }
Maya Erez7b1ebd22011-08-20 20:53:24 +03002406
2407 /* Wake up sequence */
2408 if (not_from_int) {
2409 if (ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002410 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
2411 " card %d (not by interrupt), ch %s",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002412 sdio_al_dev->host->index,
Krishna Kondaa7af6062011-09-01 18:34:38 -07002413 ch->name);
Maya Erez7b1ebd22011-08-20 20:53:24 +03002414 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002415 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
2416 " card %d (not by interrupt)",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002417 sdio_al_dev->host->index);
Maya Erez7b1ebd22011-08-20 20:53:24 +03002418 }
2419 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002420 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up card "
2421 "%d by interrupt",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002422 sdio_al_dev->host->index);
Maya Erez7b1ebd22011-08-20 20:53:24 +03002423 sdio_al_dev->print_after_interrupt = 1;
2424 }
2425
Yaniv Gardi3e327762011-07-27 11:11:04 +03002426 sdio_al_vote_for_sleep(sdio_al_dev, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428 msmsdcc_lpm_disable(host);
Maya Erez86cebda2011-10-11 11:13:40 +02002429 msmsdcc_set_pwrsave(host, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002430 /* Poll the GPIO */
2431 time_to_wait = jiffies + msecs_to_jiffies(1000);
2432 while (time_before(jiffies, time_to_wait)) {
2433 if (sdio_al->pdata->get_mdm2ap_status())
2434 break;
2435 udelay(TIME_TO_WAIT_US);
2436 }
Yaniv Gardi3e327762011-07-27 11:11:04 +03002437
Maya Erez7b1ebd22011-08-20 20:53:24 +03002438 pr_debug(MODULE_NAME ":GPIO mdm2ap_status=%d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439 sdio_al->pdata->get_mdm2ap_status());
2440
2441 /* Here get_mdm2ap_status() returning 0 is not an error condition */
2442 if (sdio_al->pdata->get_mdm2ap_status() == 0)
Krishna Kondaa7af6062011-09-01 18:34:38 -07002443 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": "
2444 "get_mdm2ap_status() is 0\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002445
2446 /* Enable Wake up Function */
Maya Erez86cebda2011-10-11 11:13:40 +02002447 if (!sdio_al_dev->card ||
2448 !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
2449 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
2450 ": NULL card or wk_func\n");
2451 return -ENODEV;
2452 }
2453 wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002454 ret = sdio_al_enable_func_retry(wk_func, "wakeup func");
2455 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002456 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2457 "sdio_enable_func() err=%d\n", -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458 goto error_exit;
2459 }
2460 /* Mark NOT OK_TOSLEEP */
2461 sdio_al_dev->is_ok_to_sleep = 0;
2462 ret = write_lpm_info(sdio_al_dev);
2463 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002464 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2465 "write_lpm_info() failed, err=%d\n", -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466 sdio_al_dev->is_ok_to_sleep = 1;
2467 sdio_disable_func(wk_func);
2468 goto error_exit;
2469 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 sdio_disable_func(wk_func);
2471
2472 /* Start the timer again*/
2473 restart_inactive_time(sdio_al_dev);
2474 sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
2475 start_timer(sdio_al_dev);
2476
Krishna Kondaa7af6062011-09-01 18:34:38 -07002477 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME "Finished Wake up sequence"
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002478 " for card %d", sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479
Maya Erez86cebda2011-10-11 11:13:40 +02002480 msmsdcc_set_pwrsave(host, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002481 pr_debug(MODULE_NAME ":Turn clock off\n");
2482
2483 return ret;
2484error_exit:
2485 sdio_al_vote_for_sleep(sdio_al_dev, 1);
Maya Erez86cebda2011-10-11 11:13:40 +02002486 msmsdcc_set_pwrsave(host, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 WARN_ON(ret);
2488 sdio_al_get_into_err_state(sdio_al_dev);
2489 return ret;
2490}
2491
2492
2493/**
2494 * SDIO Function Interrupt handler.
2495 *
2496 * Interrupt shall be triggered by SDIO-Client when:
2497 * 1. End-Of-Transfer (EOT) detected in packet mode.
2498 * 2. Bytes-available reached the threshold.
2499 *
2500 * Reading the mailbox clears the EOT/Threshold interrupt
2501 * source.
2502 * The interrupt source should be cleared before this ISR
2503 * returns. This ISR is called from IRQ Thread and not
2504 * interrupt, so it may sleep.
2505 *
2506 */
2507static void sdio_func_irq(struct sdio_func *func)
2508{
2509 struct sdio_al_device *sdio_al_dev = sdio_get_drvdata(func);
2510
2511 pr_debug(MODULE_NAME ":start %s.\n", __func__);
2512
2513 if (sdio_al_dev == NULL) {
Maya Erez86cebda2011-10-11 11:13:40 +02002514 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL device");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515 return;
2516 }
2517
2518 if (sdio_al_dev->is_ok_to_sleep)
Maya Erez7b1ebd22011-08-20 20:53:24 +03002519 sdio_al_wake_up(sdio_al_dev, 0, NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002520 else
2521 restart_timer(sdio_al_dev);
2522
2523 read_mailbox(sdio_al_dev, true);
2524
2525 pr_debug(MODULE_NAME ":end %s.\n", __func__);
2526}
2527
2528/**
2529 * Timer Expire Handler
2530 *
2531 */
2532static void sdio_al_timer_handler(unsigned long data)
2533{
2534 struct sdio_al_device *sdio_al_dev = (struct sdio_al_device *)data;
2535 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002536 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": NULL "
2537 "sdio_al_dev for data %lu\n", data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002538 return;
2539 }
2540 if (sdio_al_dev->state != CARD_INSERTED) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002541 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": sdio_al_dev "
2542 "is in invalid state %d\n", sdio_al_dev->state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002543 return;
2544 }
2545 pr_debug(MODULE_NAME " Timer Expired\n");
2546
2547 ask_reading_mailbox(sdio_al_dev);
2548
2549 restart_timer(sdio_al_dev);
2550}
2551
2552/**
2553 * Driver Setup.
2554 *
2555 */
2556static int sdio_al_setup(struct sdio_al_device *sdio_al_dev)
2557{
2558 int ret = 0;
2559 struct mmc_card *card = sdio_al_dev->card;
2560 struct sdio_func *func1 = NULL;
2561 int i = 0;
2562 int fn = 0;
2563
Maya Erez86cebda2011-10-11 11:13:40 +02002564 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002565 return -ENODEV;
Maya Erez86cebda2011-10-11 11:13:40 +02002566 func1 = card->sdio_func[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567
Krishna Kondaa7af6062011-09-01 18:34:38 -07002568 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_setup for "
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002569 "card %d\n", sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002570
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571 ret = sdio_al->pdata->config_mdm2ap_status(1);
2572 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002573 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME "Could not "
2574 "request GPIO\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002575 return ret;
2576 }
2577
2578 INIT_WORK(&sdio_al_dev->sdio_al_work.work, worker);
2579 /* disable all pipes interrupts before claim irq.
2580 since all are enabled by default. */
2581 for (i = 0 ; i < SDIO_AL_MAX_PIPES; i++) {
2582 enable_eot_interrupt(sdio_al_dev, i, false);
2583 enable_threshold_interrupt(sdio_al_dev, i, false);
2584 }
2585
2586 /* Disable all SDIO Functions before claim irq. */
2587 for (fn = 1 ; fn <= card->sdio_funcs; fn++)
2588 sdio_disable_func(card->sdio_func[fn-1]);
2589
2590 sdio_set_drvdata(func1, sdio_al_dev);
Krishna Kondaa7af6062011-09-01 18:34:38 -07002591 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":claim IRQ for card "
Maya Erez86cebda2011-10-11 11:13:40 +02002592 "%d\n", sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593
2594 ret = sdio_claim_irq(func1, sdio_func_irq);
2595 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002596 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to claim"
2597 " IRQ for card %d\n",
Maya Erez86cebda2011-10-11 11:13:40 +02002598 sdio_al_dev->host->index);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002599 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002600 }
2601
2602 sdio_al_dev->is_ready = true;
2603
2604 /* Start worker before interrupt might happen */
2605 queue_work(sdio_al_dev->workqueue, &sdio_al_dev->sdio_al_work.work);
2606
2607 start_inactive_time(sdio_al_dev);
2608
2609 pr_debug(MODULE_NAME ":Ready.\n");
2610
2611 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002612}
2613
2614/**
2615 * Driver Tear-Down.
2616 *
2617 */
2618static void sdio_al_tear_down(void)
2619{
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002620 int i, j;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002621 struct sdio_al_device *sdio_al_dev = NULL;
2622 struct sdio_func *func1;
2623
2624 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
2625 if (sdio_al->devices[i] == NULL)
2626 continue;
2627 sdio_al_dev = sdio_al->devices[i];
2628
2629 if (sdio_al_dev->is_ready) {
2630 sdio_al_dev->is_ready = false; /* Flag worker to exit */
2631 sdio_al_dev->ask_mbox = false;
2632 ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
2633 /* allow gracefully exit of the worker thread */
2634 msleep(100);
2635
2636 flush_workqueue(sdio_al_dev->workqueue);
2637 destroy_workqueue(sdio_al_dev->workqueue);
2638
2639 sdio_al_vote_for_sleep(sdio_al_dev, 1);
2640
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002641 if (!sdio_al_claim_mutex_and_verify_dev(sdio_al_dev,
2642 __func__)) {
2643 if (!sdio_al_dev->card ||
2644 !sdio_al_dev->card->sdio_func[0]) {
2645 sdio_al_loge(sdio_al_dev->dev_log,
2646 MODULE_NAME
2647 ": %s: Invalid func1",
2648 __func__);
2649 return;
2650 }
2651 func1 = sdio_al_dev->card->sdio_func[0];
2652 sdio_release_irq(func1);
2653 sdio_disable_func(func1);
2654 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002655 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002656 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002657
2658 for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++)
2659 sdio_al_dev->channel[j].signature = 0x0;
2660 sdio_al_dev->signature = 0;
2661
2662 kfree(sdio_al_dev->sdioc_sw_header);
2663 kfree(sdio_al_dev->mailbox);
2664 kfree(sdio_al_dev->rx_flush_buf);
2665 kfree(sdio_al_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002666 }
2667
2668 sdio_al->pdata->config_mdm2ap_status(0);
2669}
2670
2671/**
2672 * Find channel by name.
2673 *
2674 */
2675static struct sdio_channel *find_channel_by_name(const char *name)
2676{
2677 struct sdio_channel *ch = NULL;
2678 int i, j;
2679 struct sdio_al_device *sdio_al_dev = NULL;
2680
2681 for (j = 0; j < MAX_NUM_OF_SDIO_DEVICES; ++j) {
2682 if (sdio_al->devices[j] == NULL)
2683 continue;
2684 sdio_al_dev = sdio_al->devices[j];
2685 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002686 if (sdio_al_dev->channel[i].state ==
2687 SDIO_CHANNEL_STATE_INVALID)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002688 continue;
Venkat Gopalakrishnan16eec752011-11-11 16:32:54 -08002689 if (strncmp(sdio_al_dev->channel[i].name, name,
2690 CHANNEL_NAME_SIZE) == 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002691 ch = &sdio_al_dev->channel[i];
2692 break;
2693 }
2694 }
2695 if (ch != NULL)
2696 break;
2697 }
2698
2699 return ch;
2700}
2701
2702/**
2703 * Find the minimal poll time.
2704 *
2705 */
2706static int get_min_poll_time_msec(struct sdio_al_device *sdio_sl_dev)
2707{
2708 int i;
2709 int poll_delay_msec = 0x0FFFFFFF;
2710
2711 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++)
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002712 if ((sdio_sl_dev->channel[i].state ==
2713 SDIO_CHANNEL_STATE_OPEN) &&
2714 (sdio_sl_dev->channel[i].poll_delay_msec > 0) &&
2715 (sdio_sl_dev->channel[i].poll_delay_msec < poll_delay_msec))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002716 poll_delay_msec =
2717 sdio_sl_dev->channel[i].poll_delay_msec;
2718
2719 if (poll_delay_msec == 0x0FFFFFFF)
2720 poll_delay_msec = SDIO_AL_POLL_TIME_NO_STREAMING;
2721
2722 pr_debug(MODULE_NAME ":poll delay time is %d msec\n", poll_delay_msec);
2723
2724 return poll_delay_msec;
2725}
2726
2727/**
2728 * Open SDIO Channel.
2729 *
2730 * Enable the channel.
2731 * Set the channel context.
2732 * Trigger reading the mailbox to check available bytes.
2733 *
2734 */
2735int sdio_open(const char *name, struct sdio_channel **ret_ch, void *priv,
2736 void (*notify)(void *priv, unsigned ch_event))
2737{
2738 int ret = 0;
2739 struct sdio_channel *ch = NULL;
2740 struct sdio_al_device *sdio_al_dev = NULL;
2741
2742 *ret_ch = NULL; /* default */
2743
2744 ch = find_channel_by_name(name);
2745 if (ch == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002746 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":Can't find "
2747 "channel name %s\n", name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002748 return -EINVAL;
2749 }
2750
2751 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002752 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002753 return -ENODEV;
2754
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002755 if ((ch->state != SDIO_CHANNEL_STATE_IDLE) &&
2756 (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002757 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Wrong ch %s "
2758 "state %d\n", name, ch->state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002759 ret = -EPERM;
2760 goto exit_err;
2761 }
2762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002763 if (sdio_al_dev->is_err) {
2764 SDIO_AL_ERR(__func__);
2765 ret = -ENODEV;
2766 goto exit_err;
2767 }
2768
Maya Erez7b1ebd22011-08-20 20:53:24 +03002769 ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002770 if (ret)
2771 goto exit_err;
2772
2773 ch->notify = notify;
2774 ch->priv = priv;
2775
2776 /* Note: Set caller returned context before interrupts are enabled */
2777 *ret_ch = ch;
2778
2779 ret = open_channel(ch);
2780 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002781 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
2782 "err=%d\n", name, -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002783 goto exit_err;
2784 }
2785
Maya Erez7ad06d82011-10-02 15:47:57 +02002786 CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
2787 "completed OK\n", name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002788 if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
2789 if (sdio_al->sdioc_major == PEER_SDIOC_OLD_VERSION_MAJOR) {
2790 if (!ch->is_packet_mode) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002791 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
2792 ":setting channel %s as "
2793 "lpm_chan\n", name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002794 sdio_al_dev->lpm_chan = ch->num;
2795 }
2796 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002797 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": "
2798 "setting channel %s as lpm_chan\n",
2799 name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002800 sdio_al_dev->lpm_chan = ch->num;
2801 }
2802 }
2803
2804exit_err:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002805 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002806 return ret;
2807}
2808EXPORT_SYMBOL(sdio_open);
2809
2810/**
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002811 * Request peer operation
2812 * note: sanity checks of parameters done by caller
2813 * called under bus locked
2814 */
2815static int peer_set_operation(u32 opcode,
2816 struct sdio_al_device *sdio_al_dev,
2817 struct sdio_channel *ch)
2818{
2819 int ret;
2820 int offset;
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07002821 struct sdio_func *wk_func = NULL;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002822 u32 peer_operation;
2823 int loop_count = 0;
2824
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07002825 if (!sdio_al_dev->card ||
2826 !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
2827 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
2828 ": NULL card or wk_func\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002829 ret = -ENODEV;
2830 goto exit;
2831 }
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07002832 wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
2833
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002834 /* calculate offset of peer_operation field in sw mailbox struct */
2835 offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config) +
2836 sizeof(struct peer_sdioc_channel_config) * ch->num +
2837 offsetof(struct peer_sdioc_channel_config, peer_operation);
2838
Maya Erez7b1ebd22011-08-20 20:53:24 +03002839 ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002840 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002841 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
2842 "wake up\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002843 goto exit;
2844 }
2845 /* request operation from MDM peer */
2846 peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_INIT);
2847 ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
2848 &peer_operation, sizeof(u32));
2849 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002850 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
2851 "request close operation\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002852 goto exit;
2853 }
2854 ret = sdio_al_enable_func_retry(wk_func, "wk_func");
2855 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002856 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to enable"
2857 " Func#%d\n", wk_func->num);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002858 goto exit;
2859 }
2860 pr_debug(MODULE_NAME ":%s: wk_func enabled on ch %s\n",
2861 __func__, ch->name);
2862 /* send "start" operation to MDM */
2863 peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_START);
2864 ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
2865 &peer_operation, sizeof(u32));
2866 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002867 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
2868 "send start close operation\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002869 goto exit;
2870 }
2871 ret = sdio_disable_func(wk_func);
2872 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002873 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
2874 "disable Func#%d\n", wk_func->num);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002875 goto exit;
2876 }
2877 /* poll for peer operation ack */
2878 while (peer_operation != 0) {
2879 ret = sdio_memcpy_fromio(ch->func,
2880 &peer_operation,
2881 SDIOC_SW_MAILBOX_ADDR+offset,
2882 sizeof(u32));
2883 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002884 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
2885 ":failed to request ack on close"
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002886 " operation, loop_count = %d\n",
2887 loop_count);
2888 goto exit;
2889 }
2890 loop_count++;
2891 if (loop_count > 10) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002892 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
2893 "peer_operation=0x%x wait loop"
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002894 " %d on ch %s\n", __func__,
2895 peer_operation, loop_count, ch->name);
2896 }
2897 }
2898exit:
2899 return ret;
2900}
2901
Konstantin Dorfman52890522011-10-05 11:03:19 +02002902static int channel_close(struct sdio_channel *ch, int flush_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002903{
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002904 int ret;
2905 struct sdio_al_device *sdio_al_dev = NULL;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002906 int flush_len;
2907 ulong flush_expires;
2908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002909 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002910 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
2911 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002912 return -ENODEV;
2913 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002914
2915 if (!ch->func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002916 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL func"
2917 " on channel:%d\n", __func__, ch->num);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002918 return -ENODEV;
2919 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002920
2921 sdio_al_dev = ch->sdio_al_dev;
2922 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
2923 return -ENODEV;
2924
2925 if (!sdio_al_dev->ch_close_supported) {
2926 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: Not "
2927 "supported by mdm, ch %s\n",
2928 __func__, ch->name);
2929 ret = -ENOTSUPP;
2930 goto error_exit;
2931 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002932
2933 if (sdio_al_dev->is_err) {
2934 SDIO_AL_ERR(__func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002935 ret = -ENODEV;
2936 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002937 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02002938 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
2939 sdio_al_loge(sdio_al_dev->dev_log,
2940 MODULE_NAME ":%s: ch %s is not in "
2941 "open state (%d)\n",
2942 __func__, ch->name, ch->state);
2943 ret = -ENODEV;
2944 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002945 }
2946 ch->state = SDIO_CHANNEL_STATE_CLOSING;
2947 ret = peer_set_operation(PEER_OP_CODE_CLOSE, sdio_al_dev, ch);
2948 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002949 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
2950 "peer_set_operation() failed: %d\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002951 __func__, ret);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002952 ret = -ENODEV;
2953 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002954 }
2955 /* udate poll time for opened channels */
2956 if (ch->poll_delay_msec > 0) {
2957 sdio_al_dev->poll_delay_msec =
2958 get_min_poll_time_msec(sdio_al_dev);
2959 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002960 sdio_al_release_mutex(ch->sdio_al_dev, __func__);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002961
2962 flush_expires = jiffies +
2963 msecs_to_jiffies(SDIO_CLOSE_FLUSH_TIMEOUT_MSEC);
2964 /* flush rx packets of the channel */
Konstantin Dorfman52890522011-10-05 11:03:19 +02002965 if (flush_flag) {
2966 do {
2967 while (ch->read_avail > 0) {
2968 flush_len = ch->read_avail;
2969 ret = sdio_read_internal(ch,
2970 sdio_al_dev->rx_flush_buf,
2971 flush_len);
2972 if (ret) {
2973 sdio_al_loge(&sdio_al->gen_log,
2974 MODULE_NAME ":%s sdio_read"
2975 " failed: %d, ch %s\n",
2976 __func__, ret,
2977 ch->name);
2978 return ret;
2979 }
Yaniv Gardic4663632011-08-31 19:55:38 +03002980
Konstantin Dorfman52890522011-10-05 11:03:19 +02002981 if (time_after(jiffies, flush_expires) != 0) {
2982 sdio_al_loge(&sdio_al->gen_log,
2983 MODULE_NAME ":%s flush rx "
2984 "packets timeout: ch %s\n",
Krishna Kondaa7af6062011-09-01 18:34:38 -07002985 __func__, ch->name);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002986 sdio_al_get_into_err_state(sdio_al_dev);
2987 return -EBUSY;
2988 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002989 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02002990 msleep(100);
2991 if (ch->signature != SDIO_AL_SIGNATURE) {
2992 sdio_al_loge(&sdio_al->gen_log,
2993 MODULE_NAME ":%s: after sleep,"
2994 " invalid signature"
2995 " 0x%x\n", __func__,
2996 ch->signature);
2997 return -ENODEV;
2998 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002999 if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
3000 __func__))
Konstantin Dorfman52890522011-10-05 11:03:19 +02003001 return -ENODEV;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003002
Konstantin Dorfman52890522011-10-05 11:03:19 +02003003 ret = read_mailbox(sdio_al_dev, false);
3004 if (ret) {
3005 sdio_al_loge(&sdio_al->gen_log,
3006 MODULE_NAME ":%s: failed to"
3007 " read mailbox", __func__);
3008 goto error_exit;
3009 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003010 sdio_al_release_mutex(ch->sdio_al_dev, __func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003011 } while (ch->read_avail > 0);
3012 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003013 if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
3014 __func__))
3015 return -ENODEV;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003016 /* disable function to be able to open the channel again */
3017 ret = sdio_disable_func(ch->func);
3018 if (ret) {
Konstantin Dorfman52890522011-10-05 11:03:19 +02003019 sdio_al_loge(&sdio_al->gen_log,
3020 MODULE_NAME ":Fail to disable Func#%d\n",
3021 ch->func->num);
3022 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003023 }
3024 ch->state = SDIO_CHANNEL_STATE_CLOSED;
Maya Erez7ad06d82011-10-02 15:47:57 +02003025 CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":%s: Ch %s closed "
3026 "successfully\n", __func__, ch->name);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003027
3028error_exit:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003029 sdio_al_release_mutex(ch->sdio_al_dev, __func__);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003030
3031 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003032}
Konstantin Dorfman52890522011-10-05 11:03:19 +02003033
3034/**
3035 * Close SDIO Channel.
3036 *
3037 */
3038int sdio_close(struct sdio_channel *ch)
3039{
3040 return channel_close(ch, true);
3041}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003042EXPORT_SYMBOL(sdio_close);
3043
3044/**
3045 * Get the number of available bytes to write.
3046 *
3047 */
3048int sdio_write_avail(struct sdio_channel *ch)
3049{
3050 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003051 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3052 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003053 return -ENODEV;
3054 }
3055 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003056 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
3057 "Invalid signature 0x%x\n", __func__,
3058 ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003059 return -ENODEV;
3060 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003061 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003062 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
3063 "channel %s state is not open (%d)\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003064 __func__, ch->name, ch->state);
3065 return -ENODEV;
3066 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003067 pr_debug(MODULE_NAME ":sdio_write_avail %s 0x%x\n",
3068 ch->name, ch->write_avail);
3069
3070 return ch->write_avail;
3071}
3072EXPORT_SYMBOL(sdio_write_avail);
3073
3074/**
3075 * Get the number of available bytes to read.
3076 *
3077 */
3078int sdio_read_avail(struct sdio_channel *ch)
3079{
3080 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003081 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3082 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003083 return -ENODEV;
3084 }
3085 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003086 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
3087 "Invalid signature 0x%x\n", __func__,
3088 ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003089 return -ENODEV;
3090 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003091 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003092 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
3093 "channel %s state is not open (%d)\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003094 __func__, ch->name, ch->state);
3095 return -ENODEV;
3096 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003097 pr_debug(MODULE_NAME ":sdio_read_avail %s 0x%x\n",
3098 ch->name, ch->read_avail);
3099
3100 return ch->read_avail;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003101}
3102EXPORT_SYMBOL(sdio_read_avail);
3103
Maya Erez5795e0d2011-09-12 20:20:06 +03003104static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len)
3105{
3106 int ret = 0;
3107 struct sdio_al_device *sdio_al_dev = NULL;
3108
3109 if (!ch) {
Konstantin Dorfman52890522011-10-05 11:03:19 +02003110 sdio_al_loge(ch->sdio_al_dev->dev_log,
3111 MODULE_NAME ":%s: NULL channel\n", __func__);
Maya Erez5795e0d2011-09-12 20:20:06 +03003112 return -ENODEV;
3113 }
3114
3115 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003116 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
3117 return -ENODEV;
Maya Erez5795e0d2011-09-12 20:20:06 +03003118
3119 ret = sdio_memcpy_fromio(ch->func, sdio_al_dev->rx_flush_buf,
3120 PIPE_RX_FIFO_ADDR, len);
3121
3122 if (ret) {
Konstantin Dorfman52890522011-10-05 11:03:19 +02003123 sdio_al_loge(ch->sdio_al_dev->dev_log,
3124 MODULE_NAME ":ch %s: %s err=%d, len=%d\n",
Maya Erez5795e0d2011-09-12 20:20:06 +03003125 ch->name, __func__, -ret, len);
3126 sdio_al_dev->is_err = true;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003127 sdio_al_release_mutex(sdio_al_dev, __func__);
Maya Erez5795e0d2011-09-12 20:20:06 +03003128 return ret;
3129 }
3130
3131 restart_inactive_time(sdio_al_dev);
3132
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003133 sdio_al_release_mutex(sdio_al_dev, __func__);
Maya Erez5795e0d2011-09-12 20:20:06 +03003134
3135 return 0;
3136}
3137
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003138/**
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003139 * Internal read from SDIO Channel.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003140 *
3141 * Reading from the pipe will trigger interrupt if there are
3142 * other pending packets on the SDIO-Client.
3143 *
3144 */
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003145static int sdio_read_internal(struct sdio_channel *ch, void *data, int len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003146{
3147 int ret = 0;
3148 struct sdio_al_device *sdio_al_dev = NULL;
3149
3150 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003151 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3152 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003153 return -ENODEV;
3154 }
3155 if (!data) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003156 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
3157 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003158 return -ENODEV;
3159 }
3160 if (len == 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003161 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
3162 " to read 0 bytes\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163 return -EINVAL;
3164 }
3165
3166 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003167 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
3168 "signature 0x%x\n", __func__, ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003169 return -ENODEV;
3170 }
3171
3172 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003173 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003174 return -ENODEV;
3175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003176 if (sdio_al_dev->is_err) {
3177 SDIO_AL_ERR(__func__);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003178 ret = -ENODEV;
3179 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003180 }
3181
3182 /* lpm policy says we can't go to sleep when we have pending rx data,
3183 so either we had rx interrupt and woken up, or we never went to
3184 sleep */
3185 if (sdio_al_dev->is_ok_to_sleep) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003186 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: called "
3187 "when is_ok_to_sleep is set for ch %s, len=%d,"
3188 " last_any_read_avail=%d, last_read_avail=%d, "
3189 "last_old_read_avail=%d", __func__, ch->name,
3190 len, ch->statistics.last_any_read_avail,
3191 ch->statistics.last_read_avail,
3192 ch->statistics.last_old_read_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003193 }
3194 BUG_ON(sdio_al_dev->is_ok_to_sleep);
3195
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003196 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
3197 (ch->state != SDIO_CHANNEL_STATE_CLOSING)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003198 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s wrong "
3199 "channel %s state %d\n",
3200 __func__, ch->name, ch->state);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003201 ret = -EINVAL;
3202 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003203 }
3204
Krishna Kondaa7af6062011-09-01 18:34:38 -07003205 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s read %d "
3206 "avail %d.\n", ch->name, len, ch->read_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003207
3208 restart_inactive_time(sdio_al_dev);
3209
3210 if ((ch->is_packet_mode) && (len != ch->read_avail)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003211 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_read ch "
3212 "%s len != read_avail\n", ch->name);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003213 ret = -EINVAL;
3214 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003215 }
3216
3217 if (len > ch->read_avail) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003218 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
3219 "reading more bytes (%d) than the avail(%d).\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003220 ch->name, len, ch->read_avail);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003221 ret = -ENOMEM;
3222 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003223 }
3224
3225 ret = sdio_memcpy_fromio(ch->func, data, PIPE_RX_FIFO_ADDR, len);
3226
3227 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003228 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ch %s: "
3229 "sdio_read err=%d, len=%d, read_avail=%d, "
3230 "last_read_avail=%d, last_old_read_avail=%d\n",
Maya Erezd9cc2292011-08-04 09:20:31 +03003231 ch->name, -ret, len, ch->read_avail,
3232 ch->statistics.last_read_avail,
3233 ch->statistics.last_old_read_avail);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003234 sdio_al_get_into_err_state(sdio_al_dev);
3235 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003236 }
3237
3238 ch->statistics.total_read_times++;
3239
3240 /* Remove handled packet from the list regardless if ret is ok */
3241 if (ch->is_packet_mode)
3242 remove_handled_rx_packet(ch);
3243 else
3244 ch->read_avail -= len;
3245
3246 ch->total_rx_bytes += len;
Krishna Kondaa7af6062011-09-01 18:34:38 -07003247 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s read %d "
3248 "avail %d total %d.\n", ch->name, len,
3249 ch->read_avail, ch->total_rx_bytes);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003250
3251 if ((ch->read_avail == 0) && !(ch->is_packet_mode))
3252 ask_reading_mailbox(sdio_al_dev);
3253
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003254exit:
3255 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003256
3257 return ret;
3258}
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003259
3260/**
3261 * Read from SDIO Channel.
3262 *
3263 * Reading from the pipe will trigger interrupt if there are
3264 * other pending packets on the SDIO-Client.
3265 *
3266 */
3267int sdio_read(struct sdio_channel *ch, void *data, int len)
3268{
3269 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003270 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3271 "channel\n", __func__);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003272 return -ENODEV;
3273 }
3274 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003275 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
3276 "Invalid signature 0x%x\n", __func__, ch->signature);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003277 return -ENODEV;
3278 }
3279 if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
3280 return sdio_read_internal(ch, data, len);
3281 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003282 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME
3283 ":%s: Invalid channel %s state %d\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003284 __func__, ch->name, ch->state);
3285 }
3286 return -ENODEV;
3287}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003288EXPORT_SYMBOL(sdio_read);
3289
3290/**
3291 * Write to SDIO Channel.
3292 *
3293 */
3294int sdio_write(struct sdio_channel *ch, const void *data, int len)
3295{
3296 int ret = 0;
3297 struct sdio_al_device *sdio_al_dev = NULL;
3298
3299 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003300 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3301 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003302 return -ENODEV;
3303 }
3304 if (!data) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003305 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
3306 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003307 return -ENODEV;
3308 }
3309 if (len == 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003310 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
3311 " to write 0 bytes\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003312 return -EINVAL;
3313 }
3314
3315 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003316 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
3317 "signature 0x%x\n", __func__, ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003318 return -ENODEV;
3319 }
3320
3321 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003322 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003323 return -ENODEV;
3324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003325 WARN_ON(len > ch->write_avail);
3326
3327 if (sdio_al_dev->is_err) {
3328 SDIO_AL_ERR(__func__);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003329 ret = -ENODEV;
3330 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003331 }
3332
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003333 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003334 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":writing to "
3335 "closed channel %s\n", ch->name);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003336 ret = -EINVAL;
3337 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003338 }
3339
3340 if (sdio_al_dev->is_ok_to_sleep) {
Maya Erez7b1ebd22011-08-20 20:53:24 +03003341 ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003342 if (ret)
3343 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003344 } else {
3345 restart_inactive_time(sdio_al_dev);
3346 }
3347
Krishna Kondaa7af6062011-09-01 18:34:38 -07003348 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s write %d "
3349 "avail %d.\n", ch->name, len, ch->write_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003350
3351 if (len > ch->write_avail) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003352 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
3353 "write more bytes (%d) than available %d.\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003354 ch->name, len, ch->write_avail);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003355 ret = -ENOMEM;
3356 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003357 }
3358
3359 ret = sdio_ch_write(ch, data, len);
3360 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003361 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_write "
3362 "on channel %s err=%d\n", ch->name, -ret);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003363 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003364 }
3365
3366 ch->total_tx_bytes += len;
Krishna Kondaa7af6062011-09-01 18:34:38 -07003367 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s write %d "
3368 "avail %d total %d.\n", ch->name, len,
3369 ch->write_avail, ch->total_tx_bytes);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003370
3371 /* Round up to whole buffer size */
3372 len = ROUND_UP(len, ch->peer_tx_buf_size);
3373 /* Protect from wraparound */
3374 len = min(len, (int) ch->write_avail);
3375 ch->write_avail -= len;
3376
3377 if (ch->write_avail < ch->min_write_avail)
3378 ask_reading_mailbox(sdio_al_dev);
3379
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003380exit:
3381 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003382
3383 return ret;
3384}
3385EXPORT_SYMBOL(sdio_write);
3386
3387static int __devinit msm_sdio_al_probe(struct platform_device *pdev)
3388{
3389 if (!sdio_al) {
3390 pr_err(MODULE_NAME ": %s: NULL sdio_al\n", __func__);
3391 return -ENODEV;
3392 }
3393
3394 sdio_al->pdata = pdev->dev.platform_data;
3395 return 0;
3396}
3397
3398static int __devexit msm_sdio_al_remove(struct platform_device *pdev)
3399{
3400 return 0;
3401}
3402
Konstantin Dorfman52890522011-10-05 11:03:19 +02003403static void sdio_al_close_all_channels(struct sdio_al_device *sdio_al_dev)
Maya Erez6862b142011-08-22 09:07:07 +03003404{
Konstantin Dorfman52890522011-10-05 11:03:19 +02003405 int j;
Maya Erez6862b142011-08-22 09:07:07 +03003406 int ret;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003407 struct sdio_channel *ch = NULL;
Maya Erez6862b142011-08-22 09:07:07 +03003408
Konstantin Dorfman52890522011-10-05 11:03:19 +02003409 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
Maya Erez6862b142011-08-22 09:07:07 +03003410
Konstantin Dorfman52890522011-10-05 11:03:19 +02003411 if (!sdio_al_dev) {
3412 sdio_al_loge(sdio_al_dev->dev_log,
3413 MODULE_NAME ": %s: NULL device", __func__);
3414 return;
3415 }
3416 for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
3417 ch = &sdio_al_dev->channel[j];
3418
3419 if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
3420 sdio_al_loge(sdio_al_dev->dev_log,
3421 MODULE_NAME ": %s: Call to sdio_close() for"
3422 " ch %s\n", __func__, ch->name);
3423 ret = channel_close(ch, false);
3424 if (ret) {
3425 sdio_al_loge(sdio_al_dev->dev_log,
3426 MODULE_NAME ": %s: failed sdio_close()"
3427 " for ch %s (%d)\n",
3428 __func__, ch->name, ret);
3429 }
3430 } else {
3431 pr_debug(MODULE_NAME ": %s: skip sdio_close() ch %s"
3432 " (state=%d)\n", __func__,
3433 ch->name, ch->state);
Maya Erez6862b142011-08-22 09:07:07 +03003434 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02003435 }
3436}
3437
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003438static void sdio_al_invalidate_sdio_clients(struct sdio_al_device *sdio_al_dev,
3439 struct platform_device **pdev_arr)
3440{
3441 int j;
3442
3443 pr_debug(MODULE_NAME ": %s: Notifying SDIO clients for card %d",
3444 __func__, sdio_al_dev->host->index);
3445 for (j = 0; j < SDIO_AL_MAX_CHANNELS; ++j) {
3446 if (sdio_al_dev->channel[j].state ==
3447 SDIO_CHANNEL_STATE_INVALID)
3448 continue;
3449 pdev_arr[j] = sdio_al_dev->channel[j].pdev;
3450 sdio_al_dev->channel[j].signature = 0x0;
3451 sdio_al_dev->channel[j].state =
3452 SDIO_CHANNEL_STATE_INVALID;
3453 }
3454}
3455
3456static void sdio_al_modem_reset_operations(struct sdio_al_device
Konstantin Dorfman52890522011-10-05 11:03:19 +02003457 *sdio_al_dev)
3458{
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003459 int ret = 0;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003460 struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
3461 int j;
3462
Konstantin Dorfman52890522011-10-05 11:03:19 +02003463 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
3464
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003465 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Konstantin Dorfman52890522011-10-05 11:03:19 +02003466 return;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003467
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003468 if (sdio_al_dev->state == CARD_REMOVED) {
3469 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
3470 "card %d is already removed", __func__,
3471 sdio_al_dev->host->index);
3472 goto exit_err;
3473 }
3474
3475 if (sdio_al_dev->state == MODEM_RESTART) {
3476 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: "
3477 "card %d was already notified for modem reset",
3478 __func__, sdio_al_dev->host->index);
3479 goto exit_err;
3480 }
3481
3482 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: Set the "
3483 "state to MODEM_RESTART for card %d",
3484 __func__, sdio_al_dev->host->index);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003485 sdio_al_dev->state = MODEM_RESTART;
3486 sdio_al_dev->is_ready = false;
Maya Erez6862b142011-08-22 09:07:07 +03003487
Konstantin Dorfman52890522011-10-05 11:03:19 +02003488 /* Stop mailbox timer */
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003489 stop_and_del_timer(sdio_al_dev);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003490
Konstantin Dorfman52890522011-10-05 11:03:19 +02003491 if ((sdio_al_dev->is_ok_to_sleep) &&
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003492 (!sdio_al_dev->is_err)) {
3493 pr_debug(MODULE_NAME ": %s: wakeup modem for "
3494 "card %d", __func__,
3495 sdio_al_dev->host->index);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003496 ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
Maya Erez6862b142011-08-22 09:07:07 +03003497 }
3498
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07003499 if (!ret && (!sdio_al_dev->is_err) && sdio_al_dev->card &&
3500 sdio_al_dev->card->sdio_func[0]) {
3501 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003502 ": %s: sdio_release_irq for card %d",
3503 __func__,
3504 sdio_al_dev->host->index);
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07003505 sdio_release_irq(sdio_al_dev->card->sdio_func[0]);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003506 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003507
3508 memset(pdev_arr, 0, sizeof(pdev_arr));
3509 sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
3510
3511 sdio_al_release_mutex(sdio_al_dev, __func__);
3512
3513 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
3514 "clients for card %d",
3515 __func__, sdio_al_dev->host->index);
3516 for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
3517 if (!pdev_arr[j])
3518 continue;
3519 platform_device_unregister(pdev_arr[j]);
3520 }
3521 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
3522 "SDIO clients for card %d",
3523 __func__, sdio_al_dev->host->index);
3524
3525 return;
3526
3527exit_err:
3528 sdio_al_release_mutex(sdio_al_dev, __func__);
3529 return;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003530}
3531
3532#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
3533static void sdio_al_reset(void)
3534{
3535 int i;
3536 struct sdio_al_device *sdio_al_dev;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003537
3538 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
3539
Maya Erez6862b142011-08-22 09:07:07 +03003540 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
Maya Erez6862b142011-08-22 09:07:07 +03003541 if (sdio_al->devices[i] == NULL) {
3542 pr_debug(MODULE_NAME ": %s: NULL device in index %d",
Konstantin Dorfman52890522011-10-05 11:03:19 +02003543 __func__, i);
Maya Erez6862b142011-08-22 09:07:07 +03003544 continue;
3545 }
3546 sdio_al_dev = sdio_al->devices[i];
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003547 sdio_al_modem_reset_operations(sdio_al->devices[i]);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003548 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003549
3550 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s completed", __func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003551}
3552#endif
Maya Erez6862b142011-08-22 09:07:07 +03003553
Konstantin Dorfman52890522011-10-05 11:03:19 +02003554static void msm_sdio_al_shutdown(struct platform_device *pdev)
3555{
3556 int i;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003557 struct sdio_al_device *sdio_al_dev;
3558
3559 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME
3560 "Initiating msm_sdio_al_shutdown...");
3561
3562 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
3563 if (sdio_al->devices[i] == NULL) {
3564 pr_debug(MODULE_NAME ": %s: NULL device in index %d",
3565 __func__, i);
3566 continue;
Maya Erez8afd564f2011-08-24 15:57:06 +03003567 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02003568 sdio_al_dev = sdio_al->devices[i];
Maya Erez6862b142011-08-22 09:07:07 +03003569
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003570 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
3571 return;
Maya Erez6862b142011-08-22 09:07:07 +03003572
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003573 if (sdio_al_dev->ch_close_supported)
3574 sdio_al_close_all_channels(sdio_al_dev);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003575
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003576 sdio_al_release_mutex(sdio_al_dev, __func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003577
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003578 sdio_al_modem_reset_operations(sdio_al_dev);
Maya Erez6862b142011-08-22 09:07:07 +03003579 }
Krishna Kondaa7af6062011-09-01 18:34:38 -07003580 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
3581 "msm_sdio_al_shutdown complete.", __func__);
Maya Erez6862b142011-08-22 09:07:07 +03003582}
3583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003584static struct platform_driver msm_sdio_al_driver = {
3585 .probe = msm_sdio_al_probe,
3586 .remove = __exit_p(msm_sdio_al_remove),
Maya Erez6862b142011-08-22 09:07:07 +03003587 .shutdown = msm_sdio_al_shutdown,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003588 .driver = {
3589 .name = "msm_sdio_al",
3590 },
3591};
3592
3593/**
3594 * Initialize SDIO_AL channels.
3595 *
3596 */
3597static int init_channels(struct sdio_al_device *sdio_al_dev)
3598{
3599 int ret = 0;
3600 int i;
3601
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003602 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003603 return -ENODEV;
3604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003605 ret = read_sdioc_software_header(sdio_al_dev,
3606 sdio_al_dev->sdioc_sw_header);
3607 if (ret)
3608 goto exit;
3609
3610 ret = sdio_al_setup(sdio_al_dev);
3611 if (ret)
3612 goto exit;
3613
3614 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
3615 int ch_name_size;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003616 if (sdio_al_dev->channel[i].state == SDIO_CHANNEL_STATE_INVALID)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003617 continue;
3618 if (sdio_al->unittest_mode) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003619 memset(sdio_al_dev->channel[i].ch_test_name, 0,
3620 sizeof(sdio_al_dev->channel[i].ch_test_name));
3621 ch_name_size = strnlen(sdio_al_dev->channel[i].name,
3622 CHANNEL_NAME_SIZE);
3623 strncpy(sdio_al_dev->channel[i].ch_test_name,
3624 sdio_al_dev->channel[i].name,
3625 ch_name_size);
3626 strncat(sdio_al_dev->channel[i].ch_test_name +
3627 ch_name_size,
3628 SDIO_TEST_POSTFIX,
3629 SDIO_TEST_POSTFIX_SIZE);
3630 pr_debug(MODULE_NAME ":pdev.name = %s\n",
3631 sdio_al_dev->channel[i].ch_test_name);
3632 sdio_al_dev->channel[i].pdev = platform_device_alloc(
3633 sdio_al_dev->channel[i].ch_test_name, -1);
3634 } else {
3635 pr_debug(MODULE_NAME ":pdev.name = %s\n",
3636 sdio_al_dev->channel[i].name);
3637 sdio_al_dev->channel[i].pdev = platform_device_alloc(
3638 sdio_al_dev->channel[i].name, -1);
3639 }
3640 if (!sdio_al_dev->channel[i].pdev) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003641 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
3642 ":NULL platform device for ch %s",
3643 sdio_al_dev->channel[i].name);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003644 sdio_al_dev->channel[i].state =
3645 SDIO_CHANNEL_STATE_INVALID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003646 continue;
3647 }
3648 ret = platform_device_add(sdio_al_dev->channel[i].pdev);
3649 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003650 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
3651 ":platform_device_add failed, "
3652 "ret=%d\n", ret);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003653 sdio_al_dev->channel[i].state =
3654 SDIO_CHANNEL_STATE_INVALID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003655 }
3656 }
3657
3658exit:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003659 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660 return ret;
3661}
3662
3663/**
3664 * Initialize SDIO_AL channels according to the client setup.
3665 * This function also check if the client is in boot mode and
3666 * flashless boot is required to be activated or the client is
3667 * up and running.
3668 *
3669 */
3670static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev)
3671{
3672 int ret = 0;
3673 struct sdio_func *func1;
3674 int signature = 0;
3675
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003676 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003677 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003678
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003679 if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
3680 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":NULL card or "
3681 "func1\n");
3682 sdio_al_release_mutex(sdio_al_dev, __func__);
3683 return -ENODEV;
3684 }
3685 func1 = sdio_al_dev->card->sdio_func[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003686
3687 /* Read the header signature to determine the status of the MDM
3688 * SDIO Client
3689 */
3690 signature = sdio_readl(func1, SDIOC_SW_HEADER_ADDR, &ret);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003691 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003692 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003693 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
3694 "signature from sw header.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003695 return ret;
3696 }
3697
3698 switch (signature) {
3699 case PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE:
3700 if (sdio_al_dev == sdio_al->bootloader_dev) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003701 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":setup "
3702 "bootloader on card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003703 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003704 return sdio_al_bootloader_setup();
3705 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003706 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":wait "
3707 "for bootloader completion "
3708 "on card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003709 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003710 return sdio_al_wait_for_bootloader_comp(sdio_al_dev);
3711 }
3712 case PEER_SDIOC_SW_MAILBOX_SIGNATURE:
3713 case PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE:
3714 return init_channels(sdio_al_dev);
3715 default:
Krishna Kondaa7af6062011-09-01 18:34:38 -07003716 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
3717 "signature 0x%x\n", signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003718 return -EINVAL;
3719 }
3720
3721 return 0;
3722}
3723
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003724static void clean_sdio_al_device_data(struct sdio_al_device *sdio_al_dev)
3725{
3726 sdio_al_dev->is_ready = 0;
3727 sdio_al_dev->bootloader_done = 0;
3728 sdio_al_dev->lpm_chan = 0;
3729 sdio_al_dev->is_ok_to_sleep = 0;
3730 sdio_al_dev->inactivity_time = 0;
3731 sdio_al_dev->poll_delay_msec = 0;
3732 sdio_al_dev->is_timer_initialized = 0;
3733 sdio_al_dev->is_err = 0;
3734 sdio_al_dev->is_suspended = 0;
3735 sdio_al_dev->flashless_boot_on = 0;
3736 sdio_al_dev->ch_close_supported = 0;
3737 sdio_al_dev->print_after_interrupt = 0;
3738 memset(sdio_al_dev->sdioc_sw_header, 0,
3739 sizeof(*sdio_al_dev->sdioc_sw_header));
3740 memset(sdio_al_dev->mailbox, 0, sizeof(*sdio_al_dev->mailbox));
3741 memset(sdio_al_dev->rx_flush_buf, 0,
3742 sizeof(*sdio_al_dev->rx_flush_buf));
3743}
3744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003745/*
3746 * SDIO driver functions
3747 */
3748static int sdio_al_sdio_probe(struct sdio_func *func,
3749 const struct sdio_device_id *sdio_dev_id)
3750{
3751 int ret = 0;
3752 struct sdio_al_device *sdio_al_dev = NULL;
3753 int i;
3754 struct mmc_card *card = NULL;
3755
3756 if (!func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003757 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
3758 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003759 return -ENODEV;
3760 }
3761 card = func->card;
3762
3763 if (!card) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003764 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
3765 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003766 return -ENODEV;
3767 }
3768
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003769 if (!card->sdio_func[0]) {
3770 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
3771 "func1\n",
3772 __func__);
3773 return -ENODEV;
3774 }
3775
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003776 if (card->sdio_funcs < SDIO_AL_MAX_FUNCS) {
3777 dev_info(&card->dev,
3778 "SDIO-functions# %d less than expected.\n",
3779 card->sdio_funcs);
3780 return -ENODEV;
3781 }
3782
3783 /* Check if there is already a device for this card */
3784 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
3785 if (sdio_al->devices[i] == NULL)
3786 continue;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003787 if (sdio_al->devices[i]->host == card->host) {
3788 sdio_al_dev = sdio_al->devices[i];
3789 if (sdio_al_dev->state == CARD_INSERTED)
3790 return 0;
3791 clean_sdio_al_device_data(sdio_al_dev);
3792 break;
3793 }
3794 }
3795
3796 if (!sdio_al_dev) {
3797 sdio_al_dev = kzalloc(sizeof(struct sdio_al_device),
3798 GFP_KERNEL);
3799 if (sdio_al_dev == NULL)
3800 return -ENOMEM;
3801
3802 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
3803 if (sdio_al->devices[i] == NULL) {
3804 sdio_al->devices[i] = sdio_al_dev;
3805 sdio_al_dev->dev_log = &sdio_al->device_log[i];
3806 spin_lock_init(&sdio_al_dev->dev_log->log_lock);
3807 #ifdef CONFIG_DEBUG_FS
3808 sdio_al_dbgfs_log[i].data =
3809 sdio_al_dev->dev_log->buffer;
3810 sdio_al_dbgfs_log[i].size =
3811 SDIO_AL_DEBUG_LOG_SIZE;
3812 #endif
3813 break;
3814 }
3815 if (i == MAX_NUM_OF_SDIO_DEVICES) {
3816 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":No space "
3817 "in devices array for the device\n");
3818 return -ENOMEM;
3819 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003820 }
3821
3822 dev_info(&card->dev, "SDIO Card claimed.\n");
Maya Erezc7f63282011-10-11 12:15:23 +02003823 sdio_al->skip_print_info = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003825 sdio_al_dev->state = CARD_INSERTED;
3826
3827 if (card->host->index == SDIO_BOOTLOADER_CARD_INDEX)
3828 sdio_al->bootloader_dev = sdio_al_dev;
3829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830 sdio_al_dev->is_ready = false;
3831
3832 sdio_al_dev->signature = SDIO_AL_SIGNATURE;
3833
3834 sdio_al_dev->is_suspended = 0;
3835 sdio_al_dev->is_timer_initialized = false;
3836
3837 sdio_al_dev->lpm_chan = INVALID_SDIO_CHAN;
3838
3839 sdio_al_dev->card = card;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003840 sdio_al_dev->host = card->host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003841
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003842 if (!sdio_al_dev->mailbox) {
3843 sdio_al_dev->mailbox = kzalloc(sizeof(struct sdio_mailbox),
3844 GFP_KERNEL);
3845 if (sdio_al_dev->mailbox == NULL)
3846 return -ENOMEM;
3847 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003849 if (!sdio_al_dev->sdioc_sw_header) {
3850 sdio_al_dev->sdioc_sw_header
3851 = kzalloc(sizeof(*sdio_al_dev->sdioc_sw_header),
3852 GFP_KERNEL);
3853 if (sdio_al_dev->sdioc_sw_header == NULL)
3854 return -ENOMEM;
3855 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003857 if (!sdio_al_dev->rx_flush_buf) {
3858 sdio_al_dev->rx_flush_buf = kzalloc(RX_FLUSH_BUFFER_SIZE,
3859 GFP_KERNEL);
3860 if (sdio_al_dev->rx_flush_buf == NULL) {
3861 sdio_al_loge(&sdio_al->gen_log,
3862 MODULE_NAME ":Fail to allocate "
3863 "rx_flush_buf for card %d\n",
3864 card->host->index);
3865 return -ENOMEM;
3866 }
Maya Erez5795e0d2011-09-12 20:20:06 +03003867 }
3868
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003869 sdio_al_dev->timer.data = (unsigned long)sdio_al_dev;
3870
3871 wake_lock_init(&sdio_al_dev->wake_lock, WAKE_LOCK_SUSPEND, MODULE_NAME);
3872 /* Don't allow sleep until all required clients register */
3873 sdio_al_vote_for_sleep(sdio_al_dev, 0);
3874
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003875 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
3876 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003877
3878 /* Init Func#1 */
Yaniv Gardi9a952d92011-09-06 13:46:30 +03003879 ret = sdio_al_enable_func_retry(card->sdio_func[0], "Init Func#1");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003880 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003881 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
3882 "enable Func#%d\n", card->sdio_func[0]->num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 goto exit;
3884 }
3885
3886 /* Patch Func CIS tuple issue */
3887 ret = sdio_set_block_size(card->sdio_func[0], SDIO_AL_BLOCK_SIZE);
3888 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003889 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to set "
3890 "block size, Func#%d\n", card->sdio_func[0]->num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003891 goto exit;
3892 }
3893 sdio_al_dev->card->sdio_func[0]->max_blksize = SDIO_AL_BLOCK_SIZE;
3894
3895 sdio_al_dev->workqueue = create_singlethread_workqueue("sdio_al_wq");
3896 sdio_al_dev->sdio_al_work.sdio_al_dev = sdio_al_dev;
3897 init_waitqueue_head(&sdio_al_dev->wait_mbox);
3898
3899 ret = sdio_al_client_setup(sdio_al_dev);
3900
3901exit:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003902 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003903 return ret;
3904}
3905
3906static void sdio_al_sdio_remove(struct sdio_func *func)
3907{
3908 struct sdio_al_device *sdio_al_dev = NULL;
3909 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003910 struct mmc_card *card = NULL;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003911 struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912
3913 if (!func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003914 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
3915 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003916 return;
3917 }
3918 card = func->card;
3919
3920 if (!card) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003921 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
3922 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003923 return;
3924 }
3925
3926 /* Find the sdio_al_device of this card */
3927 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
3928 if (sdio_al->devices[i] == NULL)
3929 continue;
3930 if (sdio_al->devices[i]->card == card) {
3931 sdio_al_dev = sdio_al->devices[i];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003932 break;
3933 }
3934 }
3935 if (sdio_al_dev == NULL) {
3936 pr_debug(MODULE_NAME ":%s :NULL sdio_al_dev for card %d\n",
3937 __func__, card->host->index);
3938 return;
3939 }
3940
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003941 if (sdio_al_claim_mutex(sdio_al_dev, __func__))
3942 return;
3943
3944 if (sdio_al_dev->state == CARD_REMOVED) {
3945 sdio_al_release_mutex(sdio_al_dev, __func__);
3946 return;
3947 }
3948
3949 if (!card->sdio_func[0]) {
3950 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
3951 "func1\n", __func__);
3952 sdio_al_release_mutex(sdio_al_dev, __func__);
3953 return;
3954 }
3955
Krishna Kondaa7af6062011-09-01 18:34:38 -07003956 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s for card %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003957 __func__, card->host->index);
3958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003959 sdio_al_dev->state = CARD_REMOVED;
3960
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003961 memset(pdev_arr, 0, sizeof(pdev_arr));
3962 sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003963
Krishna Kondaa7af6062011-09-01 18:34:38 -07003964 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: ask_reading_mailbox "
3965 "for card %d\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003966 sdio_al_dev->is_ready = false; /* Flag worker to exit */
3967 sdio_al_dev->ask_mbox = false;
3968 ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
3969
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003970 stop_and_del_timer(sdio_al_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003971
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003972 sdio_al_release_mutex(sdio_al_dev, __func__);
3973
3974 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
3975 "clients for card %d",
3976 __func__, sdio_al_dev->host->index);
3977 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
3978 if (!pdev_arr[i])
3979 continue;
3980 platform_device_unregister(pdev_arr[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003981 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003982 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
3983 "SDIO clients for card %d",
3984 __func__, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003985
Krishna Kondaa7af6062011-09-01 18:34:38 -07003986 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: vote for sleep for "
3987 "card %d\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003988 sdio_al_vote_for_sleep(sdio_al_dev, 1);
3989
Krishna Kondaa7af6062011-09-01 18:34:38 -07003990 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: flush_workqueue for "
3991 "card %d\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003992 flush_workqueue(sdio_al_dev->workqueue);
3993 destroy_workqueue(sdio_al_dev->workqueue);
3994 wake_lock_destroy(&sdio_al_dev->wake_lock);
3995
Krishna Kondaa7af6062011-09-01 18:34:38 -07003996 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: sdio card %d removed."
3997 "\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003998}
3999
4000static void sdio_print_mailbox(char *prefix_str, struct sdio_mailbox *mailbox)
4001{
4002 int k = 0;
4003 char buf[256];
4004 char buf1[10];
4005
4006 if (!mailbox) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004007 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": mailbox is "
4008 "NULL\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004009 return;
4010 }
4011
Krishna Kondaa7af6062011-09-01 18:34:38 -07004012 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: pipes 0_7: eot=0x%x,"
4013 " thresh=0x%x, overflow=0x%x, "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004014 "underflow=0x%x, mask_thresh=0x%x\n",
4015 prefix_str, mailbox->eot_pipe_0_7,
4016 mailbox->thresh_above_limit_pipe_0_7,
4017 mailbox->overflow_pipe_0_7,
4018 mailbox->underflow_pipe_0_7,
4019 mailbox->mask_thresh_above_limit_pipe_0_7);
4020
4021 memset(buf, 0, sizeof(buf));
4022 strncat(buf, ": bytes_avail:", sizeof(buf));
4023
4024 for (k = 0 ; k < SDIO_AL_ACTIVE_PIPES ; ++k) {
4025 snprintf(buf1, sizeof(buf1), "%d, ",
4026 mailbox->pipe_bytes_avail[k]);
4027 strncat(buf, buf1, sizeof(buf));
4028 }
4029
Krishna Kondaa7af6062011-09-01 18:34:38 -07004030 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME "%s", buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004031}
4032
4033static void sdio_al_print_info(void)
4034{
4035 int i = 0;
4036 int j = 0;
4037 int ret = 0;
4038 struct sdio_mailbox *mailbox = NULL;
4039 struct sdio_mailbox *hw_mailbox = NULL;
4040 struct peer_sdioc_channel_config *ch_config = NULL;
4041 struct sdio_func *func1 = NULL;
4042 struct sdio_func *lpm_func = NULL;
4043 int offset = 0;
4044 int is_ok_to_sleep = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004045 char buf[50];
4046
Maya Erezc7f63282011-10-11 12:15:23 +02004047 if (sdio_al->skip_print_info == 1)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004048 return;
4049
Maya Erezc7f63282011-10-11 12:15:23 +02004050 sdio_al->skip_print_info = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004051
Krishna Kondaa7af6062011-09-01 18:34:38 -07004052 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - SDIO DEBUG INFO\n",
4053 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004054
4055 if (!sdio_al) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004056 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - ERROR - "
4057 "sdio_al is NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004058 return;
4059 }
4060
Krishna Kondaa7af6062011-09-01 18:34:38 -07004061 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": GPIO mdm2ap_status=%d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004062 sdio_al->pdata->get_mdm2ap_status());
4063
4064 for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
4065 struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
4066
4067 if (sdio_al_dev == NULL) {
4068 continue;
4069 }
4070
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004071 if (!sdio_al_dev->host) {
4072 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Host"
4073 " is NULL\n);");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004074 continue;
4075 }
4076
4077 snprintf(buf, sizeof(buf), "Card#%d: Shadow HW MB",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004078 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004079
4080 /* printing Shadowing HW Mailbox*/
4081 mailbox = sdio_al_dev->mailbox;
4082 sdio_print_mailbox(buf, mailbox);
4083
Krishna Kondaa7af6062011-09-01 18:34:38 -07004084 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004085 "is_ok_to_sleep=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004086 sdio_al_dev->host->index,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004087 sdio_al_dev->is_ok_to_sleep);
4088
4089
Krishna Kondaa7af6062011-09-01 18:34:38 -07004090 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004091 "Shadow channels SW MB:",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004092 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004093
4094 /* printing Shadowing SW Mailbox per channel*/
4095 for (i = 0 ; i < SDIO_AL_MAX_CHANNELS ; ++i) {
4096 struct sdio_channel *ch = &sdio_al_dev->channel[i];
4097
4098 if (ch == NULL) {
4099 continue;
4100 }
4101
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03004102 if (ch->state == SDIO_CHANNEL_STATE_INVALID)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004103 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004104
4105 ch_config = &sdio_al_dev->channel[i].ch_config;
4106
Krishna Kondaa7af6062011-09-01 18:34:38 -07004107 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4108 ": Ch %s: max_rx_thres=0x%x, "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004109 "max_tx_thres=0x%x, tx_buf=0x%x, "
4110 "is_packet_mode=%d, "
4111 "max_packet=0x%x, min_write=0x%x",
4112 ch->name, ch_config->max_rx_threshold,
4113 ch_config->max_tx_threshold,
4114 ch_config->tx_buf_size,
4115 ch_config->is_packet_mode,
4116 ch_config->max_packet_size,
4117 ch->min_write_avail);
4118
Krishna Kondaa7af6062011-09-01 18:34:38 -07004119 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4120 ": total_rx=0x%x, total_tx=0x%x, "
4121 "read_avail=0x%x, write_avail=0x%x, "
4122 "rx_pending=0x%x, num_reads=0x%x, "
4123 "num_notifs=0x%x", ch->total_rx_bytes,
4124 ch->total_tx_bytes, ch->read_avail,
4125 ch->write_avail, ch->rx_pending_bytes,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004126 ch->statistics.total_read_times,
4127 ch->statistics.total_notifs);
4128 } /* end loop over all channels */
4129
4130 } /* end loop over all devices */
4131
4132 /* reading from client and printing is_host_ok_to_sleep per device */
4133 for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
4134 struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
4135
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004136 if (sdio_al_verify_func1(sdio_al_dev, __func__))
4137 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004139 if (!sdio_al_dev->host) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004140 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4141 ": Host is NULL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004142 continue;
4143 }
4144
4145 if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004146 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4147 ": %s - for Card#%d, is lpm_chan=="
4148 "INVALID_SDIO_CHAN. continuing...",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004149 __func__, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004150 continue;
4151 }
4152
4153 offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
4154 sizeof(struct peer_sdioc_channel_config) *
4155 sdio_al_dev->lpm_chan+
4156 offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
4157
4158 lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->
4159 lpm_chan+1];
4160 if (!lpm_func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004161 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4162 ": %s - lpm_func is NULL for card#%d"
4163 " continuing...\n", __func__,
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004164 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004165 continue;
4166 }
4167
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004168 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
4169 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004170 ret = sdio_memcpy_fromio(lpm_func,
4171 &is_ok_to_sleep,
4172 SDIOC_SW_MAILBOX_ADDR+offset,
4173 sizeof(int));
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004174 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004175
4176 if (ret)
Krishna Kondaa7af6062011-09-01 18:34:38 -07004177 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4178 ": %s - fail to read "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004179 "is_HOST_ok_to_sleep from mailbox for card %d",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004180 __func__, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004181 else
Krishna Kondaa7af6062011-09-01 18:34:38 -07004182 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4183 ": Card#%d: "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184 "is_HOST_ok_to_sleep=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004185 sdio_al_dev->host->index,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004186 is_ok_to_sleep);
4187 }
4188
4189 for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
4190 struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
4191
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004192 if (!sdio_al_dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004193 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004194
4195 /* Reading HW Mailbox */
4196 hw_mailbox = sdio_al_dev->mailbox;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004197
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004198 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
4199 return;
4200
4201 if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
4202 sdio_al_release_mutex(sdio_al_dev, __func__);
4203 return;
4204 }
4205 func1 = sdio_al_dev->card->sdio_func[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004206 ret = sdio_memcpy_fromio(func1, hw_mailbox,
4207 HW_MAILBOX_ADDR, sizeof(*hw_mailbox));
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004208 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004209
4210 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004211 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4212 ": fail to read "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004213 "mailbox for card#%d. "
4214 "continuing...\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004215 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004216 continue;
4217 }
4218
4219 snprintf(buf, sizeof(buf), "Card#%d: Current HW MB",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004220 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004221
4222 /* Printing HW Mailbox */
4223 sdio_print_mailbox(buf, hw_mailbox);
4224 }
4225}
4226
4227static struct sdio_device_id sdio_al_sdioid[] = {
4228 {.class = 0, .vendor = 0x70, .device = 0x2460},
4229 {.class = 0, .vendor = 0x70, .device = 0x0460},
4230 {.class = 0, .vendor = 0x70, .device = 0x23F1},
4231 {.class = 0, .vendor = 0x70, .device = 0x23F0},
4232 {}
4233};
4234
4235static struct sdio_driver sdio_al_sdiofn_driver = {
4236 .name = "sdio_al_sdiofn",
4237 .id_table = sdio_al_sdioid,
4238 .probe = sdio_al_sdio_probe,
4239 .remove = sdio_al_sdio_remove,
4240};
4241
4242#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
4243/*
4244 * Callback for notifications from restart mudule.
4245 * This function handles only the BEFORE_RESTART notification.
4246 * Stop all the activity on the card and notify our clients.
4247 */
4248static int sdio_al_subsys_notifier_cb(struct notifier_block *this,
4249 unsigned long notif_type,
4250 void *data)
4251{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004252 if (notif_type != SUBSYS_BEFORE_SHUTDOWN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004253 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: got "
4254 "notification %ld", __func__, notif_type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004255 return NOTIFY_DONE;
4256 }
4257
Konstantin Dorfman52890522011-10-05 11:03:19 +02004258 sdio_al_reset();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004259 return NOTIFY_OK;
4260}
4261
4262static struct notifier_block sdio_al_nb = {
4263 .notifier_call = sdio_al_subsys_notifier_cb,
4264};
4265#endif
4266
4267/**
4268 * Module Init.
4269 *
4270 * @warn: allocate sdio_al context before registering driver.
4271 *
4272 */
4273static int __init sdio_al_init(void)
4274{
4275 int ret = 0;
4276 int i;
4277
4278 pr_debug(MODULE_NAME ":sdio_al_init\n");
4279
4280 pr_info(MODULE_NAME ":SDIO-AL SW version %s\n",
4281 DRV_VERSION);
4282
4283 sdio_al = kzalloc(sizeof(struct sdio_al), GFP_KERNEL);
4284 if (sdio_al == NULL)
4285 return -ENOMEM;
4286
4287 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
4288 sdio_al->devices[i] = NULL;
4289
4290 sdio_al->unittest_mode = false;
4291
4292 sdio_al->debug.debug_lpm_on = debug_lpm_on;
4293 sdio_al->debug.debug_data_on = debug_data_on;
Maya Erez7ad06d82011-10-02 15:47:57 +02004294 sdio_al->debug.debug_close_on = debug_close_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004295
4296#ifdef CONFIG_DEBUG_FS
4297 sdio_al_debugfs_init();
4298#endif
4299
4300
4301#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
4302 sdio_al->subsys_notif_handle = subsys_notif_register_notifier(
4303 "external_modem", &sdio_al_nb);
4304#endif
4305
4306 ret = platform_driver_register(&msm_sdio_al_driver);
4307 if (ret) {
4308 pr_err(MODULE_NAME ": platform_driver_register failed: %d\n",
4309 ret);
4310 goto exit;
4311 }
4312
4313 sdio_register_driver(&sdio_al_sdiofn_driver);
Krishna Kondaa7af6062011-09-01 18:34:38 -07004314
4315 spin_lock_init(&sdio_al->gen_log.log_lock);
4316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004317exit:
4318 if (ret)
4319 kfree(sdio_al);
4320 return ret;
4321}
4322
4323/**
4324 * Module Exit.
4325 *
4326 * Free allocated memory.
4327 * Disable SDIO-Card.
4328 * Unregister driver.
4329 *
4330 */
4331static void __exit sdio_al_exit(void)
4332{
4333 if (sdio_al == NULL)
4334 return;
4335
4336 pr_debug(MODULE_NAME ":sdio_al_exit\n");
4337
4338#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
4339 subsys_notif_unregister_notifier(
4340 sdio_al->subsys_notif_handle, &sdio_al_nb);
4341#endif
4342
4343 sdio_al_tear_down();
4344
4345 sdio_unregister_driver(&sdio_al_sdiofn_driver);
4346
4347 kfree(sdio_al);
4348
4349#ifdef CONFIG_DEBUG_FS
4350 sdio_al_debugfs_cleanup();
4351#endif
4352
4353 platform_driver_unregister(&msm_sdio_al_driver);
4354
4355 pr_debug(MODULE_NAME ":sdio_al_exit complete\n");
4356}
4357
4358module_init(sdio_al_init);
4359module_exit(sdio_al_exit);
4360
4361MODULE_LICENSE("GPL v2");
4362MODULE_DESCRIPTION("SDIO Abstraction Layer");
4363MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
4364MODULE_VERSION(DRV_VERSION);
4365