blob: 891d655b6e3a1d9c6f1ff7041eee389d7b00cb23 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
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. */
1226 if (strcmp(ch->name, "SDIO_SMEM"))
1227 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;
2689 if (strcmp(sdio_al_dev->channel[i].name, name) == 0) {
2690 ch = &sdio_al_dev->channel[i];
2691 break;
2692 }
2693 }
2694 if (ch != NULL)
2695 break;
2696 }
2697
2698 return ch;
2699}
2700
2701/**
2702 * Find the minimal poll time.
2703 *
2704 */
2705static int get_min_poll_time_msec(struct sdio_al_device *sdio_sl_dev)
2706{
2707 int i;
2708 int poll_delay_msec = 0x0FFFFFFF;
2709
2710 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++)
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002711 if ((sdio_sl_dev->channel[i].state ==
2712 SDIO_CHANNEL_STATE_OPEN) &&
2713 (sdio_sl_dev->channel[i].poll_delay_msec > 0) &&
2714 (sdio_sl_dev->channel[i].poll_delay_msec < poll_delay_msec))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002715 poll_delay_msec =
2716 sdio_sl_dev->channel[i].poll_delay_msec;
2717
2718 if (poll_delay_msec == 0x0FFFFFFF)
2719 poll_delay_msec = SDIO_AL_POLL_TIME_NO_STREAMING;
2720
2721 pr_debug(MODULE_NAME ":poll delay time is %d msec\n", poll_delay_msec);
2722
2723 return poll_delay_msec;
2724}
2725
2726/**
2727 * Open SDIO Channel.
2728 *
2729 * Enable the channel.
2730 * Set the channel context.
2731 * Trigger reading the mailbox to check available bytes.
2732 *
2733 */
2734int sdio_open(const char *name, struct sdio_channel **ret_ch, void *priv,
2735 void (*notify)(void *priv, unsigned ch_event))
2736{
2737 int ret = 0;
2738 struct sdio_channel *ch = NULL;
2739 struct sdio_al_device *sdio_al_dev = NULL;
2740
2741 *ret_ch = NULL; /* default */
2742
2743 ch = find_channel_by_name(name);
2744 if (ch == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002745 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":Can't find "
2746 "channel name %s\n", name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002747 return -EINVAL;
2748 }
2749
2750 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002751 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002752 return -ENODEV;
2753
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002754 if ((ch->state != SDIO_CHANNEL_STATE_IDLE) &&
2755 (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002756 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Wrong ch %s "
2757 "state %d\n", name, ch->state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758 ret = -EPERM;
2759 goto exit_err;
2760 }
2761
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002762 if (sdio_al_dev->is_err) {
2763 SDIO_AL_ERR(__func__);
2764 ret = -ENODEV;
2765 goto exit_err;
2766 }
2767
Maya Erez7b1ebd22011-08-20 20:53:24 +03002768 ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002769 if (ret)
2770 goto exit_err;
2771
2772 ch->notify = notify;
2773 ch->priv = priv;
2774
2775 /* Note: Set caller returned context before interrupts are enabled */
2776 *ret_ch = ch;
2777
2778 ret = open_channel(ch);
2779 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002780 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
2781 "err=%d\n", name, -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002782 goto exit_err;
2783 }
2784
Maya Erez7ad06d82011-10-02 15:47:57 +02002785 CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
2786 "completed OK\n", name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002787 if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
2788 if (sdio_al->sdioc_major == PEER_SDIOC_OLD_VERSION_MAJOR) {
2789 if (!ch->is_packet_mode) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002790 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
2791 ":setting channel %s as "
2792 "lpm_chan\n", name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002793 sdio_al_dev->lpm_chan = ch->num;
2794 }
2795 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002796 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": "
2797 "setting channel %s as lpm_chan\n",
2798 name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002799 sdio_al_dev->lpm_chan = ch->num;
2800 }
2801 }
2802
2803exit_err:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002804 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805 return ret;
2806}
2807EXPORT_SYMBOL(sdio_open);
2808
2809/**
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002810 * Request peer operation
2811 * note: sanity checks of parameters done by caller
2812 * called under bus locked
2813 */
2814static int peer_set_operation(u32 opcode,
2815 struct sdio_al_device *sdio_al_dev,
2816 struct sdio_channel *ch)
2817{
2818 int ret;
2819 int offset;
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07002820 struct sdio_func *wk_func = NULL;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002821 u32 peer_operation;
2822 int loop_count = 0;
2823
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07002824 if (!sdio_al_dev->card ||
2825 !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
2826 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
2827 ": NULL card or wk_func\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002828 ret = -ENODEV;
2829 goto exit;
2830 }
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07002831 wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
2832
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002833 /* calculate offset of peer_operation field in sw mailbox struct */
2834 offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config) +
2835 sizeof(struct peer_sdioc_channel_config) * ch->num +
2836 offsetof(struct peer_sdioc_channel_config, peer_operation);
2837
Maya Erez7b1ebd22011-08-20 20:53:24 +03002838 ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002839 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002840 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
2841 "wake up\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002842 goto exit;
2843 }
2844 /* request operation from MDM peer */
2845 peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_INIT);
2846 ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
2847 &peer_operation, sizeof(u32));
2848 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002849 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
2850 "request close operation\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002851 goto exit;
2852 }
2853 ret = sdio_al_enable_func_retry(wk_func, "wk_func");
2854 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002855 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to enable"
2856 " Func#%d\n", wk_func->num);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002857 goto exit;
2858 }
2859 pr_debug(MODULE_NAME ":%s: wk_func enabled on ch %s\n",
2860 __func__, ch->name);
2861 /* send "start" operation to MDM */
2862 peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_START);
2863 ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
2864 &peer_operation, sizeof(u32));
2865 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002866 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
2867 "send start close operation\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002868 goto exit;
2869 }
2870 ret = sdio_disable_func(wk_func);
2871 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002872 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
2873 "disable Func#%d\n", wk_func->num);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002874 goto exit;
2875 }
2876 /* poll for peer operation ack */
2877 while (peer_operation != 0) {
2878 ret = sdio_memcpy_fromio(ch->func,
2879 &peer_operation,
2880 SDIOC_SW_MAILBOX_ADDR+offset,
2881 sizeof(u32));
2882 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002883 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
2884 ":failed to request ack on close"
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002885 " operation, loop_count = %d\n",
2886 loop_count);
2887 goto exit;
2888 }
2889 loop_count++;
2890 if (loop_count > 10) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002891 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
2892 "peer_operation=0x%x wait loop"
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002893 " %d on ch %s\n", __func__,
2894 peer_operation, loop_count, ch->name);
2895 }
2896 }
2897exit:
2898 return ret;
2899}
2900
Konstantin Dorfman52890522011-10-05 11:03:19 +02002901static int channel_close(struct sdio_channel *ch, int flush_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002902{
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002903 int ret;
2904 struct sdio_al_device *sdio_al_dev = NULL;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002905 int flush_len;
2906 ulong flush_expires;
2907
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002908 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002909 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
2910 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002911 return -ENODEV;
2912 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002913
2914 if (!ch->func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002915 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL func"
2916 " on channel:%d\n", __func__, ch->num);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002917 return -ENODEV;
2918 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002919
2920 sdio_al_dev = ch->sdio_al_dev;
2921 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
2922 return -ENODEV;
2923
2924 if (!sdio_al_dev->ch_close_supported) {
2925 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: Not "
2926 "supported by mdm, ch %s\n",
2927 __func__, ch->name);
2928 ret = -ENOTSUPP;
2929 goto error_exit;
2930 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002931
2932 if (sdio_al_dev->is_err) {
2933 SDIO_AL_ERR(__func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002934 ret = -ENODEV;
2935 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002936 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02002937 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
2938 sdio_al_loge(sdio_al_dev->dev_log,
2939 MODULE_NAME ":%s: ch %s is not in "
2940 "open state (%d)\n",
2941 __func__, ch->name, ch->state);
2942 ret = -ENODEV;
2943 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002944 }
2945 ch->state = SDIO_CHANNEL_STATE_CLOSING;
2946 ret = peer_set_operation(PEER_OP_CODE_CLOSE, sdio_al_dev, ch);
2947 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002948 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
2949 "peer_set_operation() failed: %d\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002950 __func__, ret);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002951 ret = -ENODEV;
2952 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002953 }
2954 /* udate poll time for opened channels */
2955 if (ch->poll_delay_msec > 0) {
2956 sdio_al_dev->poll_delay_msec =
2957 get_min_poll_time_msec(sdio_al_dev);
2958 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002959 sdio_al_release_mutex(ch->sdio_al_dev, __func__);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002960
2961 flush_expires = jiffies +
2962 msecs_to_jiffies(SDIO_CLOSE_FLUSH_TIMEOUT_MSEC);
2963 /* flush rx packets of the channel */
Konstantin Dorfman52890522011-10-05 11:03:19 +02002964 if (flush_flag) {
2965 do {
2966 while (ch->read_avail > 0) {
2967 flush_len = ch->read_avail;
2968 ret = sdio_read_internal(ch,
2969 sdio_al_dev->rx_flush_buf,
2970 flush_len);
2971 if (ret) {
2972 sdio_al_loge(&sdio_al->gen_log,
2973 MODULE_NAME ":%s sdio_read"
2974 " failed: %d, ch %s\n",
2975 __func__, ret,
2976 ch->name);
2977 return ret;
2978 }
Yaniv Gardic4663632011-08-31 19:55:38 +03002979
Konstantin Dorfman52890522011-10-05 11:03:19 +02002980 if (time_after(jiffies, flush_expires) != 0) {
2981 sdio_al_loge(&sdio_al->gen_log,
2982 MODULE_NAME ":%s flush rx "
2983 "packets timeout: ch %s\n",
Krishna Kondaa7af6062011-09-01 18:34:38 -07002984 __func__, ch->name);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002985 sdio_al_get_into_err_state(sdio_al_dev);
2986 return -EBUSY;
2987 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002988 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02002989 msleep(100);
2990 if (ch->signature != SDIO_AL_SIGNATURE) {
2991 sdio_al_loge(&sdio_al->gen_log,
2992 MODULE_NAME ":%s: after sleep,"
2993 " invalid signature"
2994 " 0x%x\n", __func__,
2995 ch->signature);
2996 return -ENODEV;
2997 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002998 if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
2999 __func__))
Konstantin Dorfman52890522011-10-05 11:03:19 +02003000 return -ENODEV;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003001
Konstantin Dorfman52890522011-10-05 11:03:19 +02003002 ret = read_mailbox(sdio_al_dev, false);
3003 if (ret) {
3004 sdio_al_loge(&sdio_al->gen_log,
3005 MODULE_NAME ":%s: failed to"
3006 " read mailbox", __func__);
3007 goto error_exit;
3008 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003009 sdio_al_release_mutex(ch->sdio_al_dev, __func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003010 } while (ch->read_avail > 0);
3011 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003012 if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
3013 __func__))
3014 return -ENODEV;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003015 /* disable function to be able to open the channel again */
3016 ret = sdio_disable_func(ch->func);
3017 if (ret) {
Konstantin Dorfman52890522011-10-05 11:03:19 +02003018 sdio_al_loge(&sdio_al->gen_log,
3019 MODULE_NAME ":Fail to disable Func#%d\n",
3020 ch->func->num);
3021 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003022 }
3023 ch->state = SDIO_CHANNEL_STATE_CLOSED;
Maya Erez7ad06d82011-10-02 15:47:57 +02003024 CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":%s: Ch %s closed "
3025 "successfully\n", __func__, ch->name);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003026
3027error_exit:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003028 sdio_al_release_mutex(ch->sdio_al_dev, __func__);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003029
3030 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003031}
Konstantin Dorfman52890522011-10-05 11:03:19 +02003032
3033/**
3034 * Close SDIO Channel.
3035 *
3036 */
3037int sdio_close(struct sdio_channel *ch)
3038{
3039 return channel_close(ch, true);
3040}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003041EXPORT_SYMBOL(sdio_close);
3042
3043/**
3044 * Get the number of available bytes to write.
3045 *
3046 */
3047int sdio_write_avail(struct sdio_channel *ch)
3048{
3049 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003050 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3051 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052 return -ENODEV;
3053 }
3054 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003055 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
3056 "Invalid signature 0x%x\n", __func__,
3057 ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003058 return -ENODEV;
3059 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003060 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003061 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
3062 "channel %s state is not open (%d)\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003063 __func__, ch->name, ch->state);
3064 return -ENODEV;
3065 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 pr_debug(MODULE_NAME ":sdio_write_avail %s 0x%x\n",
3067 ch->name, ch->write_avail);
3068
3069 return ch->write_avail;
3070}
3071EXPORT_SYMBOL(sdio_write_avail);
3072
3073/**
3074 * Get the number of available bytes to read.
3075 *
3076 */
3077int sdio_read_avail(struct sdio_channel *ch)
3078{
3079 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003080 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3081 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003082 return -ENODEV;
3083 }
3084 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003085 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
3086 "Invalid signature 0x%x\n", __func__,
3087 ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088 return -ENODEV;
3089 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003090 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003091 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
3092 "channel %s state is not open (%d)\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003093 __func__, ch->name, ch->state);
3094 return -ENODEV;
3095 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003096 pr_debug(MODULE_NAME ":sdio_read_avail %s 0x%x\n",
3097 ch->name, ch->read_avail);
3098
3099 return ch->read_avail;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003100}
3101EXPORT_SYMBOL(sdio_read_avail);
3102
Maya Erez5795e0d2011-09-12 20:20:06 +03003103static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len)
3104{
3105 int ret = 0;
3106 struct sdio_al_device *sdio_al_dev = NULL;
3107
3108 if (!ch) {
Konstantin Dorfman52890522011-10-05 11:03:19 +02003109 sdio_al_loge(ch->sdio_al_dev->dev_log,
3110 MODULE_NAME ":%s: NULL channel\n", __func__);
Maya Erez5795e0d2011-09-12 20:20:06 +03003111 return -ENODEV;
3112 }
3113
3114 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003115 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
3116 return -ENODEV;
Maya Erez5795e0d2011-09-12 20:20:06 +03003117
3118 ret = sdio_memcpy_fromio(ch->func, sdio_al_dev->rx_flush_buf,
3119 PIPE_RX_FIFO_ADDR, len);
3120
3121 if (ret) {
Konstantin Dorfman52890522011-10-05 11:03:19 +02003122 sdio_al_loge(ch->sdio_al_dev->dev_log,
3123 MODULE_NAME ":ch %s: %s err=%d, len=%d\n",
Maya Erez5795e0d2011-09-12 20:20:06 +03003124 ch->name, __func__, -ret, len);
3125 sdio_al_dev->is_err = true;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003126 sdio_al_release_mutex(sdio_al_dev, __func__);
Maya Erez5795e0d2011-09-12 20:20:06 +03003127 return ret;
3128 }
3129
3130 restart_inactive_time(sdio_al_dev);
3131
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003132 sdio_al_release_mutex(sdio_al_dev, __func__);
Maya Erez5795e0d2011-09-12 20:20:06 +03003133
3134 return 0;
3135}
3136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137/**
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003138 * Internal read from SDIO Channel.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003139 *
3140 * Reading from the pipe will trigger interrupt if there are
3141 * other pending packets on the SDIO-Client.
3142 *
3143 */
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003144static int sdio_read_internal(struct sdio_channel *ch, void *data, int len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003145{
3146 int ret = 0;
3147 struct sdio_al_device *sdio_al_dev = NULL;
3148
3149 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003150 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3151 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003152 return -ENODEV;
3153 }
3154 if (!data) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003155 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
3156 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003157 return -ENODEV;
3158 }
3159 if (len == 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003160 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
3161 " to read 0 bytes\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003162 return -EINVAL;
3163 }
3164
3165 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003166 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
3167 "signature 0x%x\n", __func__, ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003168 return -ENODEV;
3169 }
3170
3171 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003172 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003173 return -ENODEV;
3174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003175 if (sdio_al_dev->is_err) {
3176 SDIO_AL_ERR(__func__);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003177 ret = -ENODEV;
3178 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003179 }
3180
3181 /* lpm policy says we can't go to sleep when we have pending rx data,
3182 so either we had rx interrupt and woken up, or we never went to
3183 sleep */
3184 if (sdio_al_dev->is_ok_to_sleep) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003185 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: called "
3186 "when is_ok_to_sleep is set for ch %s, len=%d,"
3187 " last_any_read_avail=%d, last_read_avail=%d, "
3188 "last_old_read_avail=%d", __func__, ch->name,
3189 len, ch->statistics.last_any_read_avail,
3190 ch->statistics.last_read_avail,
3191 ch->statistics.last_old_read_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003192 }
3193 BUG_ON(sdio_al_dev->is_ok_to_sleep);
3194
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003195 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
3196 (ch->state != SDIO_CHANNEL_STATE_CLOSING)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003197 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s wrong "
3198 "channel %s state %d\n",
3199 __func__, ch->name, ch->state);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003200 ret = -EINVAL;
3201 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202 }
3203
Krishna Kondaa7af6062011-09-01 18:34:38 -07003204 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s read %d "
3205 "avail %d.\n", ch->name, len, ch->read_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003206
3207 restart_inactive_time(sdio_al_dev);
3208
3209 if ((ch->is_packet_mode) && (len != ch->read_avail)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003210 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_read ch "
3211 "%s len != read_avail\n", ch->name);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003212 ret = -EINVAL;
3213 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214 }
3215
3216 if (len > ch->read_avail) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003217 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
3218 "reading more bytes (%d) than the avail(%d).\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003219 ch->name, len, ch->read_avail);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003220 ret = -ENOMEM;
3221 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003222 }
3223
3224 ret = sdio_memcpy_fromio(ch->func, data, PIPE_RX_FIFO_ADDR, len);
3225
3226 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003227 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ch %s: "
3228 "sdio_read err=%d, len=%d, read_avail=%d, "
3229 "last_read_avail=%d, last_old_read_avail=%d\n",
Maya Erezd9cc2292011-08-04 09:20:31 +03003230 ch->name, -ret, len, ch->read_avail,
3231 ch->statistics.last_read_avail,
3232 ch->statistics.last_old_read_avail);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003233 sdio_al_get_into_err_state(sdio_al_dev);
3234 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003235 }
3236
3237 ch->statistics.total_read_times++;
3238
3239 /* Remove handled packet from the list regardless if ret is ok */
3240 if (ch->is_packet_mode)
3241 remove_handled_rx_packet(ch);
3242 else
3243 ch->read_avail -= len;
3244
3245 ch->total_rx_bytes += len;
Krishna Kondaa7af6062011-09-01 18:34:38 -07003246 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s read %d "
3247 "avail %d total %d.\n", ch->name, len,
3248 ch->read_avail, ch->total_rx_bytes);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003249
3250 if ((ch->read_avail == 0) && !(ch->is_packet_mode))
3251 ask_reading_mailbox(sdio_al_dev);
3252
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003253exit:
3254 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003255
3256 return ret;
3257}
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003258
3259/**
3260 * Read from SDIO Channel.
3261 *
3262 * Reading from the pipe will trigger interrupt if there are
3263 * other pending packets on the SDIO-Client.
3264 *
3265 */
3266int sdio_read(struct sdio_channel *ch, void *data, int len)
3267{
3268 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003269 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3270 "channel\n", __func__);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003271 return -ENODEV;
3272 }
3273 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003274 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
3275 "Invalid signature 0x%x\n", __func__, ch->signature);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003276 return -ENODEV;
3277 }
3278 if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
3279 return sdio_read_internal(ch, data, len);
3280 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003281 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME
3282 ":%s: Invalid channel %s state %d\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003283 __func__, ch->name, ch->state);
3284 }
3285 return -ENODEV;
3286}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003287EXPORT_SYMBOL(sdio_read);
3288
3289/**
3290 * Write to SDIO Channel.
3291 *
3292 */
3293int sdio_write(struct sdio_channel *ch, const void *data, int len)
3294{
3295 int ret = 0;
3296 struct sdio_al_device *sdio_al_dev = NULL;
3297
3298 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003299 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3300 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301 return -ENODEV;
3302 }
3303 if (!data) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003304 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
3305 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003306 return -ENODEV;
3307 }
3308 if (len == 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003309 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
3310 " to write 0 bytes\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003311 return -EINVAL;
3312 }
3313
3314 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003315 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
3316 "signature 0x%x\n", __func__, ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003317 return -ENODEV;
3318 }
3319
3320 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003321 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003322 return -ENODEV;
3323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003324 WARN_ON(len > ch->write_avail);
3325
3326 if (sdio_al_dev->is_err) {
3327 SDIO_AL_ERR(__func__);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003328 ret = -ENODEV;
3329 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003330 }
3331
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003332 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003333 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":writing to "
3334 "closed channel %s\n", ch->name);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003335 ret = -EINVAL;
3336 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003337 }
3338
3339 if (sdio_al_dev->is_ok_to_sleep) {
Maya Erez7b1ebd22011-08-20 20:53:24 +03003340 ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003341 if (ret)
3342 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003343 } else {
3344 restart_inactive_time(sdio_al_dev);
3345 }
3346
Krishna Kondaa7af6062011-09-01 18:34:38 -07003347 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s write %d "
3348 "avail %d.\n", ch->name, len, ch->write_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349
3350 if (len > ch->write_avail) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003351 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
3352 "write more bytes (%d) than available %d.\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353 ch->name, len, ch->write_avail);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003354 ret = -ENOMEM;
3355 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003356 }
3357
3358 ret = sdio_ch_write(ch, data, len);
3359 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003360 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_write "
3361 "on channel %s err=%d\n", ch->name, -ret);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003362 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003363 }
3364
3365 ch->total_tx_bytes += len;
Krishna Kondaa7af6062011-09-01 18:34:38 -07003366 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s write %d "
3367 "avail %d total %d.\n", ch->name, len,
3368 ch->write_avail, ch->total_tx_bytes);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003369
3370 /* Round up to whole buffer size */
3371 len = ROUND_UP(len, ch->peer_tx_buf_size);
3372 /* Protect from wraparound */
3373 len = min(len, (int) ch->write_avail);
3374 ch->write_avail -= len;
3375
3376 if (ch->write_avail < ch->min_write_avail)
3377 ask_reading_mailbox(sdio_al_dev);
3378
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003379exit:
3380 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003381
3382 return ret;
3383}
3384EXPORT_SYMBOL(sdio_write);
3385
3386static int __devinit msm_sdio_al_probe(struct platform_device *pdev)
3387{
3388 if (!sdio_al) {
3389 pr_err(MODULE_NAME ": %s: NULL sdio_al\n", __func__);
3390 return -ENODEV;
3391 }
3392
3393 sdio_al->pdata = pdev->dev.platform_data;
3394 return 0;
3395}
3396
3397static int __devexit msm_sdio_al_remove(struct platform_device *pdev)
3398{
3399 return 0;
3400}
3401
Konstantin Dorfman52890522011-10-05 11:03:19 +02003402static void sdio_al_close_all_channels(struct sdio_al_device *sdio_al_dev)
Maya Erez6862b142011-08-22 09:07:07 +03003403{
Konstantin Dorfman52890522011-10-05 11:03:19 +02003404 int j;
Maya Erez6862b142011-08-22 09:07:07 +03003405 int ret;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003406 struct sdio_channel *ch = NULL;
Maya Erez6862b142011-08-22 09:07:07 +03003407
Konstantin Dorfman52890522011-10-05 11:03:19 +02003408 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
Maya Erez6862b142011-08-22 09:07:07 +03003409
Konstantin Dorfman52890522011-10-05 11:03:19 +02003410 if (!sdio_al_dev) {
3411 sdio_al_loge(sdio_al_dev->dev_log,
3412 MODULE_NAME ": %s: NULL device", __func__);
3413 return;
3414 }
3415 for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
3416 ch = &sdio_al_dev->channel[j];
3417
3418 if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
3419 sdio_al_loge(sdio_al_dev->dev_log,
3420 MODULE_NAME ": %s: Call to sdio_close() for"
3421 " ch %s\n", __func__, ch->name);
3422 ret = channel_close(ch, false);
3423 if (ret) {
3424 sdio_al_loge(sdio_al_dev->dev_log,
3425 MODULE_NAME ": %s: failed sdio_close()"
3426 " for ch %s (%d)\n",
3427 __func__, ch->name, ret);
3428 }
3429 } else {
3430 pr_debug(MODULE_NAME ": %s: skip sdio_close() ch %s"
3431 " (state=%d)\n", __func__,
3432 ch->name, ch->state);
Maya Erez6862b142011-08-22 09:07:07 +03003433 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02003434 }
3435}
3436
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003437static void sdio_al_invalidate_sdio_clients(struct sdio_al_device *sdio_al_dev,
3438 struct platform_device **pdev_arr)
3439{
3440 int j;
3441
3442 pr_debug(MODULE_NAME ": %s: Notifying SDIO clients for card %d",
3443 __func__, sdio_al_dev->host->index);
3444 for (j = 0; j < SDIO_AL_MAX_CHANNELS; ++j) {
3445 if (sdio_al_dev->channel[j].state ==
3446 SDIO_CHANNEL_STATE_INVALID)
3447 continue;
3448 pdev_arr[j] = sdio_al_dev->channel[j].pdev;
3449 sdio_al_dev->channel[j].signature = 0x0;
3450 sdio_al_dev->channel[j].state =
3451 SDIO_CHANNEL_STATE_INVALID;
3452 }
3453}
3454
3455static void sdio_al_modem_reset_operations(struct sdio_al_device
Konstantin Dorfman52890522011-10-05 11:03:19 +02003456 *sdio_al_dev)
3457{
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003458 int ret = 0;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003459 struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
3460 int j;
3461
Konstantin Dorfman52890522011-10-05 11:03:19 +02003462 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
3463
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003464 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Konstantin Dorfman52890522011-10-05 11:03:19 +02003465 return;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003466
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003467 if (sdio_al_dev->state == CARD_REMOVED) {
3468 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
3469 "card %d is already removed", __func__,
3470 sdio_al_dev->host->index);
3471 goto exit_err;
3472 }
3473
3474 if (sdio_al_dev->state == MODEM_RESTART) {
3475 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: "
3476 "card %d was already notified for modem reset",
3477 __func__, sdio_al_dev->host->index);
3478 goto exit_err;
3479 }
3480
3481 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: Set the "
3482 "state to MODEM_RESTART for card %d",
3483 __func__, sdio_al_dev->host->index);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003484 sdio_al_dev->state = MODEM_RESTART;
3485 sdio_al_dev->is_ready = false;
Maya Erez6862b142011-08-22 09:07:07 +03003486
Konstantin Dorfman52890522011-10-05 11:03:19 +02003487 /* Stop mailbox timer */
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003488 stop_and_del_timer(sdio_al_dev);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003489
Konstantin Dorfman52890522011-10-05 11:03:19 +02003490 if ((sdio_al_dev->is_ok_to_sleep) &&
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003491 (!sdio_al_dev->is_err)) {
3492 pr_debug(MODULE_NAME ": %s: wakeup modem for "
3493 "card %d", __func__,
3494 sdio_al_dev->host->index);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003495 ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
Maya Erez6862b142011-08-22 09:07:07 +03003496 }
3497
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07003498 if (!ret && (!sdio_al_dev->is_err) && sdio_al_dev->card &&
3499 sdio_al_dev->card->sdio_func[0]) {
3500 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003501 ": %s: sdio_release_irq for card %d",
3502 __func__,
3503 sdio_al_dev->host->index);
Venkat Gopalakrishnana3dc62f2011-10-11 13:07:53 -07003504 sdio_release_irq(sdio_al_dev->card->sdio_func[0]);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003505 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003506
3507 memset(pdev_arr, 0, sizeof(pdev_arr));
3508 sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
3509
3510 sdio_al_release_mutex(sdio_al_dev, __func__);
3511
3512 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
3513 "clients for card %d",
3514 __func__, sdio_al_dev->host->index);
3515 for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
3516 if (!pdev_arr[j])
3517 continue;
3518 platform_device_unregister(pdev_arr[j]);
3519 }
3520 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
3521 "SDIO clients for card %d",
3522 __func__, sdio_al_dev->host->index);
3523
3524 return;
3525
3526exit_err:
3527 sdio_al_release_mutex(sdio_al_dev, __func__);
3528 return;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003529}
3530
3531#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
3532static void sdio_al_reset(void)
3533{
3534 int i;
3535 struct sdio_al_device *sdio_al_dev;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003536
3537 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
3538
Maya Erez6862b142011-08-22 09:07:07 +03003539 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
Maya Erez6862b142011-08-22 09:07:07 +03003540 if (sdio_al->devices[i] == NULL) {
3541 pr_debug(MODULE_NAME ": %s: NULL device in index %d",
Konstantin Dorfman52890522011-10-05 11:03:19 +02003542 __func__, i);
Maya Erez6862b142011-08-22 09:07:07 +03003543 continue;
3544 }
3545 sdio_al_dev = sdio_al->devices[i];
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003546 sdio_al_modem_reset_operations(sdio_al->devices[i]);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003547 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003548
3549 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s completed", __func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003550}
3551#endif
Maya Erez6862b142011-08-22 09:07:07 +03003552
Konstantin Dorfman52890522011-10-05 11:03:19 +02003553static void msm_sdio_al_shutdown(struct platform_device *pdev)
3554{
3555 int i;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003556 struct sdio_al_device *sdio_al_dev;
3557
3558 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME
3559 "Initiating msm_sdio_al_shutdown...");
3560
3561 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
3562 if (sdio_al->devices[i] == NULL) {
3563 pr_debug(MODULE_NAME ": %s: NULL device in index %d",
3564 __func__, i);
3565 continue;
Maya Erez8afd5642011-08-24 15:57:06 +03003566 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02003567 sdio_al_dev = sdio_al->devices[i];
Maya Erez6862b142011-08-22 09:07:07 +03003568
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003569 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
3570 return;
Maya Erez6862b142011-08-22 09:07:07 +03003571
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003572 if (sdio_al_dev->ch_close_supported)
3573 sdio_al_close_all_channels(sdio_al_dev);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003574
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003575 sdio_al_release_mutex(sdio_al_dev, __func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003576
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003577 sdio_al_modem_reset_operations(sdio_al_dev);
Maya Erez6862b142011-08-22 09:07:07 +03003578 }
Krishna Kondaa7af6062011-09-01 18:34:38 -07003579 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
3580 "msm_sdio_al_shutdown complete.", __func__);
Maya Erez6862b142011-08-22 09:07:07 +03003581}
3582
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003583static struct platform_driver msm_sdio_al_driver = {
3584 .probe = msm_sdio_al_probe,
3585 .remove = __exit_p(msm_sdio_al_remove),
Maya Erez6862b142011-08-22 09:07:07 +03003586 .shutdown = msm_sdio_al_shutdown,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003587 .driver = {
3588 .name = "msm_sdio_al",
3589 },
3590};
3591
3592/**
3593 * Initialize SDIO_AL channels.
3594 *
3595 */
3596static int init_channels(struct sdio_al_device *sdio_al_dev)
3597{
3598 int ret = 0;
3599 int i;
3600
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003601 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003602 return -ENODEV;
3603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003604 ret = read_sdioc_software_header(sdio_al_dev,
3605 sdio_al_dev->sdioc_sw_header);
3606 if (ret)
3607 goto exit;
3608
3609 ret = sdio_al_setup(sdio_al_dev);
3610 if (ret)
3611 goto exit;
3612
3613 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
3614 int ch_name_size;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003615 if (sdio_al_dev->channel[i].state == SDIO_CHANNEL_STATE_INVALID)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003616 continue;
3617 if (sdio_al->unittest_mode) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003618 memset(sdio_al_dev->channel[i].ch_test_name, 0,
3619 sizeof(sdio_al_dev->channel[i].ch_test_name));
3620 ch_name_size = strnlen(sdio_al_dev->channel[i].name,
3621 CHANNEL_NAME_SIZE);
3622 strncpy(sdio_al_dev->channel[i].ch_test_name,
3623 sdio_al_dev->channel[i].name,
3624 ch_name_size);
3625 strncat(sdio_al_dev->channel[i].ch_test_name +
3626 ch_name_size,
3627 SDIO_TEST_POSTFIX,
3628 SDIO_TEST_POSTFIX_SIZE);
3629 pr_debug(MODULE_NAME ":pdev.name = %s\n",
3630 sdio_al_dev->channel[i].ch_test_name);
3631 sdio_al_dev->channel[i].pdev = platform_device_alloc(
3632 sdio_al_dev->channel[i].ch_test_name, -1);
3633 } else {
3634 pr_debug(MODULE_NAME ":pdev.name = %s\n",
3635 sdio_al_dev->channel[i].name);
3636 sdio_al_dev->channel[i].pdev = platform_device_alloc(
3637 sdio_al_dev->channel[i].name, -1);
3638 }
3639 if (!sdio_al_dev->channel[i].pdev) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003640 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
3641 ":NULL platform device for ch %s",
3642 sdio_al_dev->channel[i].name);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003643 sdio_al_dev->channel[i].state =
3644 SDIO_CHANNEL_STATE_INVALID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003645 continue;
3646 }
3647 ret = platform_device_add(sdio_al_dev->channel[i].pdev);
3648 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003649 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
3650 ":platform_device_add failed, "
3651 "ret=%d\n", ret);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003652 sdio_al_dev->channel[i].state =
3653 SDIO_CHANNEL_STATE_INVALID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003654 }
3655 }
3656
3657exit:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003658 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003659 return ret;
3660}
3661
3662/**
3663 * Initialize SDIO_AL channels according to the client setup.
3664 * This function also check if the client is in boot mode and
3665 * flashless boot is required to be activated or the client is
3666 * up and running.
3667 *
3668 */
3669static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev)
3670{
3671 int ret = 0;
3672 struct sdio_func *func1;
3673 int signature = 0;
3674
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003675 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003676 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003677
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003678 if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
3679 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":NULL card or "
3680 "func1\n");
3681 sdio_al_release_mutex(sdio_al_dev, __func__);
3682 return -ENODEV;
3683 }
3684 func1 = sdio_al_dev->card->sdio_func[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003685
3686 /* Read the header signature to determine the status of the MDM
3687 * SDIO Client
3688 */
3689 signature = sdio_readl(func1, SDIOC_SW_HEADER_ADDR, &ret);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003690 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003691 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003692 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
3693 "signature from sw header.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003694 return ret;
3695 }
3696
3697 switch (signature) {
3698 case PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE:
3699 if (sdio_al_dev == sdio_al->bootloader_dev) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003700 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":setup "
3701 "bootloader on card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003702 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 return sdio_al_bootloader_setup();
3704 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003705 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":wait "
3706 "for bootloader completion "
3707 "on card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003708 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003709 return sdio_al_wait_for_bootloader_comp(sdio_al_dev);
3710 }
3711 case PEER_SDIOC_SW_MAILBOX_SIGNATURE:
3712 case PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE:
3713 return init_channels(sdio_al_dev);
3714 default:
Krishna Kondaa7af6062011-09-01 18:34:38 -07003715 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
3716 "signature 0x%x\n", signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003717 return -EINVAL;
3718 }
3719
3720 return 0;
3721}
3722
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003723static void clean_sdio_al_device_data(struct sdio_al_device *sdio_al_dev)
3724{
3725 sdio_al_dev->is_ready = 0;
3726 sdio_al_dev->bootloader_done = 0;
3727 sdio_al_dev->lpm_chan = 0;
3728 sdio_al_dev->is_ok_to_sleep = 0;
3729 sdio_al_dev->inactivity_time = 0;
3730 sdio_al_dev->poll_delay_msec = 0;
3731 sdio_al_dev->is_timer_initialized = 0;
3732 sdio_al_dev->is_err = 0;
3733 sdio_al_dev->is_suspended = 0;
3734 sdio_al_dev->flashless_boot_on = 0;
3735 sdio_al_dev->ch_close_supported = 0;
3736 sdio_al_dev->print_after_interrupt = 0;
3737 memset(sdio_al_dev->sdioc_sw_header, 0,
3738 sizeof(*sdio_al_dev->sdioc_sw_header));
3739 memset(sdio_al_dev->mailbox, 0, sizeof(*sdio_al_dev->mailbox));
3740 memset(sdio_al_dev->rx_flush_buf, 0,
3741 sizeof(*sdio_al_dev->rx_flush_buf));
3742}
3743
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003744/*
3745 * SDIO driver functions
3746 */
3747static int sdio_al_sdio_probe(struct sdio_func *func,
3748 const struct sdio_device_id *sdio_dev_id)
3749{
3750 int ret = 0;
3751 struct sdio_al_device *sdio_al_dev = NULL;
3752 int i;
3753 struct mmc_card *card = NULL;
3754
3755 if (!func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003756 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
3757 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003758 return -ENODEV;
3759 }
3760 card = func->card;
3761
3762 if (!card) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003763 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
3764 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003765 return -ENODEV;
3766 }
3767
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003768 if (!card->sdio_func[0]) {
3769 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
3770 "func1\n",
3771 __func__);
3772 return -ENODEV;
3773 }
3774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775 if (card->sdio_funcs < SDIO_AL_MAX_FUNCS) {
3776 dev_info(&card->dev,
3777 "SDIO-functions# %d less than expected.\n",
3778 card->sdio_funcs);
3779 return -ENODEV;
3780 }
3781
3782 /* Check if there is already a device for this card */
3783 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
3784 if (sdio_al->devices[i] == NULL)
3785 continue;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003786 if (sdio_al->devices[i]->host == card->host) {
3787 sdio_al_dev = sdio_al->devices[i];
3788 if (sdio_al_dev->state == CARD_INSERTED)
3789 return 0;
3790 clean_sdio_al_device_data(sdio_al_dev);
3791 break;
3792 }
3793 }
3794
3795 if (!sdio_al_dev) {
3796 sdio_al_dev = kzalloc(sizeof(struct sdio_al_device),
3797 GFP_KERNEL);
3798 if (sdio_al_dev == NULL)
3799 return -ENOMEM;
3800
3801 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
3802 if (sdio_al->devices[i] == NULL) {
3803 sdio_al->devices[i] = sdio_al_dev;
3804 sdio_al_dev->dev_log = &sdio_al->device_log[i];
3805 spin_lock_init(&sdio_al_dev->dev_log->log_lock);
3806 #ifdef CONFIG_DEBUG_FS
3807 sdio_al_dbgfs_log[i].data =
3808 sdio_al_dev->dev_log->buffer;
3809 sdio_al_dbgfs_log[i].size =
3810 SDIO_AL_DEBUG_LOG_SIZE;
3811 #endif
3812 break;
3813 }
3814 if (i == MAX_NUM_OF_SDIO_DEVICES) {
3815 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":No space "
3816 "in devices array for the device\n");
3817 return -ENOMEM;
3818 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003819 }
3820
3821 dev_info(&card->dev, "SDIO Card claimed.\n");
Maya Erezc7f63282011-10-11 12:15:23 +02003822 sdio_al->skip_print_info = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003823
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824 sdio_al_dev->state = CARD_INSERTED;
3825
3826 if (card->host->index == SDIO_BOOTLOADER_CARD_INDEX)
3827 sdio_al->bootloader_dev = sdio_al_dev;
3828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003829 sdio_al_dev->is_ready = false;
3830
3831 sdio_al_dev->signature = SDIO_AL_SIGNATURE;
3832
3833 sdio_al_dev->is_suspended = 0;
3834 sdio_al_dev->is_timer_initialized = false;
3835
3836 sdio_al_dev->lpm_chan = INVALID_SDIO_CHAN;
3837
3838 sdio_al_dev->card = card;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003839 sdio_al_dev->host = card->host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003840
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003841 if (!sdio_al_dev->mailbox) {
3842 sdio_al_dev->mailbox = kzalloc(sizeof(struct sdio_mailbox),
3843 GFP_KERNEL);
3844 if (sdio_al_dev->mailbox == NULL)
3845 return -ENOMEM;
3846 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003847
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003848 if (!sdio_al_dev->sdioc_sw_header) {
3849 sdio_al_dev->sdioc_sw_header
3850 = kzalloc(sizeof(*sdio_al_dev->sdioc_sw_header),
3851 GFP_KERNEL);
3852 if (sdio_al_dev->sdioc_sw_header == NULL)
3853 return -ENOMEM;
3854 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003855
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003856 if (!sdio_al_dev->rx_flush_buf) {
3857 sdio_al_dev->rx_flush_buf = kzalloc(RX_FLUSH_BUFFER_SIZE,
3858 GFP_KERNEL);
3859 if (sdio_al_dev->rx_flush_buf == NULL) {
3860 sdio_al_loge(&sdio_al->gen_log,
3861 MODULE_NAME ":Fail to allocate "
3862 "rx_flush_buf for card %d\n",
3863 card->host->index);
3864 return -ENOMEM;
3865 }
Maya Erez5795e0d2011-09-12 20:20:06 +03003866 }
3867
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003868 sdio_al_dev->timer.data = (unsigned long)sdio_al_dev;
3869
3870 wake_lock_init(&sdio_al_dev->wake_lock, WAKE_LOCK_SUSPEND, MODULE_NAME);
3871 /* Don't allow sleep until all required clients register */
3872 sdio_al_vote_for_sleep(sdio_al_dev, 0);
3873
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003874 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
3875 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003876
3877 /* Init Func#1 */
Yaniv Gardi9a952d92011-09-06 13:46:30 +03003878 ret = sdio_al_enable_func_retry(card->sdio_func[0], "Init Func#1");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003879 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003880 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
3881 "enable Func#%d\n", card->sdio_func[0]->num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003882 goto exit;
3883 }
3884
3885 /* Patch Func CIS tuple issue */
3886 ret = sdio_set_block_size(card->sdio_func[0], SDIO_AL_BLOCK_SIZE);
3887 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003888 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to set "
3889 "block size, Func#%d\n", card->sdio_func[0]->num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003890 goto exit;
3891 }
3892 sdio_al_dev->card->sdio_func[0]->max_blksize = SDIO_AL_BLOCK_SIZE;
3893
3894 sdio_al_dev->workqueue = create_singlethread_workqueue("sdio_al_wq");
3895 sdio_al_dev->sdio_al_work.sdio_al_dev = sdio_al_dev;
3896 init_waitqueue_head(&sdio_al_dev->wait_mbox);
3897
3898 ret = sdio_al_client_setup(sdio_al_dev);
3899
3900exit:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003901 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003902 return ret;
3903}
3904
3905static void sdio_al_sdio_remove(struct sdio_func *func)
3906{
3907 struct sdio_al_device *sdio_al_dev = NULL;
3908 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003909 struct mmc_card *card = NULL;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003910 struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003911
3912 if (!func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003913 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
3914 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003915 return;
3916 }
3917 card = func->card;
3918
3919 if (!card) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003920 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
3921 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003922 return;
3923 }
3924
3925 /* Find the sdio_al_device of this card */
3926 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
3927 if (sdio_al->devices[i] == NULL)
3928 continue;
3929 if (sdio_al->devices[i]->card == card) {
3930 sdio_al_dev = sdio_al->devices[i];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003931 break;
3932 }
3933 }
3934 if (sdio_al_dev == NULL) {
3935 pr_debug(MODULE_NAME ":%s :NULL sdio_al_dev for card %d\n",
3936 __func__, card->host->index);
3937 return;
3938 }
3939
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003940 if (sdio_al_claim_mutex(sdio_al_dev, __func__))
3941 return;
3942
3943 if (sdio_al_dev->state == CARD_REMOVED) {
3944 sdio_al_release_mutex(sdio_al_dev, __func__);
3945 return;
3946 }
3947
3948 if (!card->sdio_func[0]) {
3949 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
3950 "func1\n", __func__);
3951 sdio_al_release_mutex(sdio_al_dev, __func__);
3952 return;
3953 }
3954
Krishna Kondaa7af6062011-09-01 18:34:38 -07003955 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s for card %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003956 __func__, card->host->index);
3957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003958 sdio_al_dev->state = CARD_REMOVED;
3959
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003960 memset(pdev_arr, 0, sizeof(pdev_arr));
3961 sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003962
Krishna Kondaa7af6062011-09-01 18:34:38 -07003963 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: ask_reading_mailbox "
3964 "for card %d\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003965 sdio_al_dev->is_ready = false; /* Flag worker to exit */
3966 sdio_al_dev->ask_mbox = false;
3967 ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
3968
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003969 stop_and_del_timer(sdio_al_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003970
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003971 sdio_al_release_mutex(sdio_al_dev, __func__);
3972
3973 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
3974 "clients for card %d",
3975 __func__, sdio_al_dev->host->index);
3976 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
3977 if (!pdev_arr[i])
3978 continue;
3979 platform_device_unregister(pdev_arr[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003980 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003981 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
3982 "SDIO clients for card %d",
3983 __func__, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984
Krishna Kondaa7af6062011-09-01 18:34:38 -07003985 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: vote for sleep for "
3986 "card %d\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003987 sdio_al_vote_for_sleep(sdio_al_dev, 1);
3988
Krishna Kondaa7af6062011-09-01 18:34:38 -07003989 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: flush_workqueue for "
3990 "card %d\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003991 flush_workqueue(sdio_al_dev->workqueue);
3992 destroy_workqueue(sdio_al_dev->workqueue);
3993 wake_lock_destroy(&sdio_al_dev->wake_lock);
3994
Krishna Kondaa7af6062011-09-01 18:34:38 -07003995 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: sdio card %d removed."
3996 "\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003997}
3998
3999static void sdio_print_mailbox(char *prefix_str, struct sdio_mailbox *mailbox)
4000{
4001 int k = 0;
4002 char buf[256];
4003 char buf1[10];
4004
4005 if (!mailbox) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004006 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": mailbox is "
4007 "NULL\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004008 return;
4009 }
4010
Krishna Kondaa7af6062011-09-01 18:34:38 -07004011 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: pipes 0_7: eot=0x%x,"
4012 " thresh=0x%x, overflow=0x%x, "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004013 "underflow=0x%x, mask_thresh=0x%x\n",
4014 prefix_str, mailbox->eot_pipe_0_7,
4015 mailbox->thresh_above_limit_pipe_0_7,
4016 mailbox->overflow_pipe_0_7,
4017 mailbox->underflow_pipe_0_7,
4018 mailbox->mask_thresh_above_limit_pipe_0_7);
4019
4020 memset(buf, 0, sizeof(buf));
4021 strncat(buf, ": bytes_avail:", sizeof(buf));
4022
4023 for (k = 0 ; k < SDIO_AL_ACTIVE_PIPES ; ++k) {
4024 snprintf(buf1, sizeof(buf1), "%d, ",
4025 mailbox->pipe_bytes_avail[k]);
4026 strncat(buf, buf1, sizeof(buf));
4027 }
4028
Krishna Kondaa7af6062011-09-01 18:34:38 -07004029 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME "%s", buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004030}
4031
4032static void sdio_al_print_info(void)
4033{
4034 int i = 0;
4035 int j = 0;
4036 int ret = 0;
4037 struct sdio_mailbox *mailbox = NULL;
4038 struct sdio_mailbox *hw_mailbox = NULL;
4039 struct peer_sdioc_channel_config *ch_config = NULL;
4040 struct sdio_func *func1 = NULL;
4041 struct sdio_func *lpm_func = NULL;
4042 int offset = 0;
4043 int is_ok_to_sleep = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004044 char buf[50];
4045
Maya Erezc7f63282011-10-11 12:15:23 +02004046 if (sdio_al->skip_print_info == 1)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004047 return;
4048
Maya Erezc7f63282011-10-11 12:15:23 +02004049 sdio_al->skip_print_info = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004050
Krishna Kondaa7af6062011-09-01 18:34:38 -07004051 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - SDIO DEBUG INFO\n",
4052 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004053
4054 if (!sdio_al) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004055 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - ERROR - "
4056 "sdio_al is NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057 return;
4058 }
4059
Krishna Kondaa7af6062011-09-01 18:34:38 -07004060 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": GPIO mdm2ap_status=%d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004061 sdio_al->pdata->get_mdm2ap_status());
4062
4063 for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
4064 struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
4065
4066 if (sdio_al_dev == NULL) {
4067 continue;
4068 }
4069
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004070 if (!sdio_al_dev->host) {
4071 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Host"
4072 " is NULL\n);");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004073 continue;
4074 }
4075
4076 snprintf(buf, sizeof(buf), "Card#%d: Shadow HW MB",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004077 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004078
4079 /* printing Shadowing HW Mailbox*/
4080 mailbox = sdio_al_dev->mailbox;
4081 sdio_print_mailbox(buf, mailbox);
4082
Krishna Kondaa7af6062011-09-01 18:34:38 -07004083 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084 "is_ok_to_sleep=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004085 sdio_al_dev->host->index,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004086 sdio_al_dev->is_ok_to_sleep);
4087
4088
Krishna Kondaa7af6062011-09-01 18:34:38 -07004089 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004090 "Shadow channels SW MB:",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004091 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004092
4093 /* printing Shadowing SW Mailbox per channel*/
4094 for (i = 0 ; i < SDIO_AL_MAX_CHANNELS ; ++i) {
4095 struct sdio_channel *ch = &sdio_al_dev->channel[i];
4096
4097 if (ch == NULL) {
4098 continue;
4099 }
4100
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03004101 if (ch->state == SDIO_CHANNEL_STATE_INVALID)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004102 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004103
4104 ch_config = &sdio_al_dev->channel[i].ch_config;
4105
Krishna Kondaa7af6062011-09-01 18:34:38 -07004106 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4107 ": Ch %s: max_rx_thres=0x%x, "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108 "max_tx_thres=0x%x, tx_buf=0x%x, "
4109 "is_packet_mode=%d, "
4110 "max_packet=0x%x, min_write=0x%x",
4111 ch->name, ch_config->max_rx_threshold,
4112 ch_config->max_tx_threshold,
4113 ch_config->tx_buf_size,
4114 ch_config->is_packet_mode,
4115 ch_config->max_packet_size,
4116 ch->min_write_avail);
4117
Krishna Kondaa7af6062011-09-01 18:34:38 -07004118 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4119 ": total_rx=0x%x, total_tx=0x%x, "
4120 "read_avail=0x%x, write_avail=0x%x, "
4121 "rx_pending=0x%x, num_reads=0x%x, "
4122 "num_notifs=0x%x", ch->total_rx_bytes,
4123 ch->total_tx_bytes, ch->read_avail,
4124 ch->write_avail, ch->rx_pending_bytes,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004125 ch->statistics.total_read_times,
4126 ch->statistics.total_notifs);
4127 } /* end loop over all channels */
4128
4129 } /* end loop over all devices */
4130
4131 /* reading from client and printing is_host_ok_to_sleep per device */
4132 for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
4133 struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
4134
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004135 if (sdio_al_verify_func1(sdio_al_dev, __func__))
4136 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004137
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004138 if (!sdio_al_dev->host) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004139 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4140 ": Host is NULL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141 continue;
4142 }
4143
4144 if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004145 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4146 ": %s - for Card#%d, is lpm_chan=="
4147 "INVALID_SDIO_CHAN. continuing...",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004148 __func__, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004149 continue;
4150 }
4151
4152 offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
4153 sizeof(struct peer_sdioc_channel_config) *
4154 sdio_al_dev->lpm_chan+
4155 offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
4156
4157 lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->
4158 lpm_chan+1];
4159 if (!lpm_func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004160 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4161 ": %s - lpm_func is NULL for card#%d"
4162 " continuing...\n", __func__,
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004163 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004164 continue;
4165 }
4166
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004167 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
4168 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004169 ret = sdio_memcpy_fromio(lpm_func,
4170 &is_ok_to_sleep,
4171 SDIOC_SW_MAILBOX_ADDR+offset,
4172 sizeof(int));
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004173 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004174
4175 if (ret)
Krishna Kondaa7af6062011-09-01 18:34:38 -07004176 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4177 ": %s - fail to read "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004178 "is_HOST_ok_to_sleep from mailbox for card %d",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004179 __func__, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004180 else
Krishna Kondaa7af6062011-09-01 18:34:38 -07004181 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4182 ": Card#%d: "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004183 "is_HOST_ok_to_sleep=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004184 sdio_al_dev->host->index,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004185 is_ok_to_sleep);
4186 }
4187
4188 for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
4189 struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
4190
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004191 if (!sdio_al_dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004192 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004193
4194 /* Reading HW Mailbox */
4195 hw_mailbox = sdio_al_dev->mailbox;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004196
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004197 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
4198 return;
4199
4200 if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
4201 sdio_al_release_mutex(sdio_al_dev, __func__);
4202 return;
4203 }
4204 func1 = sdio_al_dev->card->sdio_func[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004205 ret = sdio_memcpy_fromio(func1, hw_mailbox,
4206 HW_MAILBOX_ADDR, sizeof(*hw_mailbox));
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004207 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004208
4209 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004210 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4211 ": fail to read "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004212 "mailbox for card#%d. "
4213 "continuing...\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004214 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004215 continue;
4216 }
4217
4218 snprintf(buf, sizeof(buf), "Card#%d: Current HW MB",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004219 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004220
4221 /* Printing HW Mailbox */
4222 sdio_print_mailbox(buf, hw_mailbox);
4223 }
4224}
4225
4226static struct sdio_device_id sdio_al_sdioid[] = {
4227 {.class = 0, .vendor = 0x70, .device = 0x2460},
4228 {.class = 0, .vendor = 0x70, .device = 0x0460},
4229 {.class = 0, .vendor = 0x70, .device = 0x23F1},
4230 {.class = 0, .vendor = 0x70, .device = 0x23F0},
4231 {}
4232};
4233
4234static struct sdio_driver sdio_al_sdiofn_driver = {
4235 .name = "sdio_al_sdiofn",
4236 .id_table = sdio_al_sdioid,
4237 .probe = sdio_al_sdio_probe,
4238 .remove = sdio_al_sdio_remove,
4239};
4240
4241#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
4242/*
4243 * Callback for notifications from restart mudule.
4244 * This function handles only the BEFORE_RESTART notification.
4245 * Stop all the activity on the card and notify our clients.
4246 */
4247static int sdio_al_subsys_notifier_cb(struct notifier_block *this,
4248 unsigned long notif_type,
4249 void *data)
4250{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004251 if (notif_type != SUBSYS_BEFORE_SHUTDOWN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004252 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: got "
4253 "notification %ld", __func__, notif_type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004254 return NOTIFY_DONE;
4255 }
4256
Konstantin Dorfman52890522011-10-05 11:03:19 +02004257 sdio_al_reset();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004258 return NOTIFY_OK;
4259}
4260
4261static struct notifier_block sdio_al_nb = {
4262 .notifier_call = sdio_al_subsys_notifier_cb,
4263};
4264#endif
4265
4266/**
4267 * Module Init.
4268 *
4269 * @warn: allocate sdio_al context before registering driver.
4270 *
4271 */
4272static int __init sdio_al_init(void)
4273{
4274 int ret = 0;
4275 int i;
4276
4277 pr_debug(MODULE_NAME ":sdio_al_init\n");
4278
4279 pr_info(MODULE_NAME ":SDIO-AL SW version %s\n",
4280 DRV_VERSION);
4281
4282 sdio_al = kzalloc(sizeof(struct sdio_al), GFP_KERNEL);
4283 if (sdio_al == NULL)
4284 return -ENOMEM;
4285
4286 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
4287 sdio_al->devices[i] = NULL;
4288
4289 sdio_al->unittest_mode = false;
4290
4291 sdio_al->debug.debug_lpm_on = debug_lpm_on;
4292 sdio_al->debug.debug_data_on = debug_data_on;
Maya Erez7ad06d82011-10-02 15:47:57 +02004293 sdio_al->debug.debug_close_on = debug_close_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004294
4295#ifdef CONFIG_DEBUG_FS
4296 sdio_al_debugfs_init();
4297#endif
4298
4299
4300#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
4301 sdio_al->subsys_notif_handle = subsys_notif_register_notifier(
4302 "external_modem", &sdio_al_nb);
4303#endif
4304
4305 ret = platform_driver_register(&msm_sdio_al_driver);
4306 if (ret) {
4307 pr_err(MODULE_NAME ": platform_driver_register failed: %d\n",
4308 ret);
4309 goto exit;
4310 }
4311
4312 sdio_register_driver(&sdio_al_sdiofn_driver);
Krishna Kondaa7af6062011-09-01 18:34:38 -07004313
4314 spin_lock_init(&sdio_al->gen_log.log_lock);
4315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004316exit:
4317 if (ret)
4318 kfree(sdio_al);
4319 return ret;
4320}
4321
4322/**
4323 * Module Exit.
4324 *
4325 * Free allocated memory.
4326 * Disable SDIO-Card.
4327 * Unregister driver.
4328 *
4329 */
4330static void __exit sdio_al_exit(void)
4331{
4332 if (sdio_al == NULL)
4333 return;
4334
4335 pr_debug(MODULE_NAME ":sdio_al_exit\n");
4336
4337#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
4338 subsys_notif_unregister_notifier(
4339 sdio_al->subsys_notif_handle, &sdio_al_nb);
4340#endif
4341
4342 sdio_al_tear_down();
4343
4344 sdio_unregister_driver(&sdio_al_sdiofn_driver);
4345
4346 kfree(sdio_al);
4347
4348#ifdef CONFIG_DEBUG_FS
4349 sdio_al_debugfs_cleanup();
4350#endif
4351
4352 platform_driver_unregister(&msm_sdio_al_driver);
4353
4354 pr_debug(MODULE_NAME ":sdio_al_exit complete\n");
4355}
4356
4357module_init(sdio_al_init);
4358module_exit(sdio_al_exit);
4359
4360MODULE_LICENSE("GPL v2");
4361MODULE_DESCRIPTION("SDIO Abstraction Layer");
4362MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
4363MODULE_VERSION(DRV_VERSION);
4364