blob: 8267fad2b480081eb682bc82fb3fdaa7cc101090 [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 */
18#include <sdio_al_private.h>
19
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)
111
Maya Erez8ed0a9a2011-07-19 14:46:53 +0300112/* Extra bytes to ensure getting the rx threshold interrupt on stream channels
113 when restoring the threshold after sleep */
114#define THRESHOLD_CHANGE_EXTRA_BYTES (100)
115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116/** SW threshold to trigger reading the mailbox. */
117#define DEFAULT_MIN_WRITE_THRESHOLD (1024)
118#define DEFAULT_MIN_WRITE_THRESHOLD_STREAMING (1600)
119
120#define THRESHOLD_DISABLE_VAL (0xFFFFFFFF)
121
122
123/** 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{
881 struct sdio_func *lpm_func =
882 sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1];
883 int offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
884 sizeof(struct peer_sdioc_channel_config) *
885 sdio_al_dev->lpm_chan+
886 offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
887 int ret;
888
889 if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700890 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
891 "lpm_chan for card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200892 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700893 return -EINVAL;
894 }
895
896 pr_debug(MODULE_NAME ":write_lpm_info is_ok_to_sleep=%d, device %d\n",
897 sdio_al_dev->is_ok_to_sleep,
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200898 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899
900 ret = sdio_memcpy_toio(lpm_func, SDIOC_SW_MAILBOX_ADDR+offset,
901 &sdio_al_dev->is_ok_to_sleep, sizeof(u32));
902 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700903 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
904 "write lpm info for card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200905 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906 return ret;
907 }
908
909 return 0;
910}
911
912/* Set inactivity counter to intial value to allow clients come up */
913static inline void start_inactive_time(struct sdio_al_device *sdio_al_dev)
914{
915 sdio_al_dev->inactivity_time = jiffies +
916 msecs_to_jiffies(INITIAL_INACTIVITY_TIME_MSEC);
917}
918
919static inline void restart_inactive_time(struct sdio_al_device *sdio_al_dev)
920{
921 sdio_al_dev->inactivity_time = jiffies +
922 msecs_to_jiffies(INACTIVITY_TIME_MSEC);
923}
924
925static inline int is_inactive_time_expired(struct sdio_al_device *sdio_al_dev)
926{
927 return time_after(jiffies, sdio_al_dev->inactivity_time);
928}
929
930
931static int is_user_irq_enabled(struct sdio_al_device *sdio_al_dev,
932 int func_num)
933{
934 int ret = 0;
935 struct sdio_func *func1;
936 u32 user_irq = 0;
937 u32 addr = 0;
938 u32 offset = 0;
939 u32 masked_user_irq = 0;
940
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200941 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942 return 0;
943 func1 = sdio_al_dev->card->sdio_func[0];
944
945 if (func_num < 4) {
946 addr = FUNC_1_4_USER_IRQ_ADDR;
947 offset = func_num * 8;
948 } else {
949 addr = FUNC_5_7_USER_IRQ_ADDR;
950 offset = (func_num - 4) * 8;
951 }
952
953 user_irq = sdio_readl(func1, addr, &ret);
954 if (ret) {
955 pr_debug(MODULE_NAME ":read_user_irq fail\n");
956 return 0;
957 }
958
959 masked_user_irq = (user_irq >> offset) && 0xFF;
960 if (masked_user_irq == 0x1) {
Krishna Kondaa7af6062011-09-01 18:34:38 -0700961 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":user_irq "
962 "enabled\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963 return 1;
964 }
965
966 return 0;
967}
968
969static void sdio_al_sleep(struct sdio_al_device *sdio_al_dev,
970 struct mmc_host *host)
971{
972 int i;
973
974 /* Go to sleep */
Maya Erez7b1ebd22011-08-20 20:53:24 +0300975 pr_debug(MODULE_NAME ":Inactivity timer expired."
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700976 " Going to sleep\n");
977 /* Stop mailbox timer */
Maya Erez0fdb5ad2011-10-09 19:16:27 +0200978 stop_and_del_timer(sdio_al_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979 /* Make sure we get interrupt for non-packet-mode right away */
980 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
981 struct sdio_channel *ch = &sdio_al_dev->channel[i];
Maya Erez5795e0d2011-09-12 20:20:06 +0300982 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
983 (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +0300984 pr_debug(MODULE_NAME ":continue for channel %s in"
985 " state %d\n", ch->name, ch->state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 continue;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +0300987 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 if (ch->is_packet_mode == false) {
989 ch->read_threshold = 1;
990 set_pipe_threshold(sdio_al_dev,
991 ch->rx_pipe_index,
992 ch->read_threshold);
993 }
994 }
Maya Erezfd915312011-07-14 13:45:34 +0300995 /* Prevent modem to go to sleep until we get the PROG_DONE on
996 the dummy CMD52 */
Maya Erez86cebda2011-10-11 11:13:40 +0200997 msmsdcc_set_pwrsave(sdio_al_dev->host, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998 /* Mark HOST_OK_TOSLEEP */
999 sdio_al_dev->is_ok_to_sleep = 1;
1000 write_lpm_info(sdio_al_dev);
1001
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001002 msmsdcc_lpm_enable(host);
Krishna Kondaa7af6062011-09-01 18:34:38 -07001003 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Finished sleep sequence"
1004 " for card %d. Sleep now.\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001005 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006 /* Release wakelock */
1007 sdio_al_vote_for_sleep(sdio_al_dev, 1);
1008}
1009
1010
1011/**
1012 * Read SDIO-Client Mailbox from Function#1.thresh_pipe
1013 *
1014 * The mailbox contain the bytes available per pipe,
1015 * and the End-Of-Transfer indication per pipe (if available).
1016 *
1017 * WARNING: Each time the Mailbox is read from the client, the
1018 * read_bytes_avail is incremented with another pending
1019 * transfer. Therefore, a pending rx-packet should be added to a
1020 * list before the next read of the mailbox.
1021 *
1022 * This function should run from a workqueue context since it
1023 * notifies the clients.
1024 *
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001025 * This function assumes that sdio_al_claim_mutex was called before
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 * calling it.
1027 *
1028 */
1029static int read_mailbox(struct sdio_al_device *sdio_al_dev, int from_isr)
1030{
1031 int ret;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001032 struct sdio_func *func1 = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 struct sdio_mailbox *mailbox = sdio_al_dev->mailbox;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001034 struct mmc_host *host = sdio_al_dev->host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035 u32 new_write_avail = 0;
1036 u32 old_write_avail = 0;
1037 u32 any_read_avail = 0;
1038 u32 any_write_pending = 0;
1039 int i;
1040 u32 rx_notify_bitmask = 0;
1041 u32 tx_notify_bitmask = 0;
1042 u32 eot_pipe = 0;
1043 u32 thresh_pipe = 0;
1044 u32 overflow_pipe = 0;
1045 u32 underflow_pipe = 0;
1046 u32 thresh_intr_mask = 0;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001047 int is_closing = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048
1049 if (sdio_al_dev->is_err) {
1050 SDIO_AL_ERR(__func__);
1051 return 0;
1052 }
1053
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001054 if (sdio_al_verify_func1(sdio_al_dev, __func__))
1055 return -ENODEV;
1056 func1 = sdio_al_dev->card->sdio_func[0];
1057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001058 pr_debug(MODULE_NAME ":start %s from_isr = %d for card %d.\n"
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001059 , __func__, from_isr, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060
1061 pr_debug(MODULE_NAME ":before sdio_memcpy_fromio.\n");
Maya Erez320a7ca2011-08-03 09:41:27 +03001062 memset(mailbox, 0, sizeof(struct sdio_mailbox));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063 ret = sdio_memcpy_fromio(func1, mailbox,
1064 HW_MAILBOX_ADDR, sizeof(*mailbox));
1065 pr_debug(MODULE_NAME ":after sdio_memcpy_fromio.\n");
Maya Erez320a7ca2011-08-03 09:41:27 +03001066 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001067 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to read "
1068 "Mailbox for card %d, goto error state\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001069 sdio_al_dev->host->index);
Maya Erez320a7ca2011-08-03 09:41:27 +03001070 sdio_al_get_into_err_state(sdio_al_dev);
Maya Erez320a7ca2011-08-03 09:41:27 +03001071 goto exit_err;
1072 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073
1074 eot_pipe = (mailbox->eot_pipe_0_7) |
1075 (mailbox->eot_pipe_8_15<<8);
1076 thresh_pipe = (mailbox->thresh_above_limit_pipe_0_7) |
1077 (mailbox->thresh_above_limit_pipe_8_15<<8);
1078
1079 overflow_pipe = (mailbox->overflow_pipe_0_7) |
1080 (mailbox->overflow_pipe_8_15<<8);
1081 underflow_pipe = mailbox->underflow_pipe_0_7 |
1082 (mailbox->underflow_pipe_8_15<<8);
1083 thresh_intr_mask =
1084 (mailbox->mask_thresh_above_limit_pipe_0_7) |
1085 (mailbox->mask_thresh_above_limit_pipe_8_15<<8);
1086
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001087 if (overflow_pipe || underflow_pipe)
Krishna Kondaa7af6062011-09-01 18:34:38 -07001088 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Mailbox ERROR "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089 "overflow=0x%x, underflow=0x%x\n",
1090 overflow_pipe, underflow_pipe);
1091
1092 /* In case of modem reset we would like to read the daya from the modem
1093 to clear the interrupts but do not process it */
1094 if (sdio_al_dev->state != CARD_INSERTED) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001095 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_device"
1096 " (card %d) is in invalid state %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001097 sdio_al_dev->host->index,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 sdio_al_dev->state);
1099 return -ENODEV;
1100 }
1101
1102 pr_debug(MODULE_NAME ":card %d: eot=0x%x, thresh=0x%x\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001103 sdio_al_dev->host->index,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104 eot_pipe, thresh_pipe);
1105
1106 /* Scan for Rx Packets available and update read available bytes */
1107 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
1108 struct sdio_channel *ch = &sdio_al_dev->channel[i];
1109 u32 old_read_avail;
1110 u32 read_avail;
1111 u32 new_packet_size = 0;
1112
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001113 if (ch->state == SDIO_CHANNEL_STATE_CLOSING)
1114 is_closing = true; /* used to prevent sleep */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115
1116 old_read_avail = ch->read_avail;
1117 read_avail = mailbox->pipe_bytes_avail[ch->rx_pipe_index];
1118
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001119 if ((ch->state == SDIO_CHANNEL_STATE_CLOSED) &&
1120 (read_avail > 0)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001121 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1122 ":%s: Invalid read_avail 0x%x, for CLOSED ch %s\n",
Maya Erez5795e0d2011-09-12 20:20:06 +03001123 __func__, read_avail, ch->name);
1124 sdio_read_from_closed_ch(ch, read_avail);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001125 }
1126 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
1127 (ch->state != SDIO_CHANNEL_STATE_CLOSING))
1128 continue;
1129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130 if (read_avail > INVALID_DATA_AVAILABLE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001131 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 ":Invalid read_avail 0x%x for pipe %d\n",
1133 read_avail, ch->rx_pipe_index);
1134 continue;
1135 }
1136 any_read_avail |= read_avail | old_read_avail;
1137 ch->statistics.last_any_read_avail = any_read_avail;
1138 ch->statistics.last_read_avail = read_avail;
1139 ch->statistics.last_old_read_avail = old_read_avail;
1140
Maya Erez8ed0a9a2011-07-19 14:46:53 +03001141 if (ch->is_packet_mode) {
Maya Erez7b1ebd22011-08-20 20:53:24 +03001142 if ((eot_pipe & (1<<ch->rx_pipe_index)) &&
1143 sdio_al_dev->print_after_interrupt) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001144 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
1145 ":Interrupt on ch %s, "
1146 "card %d", ch->name,
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001147 sdio_al_dev->host->index);
Maya Erez7b1ebd22011-08-20 20:53:24 +03001148 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001149 new_packet_size = check_pending_rx_packet(ch, eot_pipe);
Maya Erez8ed0a9a2011-07-19 14:46:53 +03001150 } else {
Maya Erez7b1ebd22011-08-20 20:53:24 +03001151 if ((thresh_pipe & (1<<ch->rx_pipe_index)) &&
1152 sdio_al_dev->print_after_interrupt) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001153 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
1154 ":Interrupt on ch %s, "
1155 "card %d", ch->name,
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001156 sdio_al_dev->host->index);
Maya Erez7b1ebd22011-08-20 20:53:24 +03001157 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158 ch->read_avail = read_avail;
Maya Erez8ed0a9a2011-07-19 14:46:53 +03001159 /* Restore default thresh for non packet channels */
1160 if ((ch->read_threshold != ch->def_read_threshold) &&
1161 (read_avail >= ch->threshold_change_cnt)) {
1162 ch->read_threshold = ch->def_read_threshold;
1163 set_pipe_threshold(sdio_al_dev,
1164 ch->rx_pipe_index,
1165 ch->read_threshold);
1166 }
1167 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168
1169 if ((ch->is_packet_mode) && (new_packet_size > 0)) {
1170 rx_notify_bitmask |= (1<<ch->num);
1171 ch->statistics.total_notifs++;
1172 }
1173
1174 if ((!ch->is_packet_mode) && (ch->read_avail > 0) &&
1175 (old_read_avail == 0)) {
1176 rx_notify_bitmask |= (1<<ch->num);
1177 ch->statistics.total_notifs++;
1178 }
1179 }
Maya Erez7b1ebd22011-08-20 20:53:24 +03001180 sdio_al_dev->print_after_interrupt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181
1182 /* Update Write available */
1183 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
1184 struct sdio_channel *ch = &sdio_al_dev->channel[i];
1185
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001186 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
1187 (ch->state != SDIO_CHANNEL_STATE_CLOSING))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 continue;
1189
1190 new_write_avail = mailbox->pipe_bytes_avail[ch->tx_pipe_index];
1191
1192 if (new_write_avail > INVALID_DATA_AVAILABLE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001193 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194 ":Invalid write_avail 0x%x for pipe %d\n",
1195 new_write_avail, ch->tx_pipe_index);
1196 continue;
1197 }
1198
1199 old_write_avail = ch->write_avail;
1200 ch->write_avail = new_write_avail;
1201
1202 if ((old_write_avail <= ch->min_write_avail) &&
1203 (new_write_avail >= ch->min_write_avail))
1204 tx_notify_bitmask |= (1<<ch->num);
1205
1206 /* There is not enough write avail for this channel.
1207 We need to keep reading mailbox to wait for the appropriate
1208 write avail and cannot sleep. Ignore SMEM channel that has
1209 only one direction. */
1210 if (strcmp(ch->name, "SDIO_SMEM"))
1211 any_write_pending |=
1212 (new_write_avail < ch->ch_config.max_tx_threshold);
1213 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001214 /* notify clients */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
1216 struct sdio_channel *ch = &sdio_al_dev->channel[i];
1217
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001218 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) ||
1219 (ch->notify == NULL))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 continue;
1221
1222 if (rx_notify_bitmask & (1<<ch->num))
1223 ch->notify(ch->priv,
1224 SDIO_EVENT_DATA_READ_AVAIL);
1225
1226 if (tx_notify_bitmask & (1<<ch->num))
1227 ch->notify(ch->priv,
1228 SDIO_EVENT_DATA_WRITE_AVAIL);
1229 }
1230
1231
1232 if ((rx_notify_bitmask == 0) && (tx_notify_bitmask == 0) &&
1233 !any_read_avail && !any_write_pending) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001234 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Nothing to "
1235 "Notify for card %d, is_closing=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001236 sdio_al_dev->host->index, is_closing);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001237 if (is_closing)
1238 restart_inactive_time(sdio_al_dev);
1239 else if (is_inactive_time_expired(sdio_al_dev))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240 sdio_al_sleep(sdio_al_dev, host);
1241 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001242 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Notify bitmask"
1243 " for card %d rx=0x%x, tx=0x%x.\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001244 sdio_al_dev->host->index,
Krishna Kondaa7af6062011-09-01 18:34:38 -07001245 rx_notify_bitmask, tx_notify_bitmask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246 /* Restart inactivity timer if any activity on the channel */
1247 restart_inactive_time(sdio_al_dev);
1248 }
1249
1250 pr_debug(MODULE_NAME ":end %s.\n", __func__);
1251
1252exit_err:
1253 return ret;
1254}
1255
1256/**
1257 * Check pending rx packet when reading the mailbox.
1258 */
1259static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot)
1260{
1261 u32 rx_pending;
1262 u32 rx_avail;
1263 u32 new_packet_size = 0;
1264 struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
1265
1266
1267 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001268 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
1269 " for channel %s\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 return -EINVAL;
1271 }
1272
1273 mutex_lock(&ch->ch_lock);
1274
1275 rx_pending = ch->rx_pending_bytes;
1276 rx_avail = sdio_al_dev->mailbox->pipe_bytes_avail[ch->rx_pipe_index];
1277
1278 pr_debug(MODULE_NAME ":pipe %d of card %d rx_avail=0x%x, "
1279 "rx_pending=0x%x\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001280 ch->rx_pipe_index, sdio_al_dev->host->index, rx_avail,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 rx_pending);
1282
1283
1284 /* new packet detected */
1285 if (eot & (1<<ch->rx_pipe_index)) {
1286 struct rx_packet_size *p = NULL;
1287 new_packet_size = rx_avail - rx_pending;
1288
1289 if ((rx_avail <= rx_pending)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001290 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1291 ": Invalid new packet size."
1292 " rx_avail=%d.\n", rx_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293 new_packet_size = 0;
1294 goto exit_err;
1295 }
1296
1297 p = kzalloc(sizeof(*p), GFP_KERNEL);
Maya Erezd9cc2292011-08-04 09:20:31 +03001298 if (p == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001299 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1300 ": failed to allocate item for "
1301 "rx_pending list. rx_avail=%d, "
1302 "rx_pending=%d.\n",
1303 rx_avail, rx_pending);
Maya Erezd9cc2292011-08-04 09:20:31 +03001304 new_packet_size = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 goto exit_err;
Maya Erezd9cc2292011-08-04 09:20:31 +03001306 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 p->size = new_packet_size;
1308 /* Add new packet as last */
1309 list_add_tail(&p->list, &ch->rx_size_list_head);
1310 ch->rx_pending_bytes += new_packet_size;
1311
1312 if (ch->read_avail == 0)
1313 ch->read_avail = new_packet_size;
1314 }
1315
1316exit_err:
1317 mutex_unlock(&ch->ch_lock);
1318
1319 return new_packet_size;
1320}
1321
1322
1323
1324/**
1325 * Remove first pending packet from the list.
1326 */
1327static u32 remove_handled_rx_packet(struct sdio_channel *ch)
1328{
1329 struct rx_packet_size *p = NULL;
1330
1331 mutex_lock(&ch->ch_lock);
1332
1333 ch->rx_pending_bytes -= ch->read_avail;
1334
1335 if (!list_empty(&ch->rx_size_list_head)) {
1336 p = list_first_entry(&ch->rx_size_list_head,
1337 struct rx_packet_size, list);
1338 list_del(&p->list);
1339 kfree(p);
Maya Erezd9cc2292011-08-04 09:20:31 +03001340 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001341 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: ch "
1342 "%s: unexpected empty list!!\n",
1343 __func__, ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001344 }
1345
1346 if (list_empty(&ch->rx_size_list_head)) {
1347 ch->read_avail = 0;
1348 } else {
1349 p = list_first_entry(&ch->rx_size_list_head,
1350 struct rx_packet_size, list);
1351 ch->read_avail = p->size;
1352 }
1353
1354 mutex_unlock(&ch->ch_lock);
1355
1356 return ch->read_avail;
1357}
1358
1359
1360/**
1361 * Bootloader worker function.
1362 *
1363 * @note: clear the bootloader_done flag only after reading the
1364 * mailbox, to ignore more requests while reading the mailbox.
1365 */
1366static void boot_worker(struct work_struct *work)
1367{
1368 int ret = 0;
1369 int func_num = 0;
1370 int i;
1371 struct sdio_al_device *sdio_al_dev = NULL;
1372 struct sdio_al_work *sdio_al_work = container_of(work,
1373 struct sdio_al_work,
1374 work);
1375
1376 if (sdio_al_work == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001377 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
1378 "sdio_al_work\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001379 return;
1380 }
1381
1382 sdio_al_dev = sdio_al_work->sdio_al_dev;
1383 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001384 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
1385 "sdio_al_dev\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001386 return;
1387 }
Krishna Kondaa7af6062011-09-01 18:34:38 -07001388 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Bootloader Worker Started"
1389 ", wait for bootloader_done event..\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 wait_event(sdio_al_dev->wait_mbox,
1391 sdio_al_dev->bootloader_done);
Krishna Kondaa7af6062011-09-01 18:34:38 -07001392 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Got bootloader_done "
1393 "event..\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394 /* Do polling until MDM is up */
1395 for (i = 0; i < 5000; ++i) {
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001396 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001397 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398 if (is_user_irq_enabled(sdio_al_dev, func_num)) {
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001399 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 sdio_al_dev->bootloader_done = 0;
1401 ret = sdio_al_client_setup(sdio_al_dev);
1402 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001403 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1404 ": sdio_al_client_setup failed, "
1405 "for card %d ret=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001406 sdio_al_dev->host->index, ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001407 sdio_al_get_into_err_state(sdio_al_dev);
1408 }
1409 goto done;
1410 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001411 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412 msleep(100);
1413 }
Krishna Kondaa7af6062011-09-01 18:34:38 -07001414 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Timeout waiting for "
1415 "user_irq for card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001416 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001417 sdio_al_get_into_err_state(sdio_al_dev);
1418
1419done:
1420 pr_debug(MODULE_NAME ":Boot Worker for card %d Exit!\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001421 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001422}
1423
1424/**
1425 * Worker function.
1426 *
1427 * @note: clear the ask_mbox flag only after
1428 * reading the mailbox, to ignore more requests while
1429 * reading the mailbox.
1430 */
1431static void worker(struct work_struct *work)
1432{
1433 int ret = 0;
1434 struct sdio_al_device *sdio_al_dev = NULL;
1435 struct sdio_al_work *sdio_al_work = container_of(work,
1436 struct sdio_al_work,
1437 work);
1438 if (sdio_al_work == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001439 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
1440 "sdio_al_work\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441 return;
1442 }
1443
1444 sdio_al_dev = sdio_al_work->sdio_al_dev;
1445 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001446 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
1447 "sdio_al_dev\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 return;
1449 }
1450 pr_debug(MODULE_NAME ":Worker Started..\n");
1451 while ((sdio_al_dev->is_ready) && (ret == 0)) {
1452 pr_debug(MODULE_NAME ":Wait for read mailbox request..\n");
1453 wait_event(sdio_al_dev->wait_mbox, sdio_al_dev->ask_mbox);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 if (!sdio_al_dev->is_ready)
1455 break;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001456 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
1457 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 if (sdio_al_dev->is_ok_to_sleep) {
Maya Erez7b1ebd22011-08-20 20:53:24 +03001459 ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 if (ret) {
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001461 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 return;
1463 }
1464 }
1465 ret = read_mailbox(sdio_al_dev, false);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001466 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 sdio_al_dev->ask_mbox = false;
1468 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001469
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470 pr_debug(MODULE_NAME ":Worker Exit!\n");
1471}
1472
1473/**
1474 * Write command using CMD54 rather than CMD53.
1475 * Writing with CMD54 generate EOT interrupt at the
1476 * SDIO-Client.
1477 * Based on mmc_io_rw_extended()
1478 */
1479static int sdio_write_cmd54(struct mmc_card *card, unsigned fn,
1480 unsigned addr, const u8 *buf,
1481 unsigned blocks, unsigned blksz)
1482{
1483 struct mmc_request mrq;
1484 struct mmc_command cmd;
1485 struct mmc_data data;
1486 struct scatterlist sg;
1487 int incr_addr = 1; /* MUST */
1488 int write = 1;
1489
1490 BUG_ON(!card);
1491 BUG_ON(fn > 7);
1492 BUG_ON(blocks == 1 && blksz > 512);
1493 WARN_ON(blocks == 0);
1494 WARN_ON(blksz == 0);
1495
1496 write = true;
1497 pr_debug(MODULE_NAME ":sdio_write_cmd54()"
1498 "fn=%d,buf=0x%x,blocks=%d,blksz=%d\n",
1499 fn, (u32) buf, blocks, blksz);
1500
1501 memset(&mrq, 0, sizeof(struct mmc_request));
1502 memset(&cmd, 0, sizeof(struct mmc_command));
1503 memset(&data, 0, sizeof(struct mmc_data));
1504
1505 mrq.cmd = &cmd;
1506 mrq.data = &data;
1507
1508 cmd.opcode = SD_IO_RW_EXTENDED_QCOM;
1509
1510 cmd.arg = write ? 0x80000000 : 0x00000000;
1511 cmd.arg |= fn << 28;
1512 cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
1513 cmd.arg |= addr << 9;
1514 if (blocks == 1 && blksz <= 512)
1515 cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
1516 else
1517 cmd.arg |= 0x08000000 | blocks; /* block mode */
1518 cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
1519
1520 data.blksz = blksz;
1521 data.blocks = blocks;
1522 data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
1523 data.sg = &sg;
1524 data.sg_len = 1;
1525
1526 sg_init_one(&sg, buf, blksz * blocks);
1527
1528 mmc_set_data_timeout(&data, card);
1529
1530 mmc_wait_for_req(card->host, &mrq);
1531
1532 if (cmd.error)
1533 return cmd.error;
1534 if (data.error)
1535 return data.error;
1536
1537 if (mmc_host_is_spi(card->host)) {
1538 /* host driver already reported errors */
1539 } else {
1540 if (cmd.resp[0] & R5_ERROR) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001541 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
1542 ":%s: R5_ERROR for card %d",
1543 __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 return -EIO;
1545 }
1546 if (cmd.resp[0] & R5_FUNCTION_NUMBER) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001547 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
1548 ":%s: R5_FUNCTION_NUMBER for card %d",
1549 __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 return -EINVAL;
1551 }
1552 if (cmd.resp[0] & R5_OUT_OF_RANGE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001553 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
1554 ":%s: R5_OUT_OF_RANGE for card %d",
1555 __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 return -ERANGE;
1557 }
1558 }
1559
1560 return 0;
1561}
1562
1563
1564/**
1565 * Write data to channel.
1566 * Handle different data size types.
1567 *
1568 */
1569static int sdio_ch_write(struct sdio_channel *ch, const u8 *buf, u32 len)
1570{
1571 int ret = 0;
1572 unsigned blksz = ch->func->cur_blksize;
1573 int blocks = len / blksz;
1574 int remain_bytes = len % blksz;
1575 struct mmc_card *card = NULL;
1576 u32 fn = ch->func->num;
1577
Krishna Kondaa7af6062011-09-01 18:34:38 -07001578 if (!ch) {
1579 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
1580 "channel\n", __func__);
1581 return -ENODEV;
1582 }
1583
1584 if (!ch->sdio_al_dev) {
1585 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
1586 "sdio_al_dev\n", __func__);
1587 return -ENODEV;
1588 }
1589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590 if (len == 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001591 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":channel "
1592 "%s trying to write 0 bytes\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001593 return -EINVAL;
1594 }
1595
1596 card = ch->func->card;
1597
1598 if (remain_bytes) {
1599 /* CMD53 */
1600 if (blocks) {
1601 ret = sdio_memcpy_toio(ch->func, PIPE_TX_FIFO_ADDR,
1602 (void *) buf, blocks*blksz);
1603 if (ret != 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001604 sdio_al_loge(ch->sdio_al_dev->dev_log,
1605 MODULE_NAME ":%s: sdio_memcpy_toio "
1606 "failed for channel %s\n",
1607 __func__, ch->name);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001608 sdio_al_get_into_err_state(ch->sdio_al_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609 return ret;
1610 }
1611 }
1612
1613 buf += (blocks*blksz);
1614
1615 ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
1616 buf, 1, remain_bytes);
1617 } else {
1618 ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
1619 buf, blocks, blksz);
1620 }
1621
1622 if (ret != 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001623 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
1624 "sdio_write_cmd54 failed for channel %s\n",
1625 __func__, ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001626 ch->sdio_al_dev->is_err = true;
1627 return ret;
1628 }
1629
1630 return ret;
1631}
1632
1633static int sdio_al_bootloader_completed(void)
1634{
1635 int i;
1636
1637 pr_debug(MODULE_NAME ":sdio_al_bootloader_completed was called\n");
1638
1639 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
1640 struct sdio_al_device *dev = NULL;
1641 if (sdio_al->devices[i] == NULL)
1642 continue;
1643 dev = sdio_al->devices[i];
1644 dev->bootloader_done = 1;
1645 wake_up(&dev->wait_mbox);
1646 }
1647
1648 return 0;
1649}
1650
1651static int sdio_al_wait_for_bootloader_comp(struct sdio_al_device *sdio_al_dev)
1652{
1653 int ret = 0;
1654
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001655 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001656 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001658 /*
1659 * Enable function 0 interrupt mask to allow 9k to raise this interrupt
1660 * in power-up. When sdio_downloader will notify its completion
1661 * we will poll on this interrupt to wait for 9k power-up
1662 */
1663 ret = enable_mask_irq(sdio_al_dev, 0, 1, 0);
1664 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001665 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1666 ": Enable_mask_irq for card %d failed, "
1667 "ret=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001668 sdio_al_dev->host->index, ret);
1669 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 return ret;
1671 }
1672
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001673 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674
1675 /*
1676 * Start bootloader worker that will wait for the bootloader
1677 * completion
1678 */
1679 sdio_al_dev->boot_work.sdio_al_dev = sdio_al_dev;
1680 INIT_WORK(&sdio_al_dev->boot_work.work, boot_worker);
1681 sdio_al_dev->bootloader_done = 0;
1682 queue_work(sdio_al_dev->workqueue, &sdio_al_dev->boot_work.work);
1683
1684 return 0;
1685}
1686
1687static int sdio_al_bootloader_setup(void)
1688{
1689 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001690 struct sdio_al_device *bootloader_dev = sdio_al->bootloader_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001691 struct sdio_func *func1 = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001693 if (sdio_al_claim_mutex_and_verify_dev(bootloader_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001694 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001696 if (bootloader_dev->flashless_boot_on) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001697 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":Already "
1698 "in boot process.\n");
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001699 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700 return 0;
1701 }
1702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703 bootloader_dev->sdioc_boot_sw_header
1704 = kzalloc(sizeof(*bootloader_dev->sdioc_boot_sw_header),
1705 GFP_KERNEL);
1706 if (bootloader_dev->sdioc_boot_sw_header == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001707 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
1708 "allocate sdioc boot sw header.\n");
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001709 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001710 return -ENOMEM;
1711 }
1712
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001713 if (sdio_al_verify_func1(bootloader_dev, __func__)) {
1714 sdio_al_release_mutex(bootloader_dev, __func__);
1715 goto exit_err;
1716 }
1717 func1 = bootloader_dev->card->sdio_func[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718
1719 ret = sdio_memcpy_fromio(func1,
1720 bootloader_dev->sdioc_boot_sw_header,
1721 SDIOC_SW_HEADER_ADDR,
1722 sizeof(struct peer_sdioc_boot_sw_header));
1723 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001724 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
1725 "read sdioc boot sw header.\n");
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001726 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001727 goto exit_err;
1728 }
1729
1730 if (bootloader_dev->sdioc_boot_sw_header->signature !=
1731 (u32) PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001732 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":invalid "
1733 "mailbox signature 0x%x.\n",
1734 bootloader_dev->sdioc_boot_sw_header->signature);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001735 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 ret = -EINVAL;
1737 goto exit_err;
1738 }
1739
1740 /* Upper byte has to be equal - no backward compatibility for unequal */
1741 if ((bootloader_dev->sdioc_boot_sw_header->version >> 16) !=
1742 (sdio_al->pdata->peer_sdioc_boot_version_major)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001743 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ": HOST(0x%x)"
1744 " and CLIENT(0x%x) SDIO_AL BOOT VERSION don't match\n",
1745 ((sdio_al->pdata->peer_sdioc_boot_version_major<<16)+
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 sdio_al->pdata->peer_sdioc_boot_version_minor),
Krishna Kondaa7af6062011-09-01 18:34:38 -07001747 bootloader_dev->sdioc_boot_sw_header->version);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001748 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001749 ret = -EIO;
1750 goto exit_err;
1751 }
1752
Krishna Kondaa7af6062011-09-01 18:34:38 -07001753 sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ": SDIOC BOOT SW "
1754 "version 0x%x\n",
1755 bootloader_dev->sdioc_boot_sw_header->version);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001756
1757 bootloader_dev->flashless_boot_on = true;
1758
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001759 sdio_al_release_mutex(bootloader_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001760
1761 ret = sdio_al_wait_for_bootloader_comp(bootloader_dev);
1762 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001763 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
1764 ": sdio_al_wait_for_bootloader_comp failed, "
1765 "err=%d\n", ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 goto exit_err;
1767 }
1768
1769 ret = sdio_downloader_setup(bootloader_dev->card, 1,
1770 bootloader_dev->sdioc_boot_sw_header->boot_ch_num,
1771 sdio_al_bootloader_completed);
1772
1773 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001774 sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
1775 ": sdio_downloader_setup failed, err=%d\n", ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 goto exit_err;
1777 }
1778
Krishna Kondaa7af6062011-09-01 18:34:38 -07001779 sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ":In Flashless boot,"
1780 " waiting for its completion\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001781
1782
1783exit_err:
Krishna Kondaa7af6062011-09-01 18:34:38 -07001784 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":free "
1785 "sdioc_boot_sw_header.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 kfree(bootloader_dev->sdioc_boot_sw_header);
1787 bootloader_dev->sdioc_boot_sw_header = NULL;
1788 bootloader_dev = NULL;
1789
1790 return ret;
1791}
1792
1793
1794/**
1795 * Read SDIO-Client software header
1796 *
1797 */
1798static int read_sdioc_software_header(struct sdio_al_device *sdio_al_dev,
1799 struct peer_sdioc_sw_header *header)
1800{
1801 int ret;
1802 int i;
1803 int test_version = 0;
1804 int sdioc_test_version = 0;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001805 struct sdio_func *func1 = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806
1807 pr_debug(MODULE_NAME ":reading sdioc sw header.\n");
1808
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001809 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001810 return -ENODEV;
1811
Maya Erez0fdb5ad2011-10-09 19:16:27 +02001812 func1 = sdio_al_dev->card->sdio_func[0];
1813
1814 ret = sdio_memcpy_fromio(func1, header,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001815 SDIOC_SW_HEADER_ADDR, sizeof(*header));
1816 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001817 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
1818 "sdioc sw header.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819 goto exit_err;
1820 }
1821
1822 if (header->signature == (u32)PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001823 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
1824 "unittest signature. 0x%x\n",
1825 header->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826 sdio_al->unittest_mode = true;
1827 /* Verify test code compatibility with the modem */
1828 sdioc_test_version = (header->version & 0xFF00) >> 8;
1829 test_version = sdio_al->pdata->peer_sdioc_version_minor >> 8;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001830 if (test_version != sdioc_test_version) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001831 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1832 ": HOST(0x%x) and CLIENT(0x%x) "
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001833 "testing VERSION don't match\n",
Krishna Kondaa7af6062011-09-01 18:34:38 -07001834 test_version,
1835 sdioc_test_version);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001836 msleep(500);
1837 BUG();
1838 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 }
1840
1841 if ((header->signature != (u32) PEER_SDIOC_SW_MAILBOX_SIGNATURE) &&
1842 (header->signature != (u32) PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001843 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
1844 "invalid signature. 0x%x\n", header->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001845 goto exit_err;
1846 }
1847 /* Upper byte has to be equal - no backward compatibility for unequal */
1848 sdio_al->sdioc_major = header->version >> 16;
1849 if (sdio_al->pdata->allow_sdioc_version_major_2) {
1850 if ((sdio_al->sdioc_major !=
1851 sdio_al->pdata->peer_sdioc_version_major) &&
1852 (sdio_al->sdioc_major != PEER_SDIOC_OLD_VERSION_MAJOR)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001853 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1854 ": HOST(0x%x) and CLIENT(0x%x) "
1855 "SDIO_AL VERSION don't match\n",
1856 ((sdio_al->pdata->peer_sdioc_version_major<<16)+
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 sdio_al->pdata->peer_sdioc_version_minor),
Krishna Kondaa7af6062011-09-01 18:34:38 -07001858 header->version);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 goto exit_err;
1860 }
1861 } else {
1862 if (sdio_al->sdioc_major !=
1863 sdio_al->pdata->peer_sdioc_version_major) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001864 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
1865 ": HOST(0x%x) and CLIENT(0x%x) "
1866 "SDIO_AL VERSION don't match\n",
1867 ((sdio_al->pdata->peer_sdioc_version_major<<16)+
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001868 sdio_al->pdata->peer_sdioc_version_minor),
Krishna Kondaa7af6062011-09-01 18:34:38 -07001869 header->version);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 goto exit_err;
1871 }
1872 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001873 sdio_al_dev->ch_close_supported = (header->version & 0x000F) >=
1874 (sdio_al->pdata->peer_sdioc_version_minor & 0xF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875
Krishna Kondaa7af6062011-09-01 18:34:38 -07001876 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW version 0x%x,"
1877 " sdio_al major 0x%x minor 0x%x\n", header->version,
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001878 sdio_al->sdioc_major,
1879 sdio_al->pdata->peer_sdioc_version_minor);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880
1881 sdio_al_dev->flashless_boot_on = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
1883 struct sdio_channel *ch = &sdio_al_dev->channel[i];
1884
1885 /* Set default values */
1886 ch->read_threshold = DEFAULT_READ_THRESHOLD;
1887 ch->write_threshold = DEFAULT_WRITE_THRESHOLD;
1888 ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD;
1889 ch->is_packet_mode = true;
1890 ch->peer_tx_buf_size = DEFAULT_PEER_TX_BUF_SIZE;
1891 ch->poll_delay_msec = 0;
1892
1893 ch->num = i;
1894
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001895 ch->func = sdio_al_dev->card->sdio_func[ch->num+1];
1896 ch->rx_pipe_index = ch->num*2;
1897 ch->tx_pipe_index = ch->num*2+1;
1898
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001899 memset(ch->name, 0, sizeof(ch->name));
1900
1901 if (header->channel_names[i][0]) {
1902 memcpy(ch->name, SDIO_PREFIX,
1903 strlen(SDIO_PREFIX));
1904 memcpy(ch->name + strlen(SDIO_PREFIX),
1905 header->channel_names[i],
1906 PEER_CHANNEL_NAME_SIZE);
1907
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001908 ch->state = SDIO_CHANNEL_STATE_IDLE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 ch->sdio_al_dev = sdio_al_dev;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001910 } else {
1911 ch->state = SDIO_CHANNEL_STATE_INVALID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001912 }
1913
Krishna Kondaa7af6062011-09-01 18:34:38 -07001914 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Channel=%s, "
1915 "state=%d\n", ch->name, ch->state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001916 }
1917
1918 return 0;
1919
1920exit_err:
1921 sdio_al_get_into_err_state(sdio_al_dev);
1922 memset(header, 0, sizeof(*header));
1923
1924 return -EIO;
1925}
1926
1927/**
1928 * Read SDIO-Client channel configuration
1929 *
1930 */
1931static int read_sdioc_channel_config(struct sdio_channel *ch)
1932{
1933 int ret;
1934 struct peer_sdioc_sw_mailbox *sw_mailbox = NULL;
1935 struct peer_sdioc_channel_config *ch_config = NULL;
1936 struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
1937
1938 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001939 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
1940 " for channel %s\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 return -EINVAL;
1942 }
1943
1944 if (sdio_al_dev->sdioc_sw_header->version == 0)
1945 return -1;
1946
1947 pr_debug(MODULE_NAME ":reading sw mailbox %s channel.\n", ch->name);
1948
1949 sw_mailbox = kzalloc(sizeof(*sw_mailbox), GFP_KERNEL);
1950 if (sw_mailbox == NULL)
1951 return -ENOMEM;
1952
1953 ret = sdio_memcpy_fromio(ch->func, sw_mailbox,
1954 SDIOC_SW_MAILBOX_ADDR, sizeof(*sw_mailbox));
1955 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001956 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
1957 "sw mailbox.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001958 goto exit_err;
1959 }
1960
1961 ch_config = &sw_mailbox->ch_config[ch->num];
1962 memcpy(&ch->ch_config, ch_config,
1963 sizeof(struct peer_sdioc_channel_config));
1964
1965 if (!ch_config->is_ready) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07001966 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sw mailbox "
1967 "channel not ready.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001968 goto exit_err;
1969 }
1970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971 /* Aggregation up to 90% of the maximum size */
1972 ch->read_threshold = (ch_config->max_rx_threshold * 9) / 10;
1973 /* Threshold on 50% of the maximum size , sdioc uses double-buffer */
1974 ch->write_threshold = (ch_config->max_tx_threshold * 5) / 10;
Maya Erez8ed0a9a2011-07-19 14:46:53 +03001975 ch->threshold_change_cnt = ch->ch_config.max_rx_threshold -
1976 ch->read_threshold + THRESHOLD_CHANGE_EXTRA_BYTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001977
1978 ch->def_read_threshold = ch->read_threshold;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 ch->is_packet_mode = ch_config->is_packet_mode;
1980 if (!ch->is_packet_mode) {
1981 ch->poll_delay_msec = DEFAULT_POLL_DELAY_NOPACKET_MSEC;
1982 ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD_STREAMING;
1983 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001984 /* The max_packet_size is set by the modem in version 3 and on */
1985 if (sdio_al->sdioc_major > PEER_SDIOC_OLD_VERSION_MAJOR)
1986 ch->min_write_avail = ch_config->max_packet_size;
1987
1988 if (ch->min_write_avail > ch->write_threshold)
1989 ch->min_write_avail = ch->write_threshold;
1990
Maya Erez7ad06d82011-10-02 15:47:57 +02001991 CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":ch %s "
Krishna Kondaa7af6062011-09-01 18:34:38 -07001992 "read_threshold=%d, write_threshold=%d,"
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03001993 " min_write_avail=%d, max_rx_threshold=%d,"
1994 " max_tx_threshold=%d\n", ch->name, ch->read_threshold,
1995 ch->write_threshold, ch->min_write_avail,
1996 ch_config->max_rx_threshold,
1997 ch_config->max_tx_threshold);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001998
1999 ch->peer_tx_buf_size = ch_config->tx_buf_size;
2000
2001 kfree(sw_mailbox);
2002
2003 return 0;
2004
2005exit_err:
Krishna Kondaa7af6062011-09-01 18:34:38 -07002006 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Reading SW Mailbox "
2007 "error.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 kfree(sw_mailbox);
2009
2010 return -1;
2011}
2012
2013
2014/**
2015 * Enable/Disable EOT interrupt of a pipe.
2016 *
2017 */
2018static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
2019 int pipe_index, int enable)
2020{
2021 int ret = 0;
2022 struct sdio_func *func1;
2023 u32 mask;
2024 u32 pipe_mask;
2025 u32 addr;
2026
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002027 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 return -ENODEV;
2029 func1 = sdio_al_dev->card->sdio_func[0];
2030
2031 if (pipe_index < 8) {
2032 addr = PIPES_0_7_IRQ_MASK_ADDR;
2033 pipe_mask = (1<<pipe_index);
2034 } else {
2035 addr = PIPES_8_15_IRQ_MASK_ADDR;
2036 pipe_mask = (1<<(pipe_index-8));
2037 }
2038
2039 mask = sdio_readl(func1, addr, &ret);
2040 if (ret) {
2041 pr_debug(MODULE_NAME ":enable_eot_interrupt fail\n");
2042 goto exit_err;
2043 }
2044
2045 if (enable)
2046 mask &= (~pipe_mask); /* 0 = enable */
2047 else
2048 mask |= (pipe_mask); /* 1 = disable */
2049
2050 sdio_writel(func1, mask, addr, &ret);
2051
2052exit_err:
2053 return ret;
2054}
2055
2056
2057/**
2058 * Enable/Disable mask interrupt of a function.
2059 *
2060 */
2061static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
2062 int func_num, int enable, u8 bit_offset)
2063{
2064 int ret = 0;
2065 struct sdio_func *func1 = NULL;
2066 u32 mask = 0;
2067 u32 func_mask = 0;
2068 u32 addr = 0;
2069 u32 offset = 0;
2070
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002071 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002072 return -ENODEV;
2073 func1 = sdio_al_dev->card->sdio_func[0];
2074
2075 if (func_num < 4) {
2076 addr = FUNC_1_4_MASK_IRQ_ADDR;
2077 offset = func_num * 8 + bit_offset;
2078 } else {
2079 addr = FUNC_5_7_MASK_IRQ_ADDR;
2080 offset = (func_num - 4) * 8 + bit_offset;
2081 }
2082
2083 func_mask = 1<<offset;
2084
2085 mask = sdio_readl(func1, addr, &ret);
2086 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002087 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2088 "enable_mask_irq fail\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089 goto exit_err;
2090 }
2091
2092 if (enable)
2093 mask &= (~func_mask); /* 0 = enable */
2094 else
2095 mask |= (func_mask); /* 1 = disable */
2096
2097 pr_debug(MODULE_NAME ":enable_mask_irq, writing mask = 0x%x\n", mask);
2098
2099 sdio_writel(func1, mask, addr, &ret);
2100
2101exit_err:
2102 return ret;
2103}
2104
2105/**
2106 * Enable/Disable Threshold interrupt of a pipe.
2107 *
2108 */
2109static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
2110 int pipe_index, int enable)
2111{
2112 int ret = 0;
2113 struct sdio_func *func1;
2114 u32 mask;
2115 u32 pipe_mask;
2116 u32 addr;
2117
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002118 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119 return -ENODEV;
2120 func1 = sdio_al_dev->card->sdio_func[0];
2121
2122 if (pipe_index < 8) {
2123 addr = PIPES_0_7_IRQ_MASK_ADDR;
2124 pipe_mask = (1<<pipe_index);
2125 } else {
2126 addr = PIPES_8_15_IRQ_MASK_ADDR;
2127 pipe_mask = (1<<(pipe_index-8));
2128 }
2129
2130 mask = sdio_readl(func1, addr, &ret);
2131 if (ret) {
2132 pr_debug(MODULE_NAME ":enable_threshold_interrupt fail\n");
2133 goto exit_err;
2134 }
2135
2136 pipe_mask = pipe_mask<<8; /* Threshold bits 8..15 */
2137 if (enable)
2138 mask &= (~pipe_mask); /* 0 = enable */
2139 else
2140 mask |= (pipe_mask); /* 1 = disable */
2141
2142 sdio_writel(func1, mask, addr, &ret);
2143
2144exit_err:
2145 return ret;
2146}
2147
2148/**
2149 * Set the threshold to trigger interrupt from SDIO-Card on
2150 * pipe available bytes.
2151 *
2152 */
2153static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
2154 int pipe_index, int threshold)
2155{
2156 int ret = 0;
2157 struct sdio_func *func1;
2158
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002159 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002160 return -ENODEV;
2161 func1 = sdio_al_dev->card->sdio_func[0];
2162
2163 sdio_writel(func1, threshold,
2164 PIPES_THRESHOLD_ADDR+pipe_index*4, &ret);
2165 if (ret)
Krishna Kondaa7af6062011-09-01 18:34:38 -07002166 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2167 "set_pipe_threshold err=%d\n", -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002168
2169 return ret;
2170}
2171
2172/**
2173 * Enable func w/ retries
2174 *
2175 */
2176static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name)
2177{
2178 int ret, i;
2179 for (i = 0; i < 200; i++) {
2180 ret = sdio_enable_func(func);
2181 if (ret) {
2182 pr_debug(MODULE_NAME ":retry enable %s func#%d "
2183 "ret=%d\n",
2184 name, func->num, ret);
2185 msleep(10);
2186 } else
2187 break;
2188 }
2189
2190 return ret;
2191}
2192
2193/**
2194 * Open Channel
2195 *
2196 * 1. Init Channel Context.
2197 * 2. Init the Channel SDIO-Function.
2198 * 3. Init the Channel Pipes on Mailbox.
2199 */
2200static int open_channel(struct sdio_channel *ch)
2201{
2202 int ret = 0;
2203 struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
2204
2205 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002206 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL "
2207 "sdio_al_dev for channel %s\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208 return -EINVAL;
2209 }
2210
2211 /* Init channel Context */
2212 /** Func#1 is reserved for mailbox */
2213 ch->func = sdio_al_dev->card->sdio_func[ch->num+1];
2214 ch->rx_pipe_index = ch->num*2;
2215 ch->tx_pipe_index = ch->num*2+1;
2216 ch->signature = SDIO_AL_SIGNATURE;
2217
2218 ch->total_rx_bytes = 0;
2219 ch->total_tx_bytes = 0;
2220
2221 ch->write_avail = 0;
2222 ch->read_avail = 0;
2223 ch->rx_pending_bytes = 0;
2224
2225 mutex_init(&ch->ch_lock);
2226
2227 pr_debug(MODULE_NAME ":open_channel %s func#%d\n",
2228 ch->name, ch->func->num);
2229
2230 INIT_LIST_HEAD(&(ch->rx_size_list_head));
2231
2232 /* Init SDIO Function */
2233 ret = sdio_al_enable_func_retry(ch->func, ch->name);
2234 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002235 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2236 "sdio_enable_func() err=%d\n", -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002237 goto exit_err;
2238 }
2239
2240 /* Note: Patch Func CIS tuple issue */
2241 ret = sdio_set_block_size(ch->func, SDIO_AL_BLOCK_SIZE);
2242 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002243 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2244 "sdio_set_block_size()failed, err=%d\n", -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002245 goto exit_err;
2246 }
2247
2248 ch->func->max_blksize = SDIO_AL_BLOCK_SIZE;
2249
2250 sdio_set_drvdata(ch->func, ch);
2251
2252 /* Get channel parameters from the peer SDIO-Client */
2253 read_sdioc_channel_config(ch);
2254
2255 /* Set Pipes Threshold on Mailbox */
2256 ret = set_pipe_threshold(sdio_al_dev,
2257 ch->rx_pipe_index, ch->read_threshold);
2258 if (ret)
2259 goto exit_err;
2260 ret = set_pipe_threshold(sdio_al_dev,
2261 ch->tx_pipe_index, ch->write_threshold);
2262 if (ret)
2263 goto exit_err;
2264
2265 /* Set flag before interrupts are enabled to allow notify */
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002266 ch->state = SDIO_CHANNEL_STATE_OPEN;
2267 pr_debug(MODULE_NAME ":channel %s is in OPEN state now\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268
2269 sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
2270
2271 /* lpm mechanism lives under the assumption there is always a timer */
2272 /* Check if need to start the timer */
2273 if ((sdio_al_dev->poll_delay_msec) &&
2274 (sdio_al_dev->is_timer_initialized == false)) {
2275
2276 init_timer(&sdio_al_dev->timer);
2277 sdio_al_dev->timer.data = (unsigned long) sdio_al_dev;
2278 sdio_al_dev->timer.function = sdio_al_timer_handler;
2279 sdio_al_dev->timer.expires = jiffies +
2280 msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
2281 add_timer(&sdio_al_dev->timer);
2282 sdio_al_dev->is_timer_initialized = true;
2283 }
2284
2285 /* Enable Pipes Interrupts */
2286 enable_eot_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
2287 enable_eot_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
2288
2289 enable_threshold_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
2290 enable_threshold_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
2291
2292exit_err:
2293
2294 return ret;
2295}
2296
2297/**
2298 * Ask the worker to read the mailbox.
2299 */
2300static void ask_reading_mailbox(struct sdio_al_device *sdio_al_dev)
2301{
2302 if (!sdio_al_dev->ask_mbox) {
2303 pr_debug(MODULE_NAME ":ask_reading_mailbox for card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002304 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305 sdio_al_dev->ask_mbox = true;
2306 wake_up(&sdio_al_dev->wait_mbox);
2307 }
2308}
2309
2310/**
2311 * Start the timer
2312 */
2313static void start_timer(struct sdio_al_device *sdio_al_dev)
2314{
2315 if ((sdio_al_dev->poll_delay_msec) &&
2316 (sdio_al_dev->state == CARD_INSERTED)) {
2317 sdio_al_dev->timer.expires = jiffies +
2318 msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
2319 add_timer(&sdio_al_dev->timer);
2320 }
2321}
2322
2323/**
2324 * Restart(postpone) the already working timer
2325 */
2326static void restart_timer(struct sdio_al_device *sdio_al_dev)
2327{
2328 if ((sdio_al_dev->poll_delay_msec) &&
2329 (sdio_al_dev->state == CARD_INSERTED)) {
2330 ulong expires = jiffies +
2331 msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
2332 mod_timer(&sdio_al_dev->timer, expires);
2333 }
2334}
2335
2336/**
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002337 * Stop and delete the timer
2338 */
2339static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev)
2340{
2341 if (sdio_al_dev->is_timer_initialized) {
2342 sdio_al_dev->poll_delay_msec = 0;
2343 del_timer_sync(&sdio_al_dev->timer);
2344 }
2345}
2346
2347/**
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002348 * Do the wakup sequence.
2349 * This function should be called after claiming the host!
2350 * The caller is responsible for releasing the host.
2351 *
2352 * Wake up sequence
2353 * 1. Get lock
2354 * 2. Enable wake up function if needed
2355 * 3. Mark NOT OK to sleep and write it
2356 * 4. Restore default thresholds
2357 * 5. Start the mailbox and inactivity timer again
2358 */
2359static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
Maya Erez7b1ebd22011-08-20 20:53:24 +03002360 u32 not_from_int, struct sdio_channel *ch)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002361{
Maya Erez8ed0a9a2011-07-19 14:46:53 +03002362 int ret = 0;
Maya Erez86cebda2011-10-11 11:13:40 +02002363 struct sdio_func *wk_func = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002364 unsigned long time_to_wait;
Maya Erez86cebda2011-10-11 11:13:40 +02002365 struct mmc_host *host = sdio_al_dev->host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366
2367 if (sdio_al_dev->is_err) {
2368 SDIO_AL_ERR(__func__);
2369 return -ENODEV;
2370 }
2371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372 if (!sdio_al_dev->is_ok_to_sleep) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002373 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":card %d "
2374 "already awake, no need to wake up\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002375 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002376 return 0;
2377 }
Maya Erez7b1ebd22011-08-20 20:53:24 +03002378
2379 /* Wake up sequence */
2380 if (not_from_int) {
2381 if (ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002382 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
2383 " card %d (not by interrupt), ch %s",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002384 sdio_al_dev->host->index,
Krishna Kondaa7af6062011-09-01 18:34:38 -07002385 ch->name);
Maya Erez7b1ebd22011-08-20 20:53:24 +03002386 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002387 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
2388 " card %d (not by interrupt)",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002389 sdio_al_dev->host->index);
Maya Erez7b1ebd22011-08-20 20:53:24 +03002390 }
2391 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002392 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up card "
2393 "%d by interrupt",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002394 sdio_al_dev->host->index);
Maya Erez7b1ebd22011-08-20 20:53:24 +03002395 sdio_al_dev->print_after_interrupt = 1;
2396 }
2397
Yaniv Gardi3e327762011-07-27 11:11:04 +03002398 sdio_al_vote_for_sleep(sdio_al_dev, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002400 msmsdcc_lpm_disable(host);
Maya Erez86cebda2011-10-11 11:13:40 +02002401 msmsdcc_set_pwrsave(host, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402 /* Poll the GPIO */
2403 time_to_wait = jiffies + msecs_to_jiffies(1000);
2404 while (time_before(jiffies, time_to_wait)) {
2405 if (sdio_al->pdata->get_mdm2ap_status())
2406 break;
2407 udelay(TIME_TO_WAIT_US);
2408 }
Yaniv Gardi3e327762011-07-27 11:11:04 +03002409
Maya Erez7b1ebd22011-08-20 20:53:24 +03002410 pr_debug(MODULE_NAME ":GPIO mdm2ap_status=%d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002411 sdio_al->pdata->get_mdm2ap_status());
2412
2413 /* Here get_mdm2ap_status() returning 0 is not an error condition */
2414 if (sdio_al->pdata->get_mdm2ap_status() == 0)
Krishna Kondaa7af6062011-09-01 18:34:38 -07002415 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": "
2416 "get_mdm2ap_status() is 0\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417
2418 /* Enable Wake up Function */
Maya Erez86cebda2011-10-11 11:13:40 +02002419 if (!sdio_al_dev->card ||
2420 !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
2421 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
2422 ": NULL card or wk_func\n");
2423 return -ENODEV;
2424 }
2425 wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002426 ret = sdio_al_enable_func_retry(wk_func, "wakeup func");
2427 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002428 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2429 "sdio_enable_func() err=%d\n", -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002430 goto error_exit;
2431 }
2432 /* Mark NOT OK_TOSLEEP */
2433 sdio_al_dev->is_ok_to_sleep = 0;
2434 ret = write_lpm_info(sdio_al_dev);
2435 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002436 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
2437 "write_lpm_info() failed, err=%d\n", -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002438 sdio_al_dev->is_ok_to_sleep = 1;
2439 sdio_disable_func(wk_func);
2440 goto error_exit;
2441 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 sdio_disable_func(wk_func);
2443
2444 /* Start the timer again*/
2445 restart_inactive_time(sdio_al_dev);
2446 sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
2447 start_timer(sdio_al_dev);
2448
Krishna Kondaa7af6062011-09-01 18:34:38 -07002449 LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME "Finished Wake up sequence"
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002450 " for card %d", sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451
Maya Erez86cebda2011-10-11 11:13:40 +02002452 msmsdcc_set_pwrsave(host, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 pr_debug(MODULE_NAME ":Turn clock off\n");
2454
2455 return ret;
2456error_exit:
2457 sdio_al_vote_for_sleep(sdio_al_dev, 1);
Maya Erez86cebda2011-10-11 11:13:40 +02002458 msmsdcc_set_pwrsave(host, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459 WARN_ON(ret);
2460 sdio_al_get_into_err_state(sdio_al_dev);
2461 return ret;
2462}
2463
2464
2465/**
2466 * SDIO Function Interrupt handler.
2467 *
2468 * Interrupt shall be triggered by SDIO-Client when:
2469 * 1. End-Of-Transfer (EOT) detected in packet mode.
2470 * 2. Bytes-available reached the threshold.
2471 *
2472 * Reading the mailbox clears the EOT/Threshold interrupt
2473 * source.
2474 * The interrupt source should be cleared before this ISR
2475 * returns. This ISR is called from IRQ Thread and not
2476 * interrupt, so it may sleep.
2477 *
2478 */
2479static void sdio_func_irq(struct sdio_func *func)
2480{
2481 struct sdio_al_device *sdio_al_dev = sdio_get_drvdata(func);
2482
2483 pr_debug(MODULE_NAME ":start %s.\n", __func__);
2484
2485 if (sdio_al_dev == NULL) {
Maya Erez86cebda2011-10-11 11:13:40 +02002486 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL device");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 return;
2488 }
2489
2490 if (sdio_al_dev->is_ok_to_sleep)
Maya Erez7b1ebd22011-08-20 20:53:24 +03002491 sdio_al_wake_up(sdio_al_dev, 0, NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492 else
2493 restart_timer(sdio_al_dev);
2494
2495 read_mailbox(sdio_al_dev, true);
2496
2497 pr_debug(MODULE_NAME ":end %s.\n", __func__);
2498}
2499
2500/**
2501 * Timer Expire Handler
2502 *
2503 */
2504static void sdio_al_timer_handler(unsigned long data)
2505{
2506 struct sdio_al_device *sdio_al_dev = (struct sdio_al_device *)data;
2507 if (sdio_al_dev == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002508 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": NULL "
2509 "sdio_al_dev for data %lu\n", data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002510 return;
2511 }
2512 if (sdio_al_dev->state != CARD_INSERTED) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002513 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": sdio_al_dev "
2514 "is in invalid state %d\n", sdio_al_dev->state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515 return;
2516 }
2517 pr_debug(MODULE_NAME " Timer Expired\n");
2518
2519 ask_reading_mailbox(sdio_al_dev);
2520
2521 restart_timer(sdio_al_dev);
2522}
2523
2524/**
2525 * Driver Setup.
2526 *
2527 */
2528static int sdio_al_setup(struct sdio_al_device *sdio_al_dev)
2529{
2530 int ret = 0;
2531 struct mmc_card *card = sdio_al_dev->card;
2532 struct sdio_func *func1 = NULL;
2533 int i = 0;
2534 int fn = 0;
2535
Maya Erez86cebda2011-10-11 11:13:40 +02002536 if (sdio_al_verify_func1(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002537 return -ENODEV;
Maya Erez86cebda2011-10-11 11:13:40 +02002538 func1 = card->sdio_func[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539
Krishna Kondaa7af6062011-09-01 18:34:38 -07002540 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_setup for "
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002541 "card %d\n", sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002543 ret = sdio_al->pdata->config_mdm2ap_status(1);
2544 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002545 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME "Could not "
2546 "request GPIO\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547 return ret;
2548 }
2549
2550 INIT_WORK(&sdio_al_dev->sdio_al_work.work, worker);
2551 /* disable all pipes interrupts before claim irq.
2552 since all are enabled by default. */
2553 for (i = 0 ; i < SDIO_AL_MAX_PIPES; i++) {
2554 enable_eot_interrupt(sdio_al_dev, i, false);
2555 enable_threshold_interrupt(sdio_al_dev, i, false);
2556 }
2557
2558 /* Disable all SDIO Functions before claim irq. */
2559 for (fn = 1 ; fn <= card->sdio_funcs; fn++)
2560 sdio_disable_func(card->sdio_func[fn-1]);
2561
2562 sdio_set_drvdata(func1, sdio_al_dev);
Krishna Kondaa7af6062011-09-01 18:34:38 -07002563 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":claim IRQ for card "
Maya Erez86cebda2011-10-11 11:13:40 +02002564 "%d\n", sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002565
2566 ret = sdio_claim_irq(func1, sdio_func_irq);
2567 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002568 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to claim"
2569 " IRQ for card %d\n",
Maya Erez86cebda2011-10-11 11:13:40 +02002570 sdio_al_dev->host->index);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002571 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002572 }
2573
2574 sdio_al_dev->is_ready = true;
2575
2576 /* Start worker before interrupt might happen */
2577 queue_work(sdio_al_dev->workqueue, &sdio_al_dev->sdio_al_work.work);
2578
2579 start_inactive_time(sdio_al_dev);
2580
2581 pr_debug(MODULE_NAME ":Ready.\n");
2582
2583 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002584}
2585
2586/**
2587 * Driver Tear-Down.
2588 *
2589 */
2590static void sdio_al_tear_down(void)
2591{
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002592 int i, j;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593 struct sdio_al_device *sdio_al_dev = NULL;
2594 struct sdio_func *func1;
2595
2596 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
2597 if (sdio_al->devices[i] == NULL)
2598 continue;
2599 sdio_al_dev = sdio_al->devices[i];
2600
2601 if (sdio_al_dev->is_ready) {
2602 sdio_al_dev->is_ready = false; /* Flag worker to exit */
2603 sdio_al_dev->ask_mbox = false;
2604 ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
2605 /* allow gracefully exit of the worker thread */
2606 msleep(100);
2607
2608 flush_workqueue(sdio_al_dev->workqueue);
2609 destroy_workqueue(sdio_al_dev->workqueue);
2610
2611 sdio_al_vote_for_sleep(sdio_al_dev, 1);
2612
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002613 if (!sdio_al_claim_mutex_and_verify_dev(sdio_al_dev,
2614 __func__)) {
2615 if (!sdio_al_dev->card ||
2616 !sdio_al_dev->card->sdio_func[0]) {
2617 sdio_al_loge(sdio_al_dev->dev_log,
2618 MODULE_NAME
2619 ": %s: Invalid func1",
2620 __func__);
2621 return;
2622 }
2623 func1 = sdio_al_dev->card->sdio_func[0];
2624 sdio_release_irq(func1);
2625 sdio_disable_func(func1);
2626 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002627 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002629
2630 for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++)
2631 sdio_al_dev->channel[j].signature = 0x0;
2632 sdio_al_dev->signature = 0;
2633
2634 kfree(sdio_al_dev->sdioc_sw_header);
2635 kfree(sdio_al_dev->mailbox);
2636 kfree(sdio_al_dev->rx_flush_buf);
2637 kfree(sdio_al_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002638 }
2639
2640 sdio_al->pdata->config_mdm2ap_status(0);
2641}
2642
2643/**
2644 * Find channel by name.
2645 *
2646 */
2647static struct sdio_channel *find_channel_by_name(const char *name)
2648{
2649 struct sdio_channel *ch = NULL;
2650 int i, j;
2651 struct sdio_al_device *sdio_al_dev = NULL;
2652
2653 for (j = 0; j < MAX_NUM_OF_SDIO_DEVICES; ++j) {
2654 if (sdio_al->devices[j] == NULL)
2655 continue;
2656 sdio_al_dev = sdio_al->devices[j];
2657 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002658 if (sdio_al_dev->channel[i].state ==
2659 SDIO_CHANNEL_STATE_INVALID)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660 continue;
2661 if (strcmp(sdio_al_dev->channel[i].name, name) == 0) {
2662 ch = &sdio_al_dev->channel[i];
2663 break;
2664 }
2665 }
2666 if (ch != NULL)
2667 break;
2668 }
2669
2670 return ch;
2671}
2672
2673/**
2674 * Find the minimal poll time.
2675 *
2676 */
2677static int get_min_poll_time_msec(struct sdio_al_device *sdio_sl_dev)
2678{
2679 int i;
2680 int poll_delay_msec = 0x0FFFFFFF;
2681
2682 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++)
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002683 if ((sdio_sl_dev->channel[i].state ==
2684 SDIO_CHANNEL_STATE_OPEN) &&
2685 (sdio_sl_dev->channel[i].poll_delay_msec > 0) &&
2686 (sdio_sl_dev->channel[i].poll_delay_msec < poll_delay_msec))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687 poll_delay_msec =
2688 sdio_sl_dev->channel[i].poll_delay_msec;
2689
2690 if (poll_delay_msec == 0x0FFFFFFF)
2691 poll_delay_msec = SDIO_AL_POLL_TIME_NO_STREAMING;
2692
2693 pr_debug(MODULE_NAME ":poll delay time is %d msec\n", poll_delay_msec);
2694
2695 return poll_delay_msec;
2696}
2697
2698/**
2699 * Open SDIO Channel.
2700 *
2701 * Enable the channel.
2702 * Set the channel context.
2703 * Trigger reading the mailbox to check available bytes.
2704 *
2705 */
2706int sdio_open(const char *name, struct sdio_channel **ret_ch, void *priv,
2707 void (*notify)(void *priv, unsigned ch_event))
2708{
2709 int ret = 0;
2710 struct sdio_channel *ch = NULL;
2711 struct sdio_al_device *sdio_al_dev = NULL;
2712
2713 *ret_ch = NULL; /* default */
2714
2715 ch = find_channel_by_name(name);
2716 if (ch == NULL) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002717 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":Can't find "
2718 "channel name %s\n", name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002719 return -EINVAL;
2720 }
2721
2722 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002723 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002724 return -ENODEV;
2725
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002726 if ((ch->state != SDIO_CHANNEL_STATE_IDLE) &&
2727 (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002728 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Wrong ch %s "
2729 "state %d\n", name, ch->state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002730 ret = -EPERM;
2731 goto exit_err;
2732 }
2733
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002734 if (sdio_al_dev->is_err) {
2735 SDIO_AL_ERR(__func__);
2736 ret = -ENODEV;
2737 goto exit_err;
2738 }
2739
Maya Erez7b1ebd22011-08-20 20:53:24 +03002740 ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002741 if (ret)
2742 goto exit_err;
2743
2744 ch->notify = notify;
2745 ch->priv = priv;
2746
2747 /* Note: Set caller returned context before interrupts are enabled */
2748 *ret_ch = ch;
2749
2750 ret = open_channel(ch);
2751 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002752 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
2753 "err=%d\n", name, -ret);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002754 goto exit_err;
2755 }
2756
Maya Erez7ad06d82011-10-02 15:47:57 +02002757 CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
2758 "completed OK\n", name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002759 if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
2760 if (sdio_al->sdioc_major == PEER_SDIOC_OLD_VERSION_MAJOR) {
2761 if (!ch->is_packet_mode) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002762 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
2763 ":setting channel %s as "
2764 "lpm_chan\n", name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002765 sdio_al_dev->lpm_chan = ch->num;
2766 }
2767 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002768 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": "
2769 "setting channel %s as lpm_chan\n",
2770 name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771 sdio_al_dev->lpm_chan = ch->num;
2772 }
2773 }
2774
2775exit_err:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002776 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002777 return ret;
2778}
2779EXPORT_SYMBOL(sdio_open);
2780
2781/**
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002782 * Request peer operation
2783 * note: sanity checks of parameters done by caller
2784 * called under bus locked
2785 */
2786static int peer_set_operation(u32 opcode,
2787 struct sdio_al_device *sdio_al_dev,
2788 struct sdio_channel *ch)
2789{
2790 int ret;
2791 int offset;
2792 struct sdio_func *wk_func;
2793 u32 peer_operation;
2794 int loop_count = 0;
2795
2796 wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
2797 if (!wk_func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002798 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL "
2799 "wakeup func:%d\n", __func__,
2800 SDIO_AL_WAKEUP_FUNC);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002801 ret = -ENODEV;
2802 goto exit;
2803 }
2804 /* calculate offset of peer_operation field in sw mailbox struct */
2805 offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config) +
2806 sizeof(struct peer_sdioc_channel_config) * ch->num +
2807 offsetof(struct peer_sdioc_channel_config, peer_operation);
2808
Maya Erez7b1ebd22011-08-20 20:53:24 +03002809 ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002810 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002811 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
2812 "wake up\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002813 goto exit;
2814 }
2815 /* request operation from MDM peer */
2816 peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_INIT);
2817 ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
2818 &peer_operation, sizeof(u32));
2819 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002820 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
2821 "request close operation\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002822 goto exit;
2823 }
2824 ret = sdio_al_enable_func_retry(wk_func, "wk_func");
2825 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002826 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to enable"
2827 " Func#%d\n", wk_func->num);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002828 goto exit;
2829 }
2830 pr_debug(MODULE_NAME ":%s: wk_func enabled on ch %s\n",
2831 __func__, ch->name);
2832 /* send "start" operation to MDM */
2833 peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_START);
2834 ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
2835 &peer_operation, sizeof(u32));
2836 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002837 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
2838 "send start close operation\n");
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002839 goto exit;
2840 }
2841 ret = sdio_disable_func(wk_func);
2842 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002843 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
2844 "disable Func#%d\n", wk_func->num);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002845 goto exit;
2846 }
2847 /* poll for peer operation ack */
2848 while (peer_operation != 0) {
2849 ret = sdio_memcpy_fromio(ch->func,
2850 &peer_operation,
2851 SDIOC_SW_MAILBOX_ADDR+offset,
2852 sizeof(u32));
2853 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002854 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
2855 ":failed to request ack on close"
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002856 " operation, loop_count = %d\n",
2857 loop_count);
2858 goto exit;
2859 }
2860 loop_count++;
2861 if (loop_count > 10) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002862 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
2863 "peer_operation=0x%x wait loop"
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002864 " %d on ch %s\n", __func__,
2865 peer_operation, loop_count, ch->name);
2866 }
2867 }
2868exit:
2869 return ret;
2870}
2871
Konstantin Dorfman52890522011-10-05 11:03:19 +02002872static int channel_close(struct sdio_channel *ch, int flush_flag)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002873{
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002874 int ret;
2875 struct sdio_al_device *sdio_al_dev = NULL;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002876 int flush_len;
2877 ulong flush_expires;
2878
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002880 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
2881 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002882 return -ENODEV;
2883 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002884
2885 if (!ch->func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002886 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL func"
2887 " on channel:%d\n", __func__, ch->num);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002888 return -ENODEV;
2889 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002890
2891 sdio_al_dev = ch->sdio_al_dev;
2892 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
2893 return -ENODEV;
2894
2895 if (!sdio_al_dev->ch_close_supported) {
2896 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: Not "
2897 "supported by mdm, ch %s\n",
2898 __func__, ch->name);
2899 ret = -ENOTSUPP;
2900 goto error_exit;
2901 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002902
2903 if (sdio_al_dev->is_err) {
2904 SDIO_AL_ERR(__func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002905 ret = -ENODEV;
2906 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002907 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02002908 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
2909 sdio_al_loge(sdio_al_dev->dev_log,
2910 MODULE_NAME ":%s: ch %s is not in "
2911 "open state (%d)\n",
2912 __func__, ch->name, ch->state);
2913 ret = -ENODEV;
2914 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002915 }
2916 ch->state = SDIO_CHANNEL_STATE_CLOSING;
2917 ret = peer_set_operation(PEER_OP_CODE_CLOSE, sdio_al_dev, ch);
2918 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07002919 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
2920 "peer_set_operation() failed: %d\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002921 __func__, ret);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002922 ret = -ENODEV;
2923 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002924 }
2925 /* udate poll time for opened channels */
2926 if (ch->poll_delay_msec > 0) {
2927 sdio_al_dev->poll_delay_msec =
2928 get_min_poll_time_msec(sdio_al_dev);
2929 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002930 sdio_al_release_mutex(ch->sdio_al_dev, __func__);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002931
2932 flush_expires = jiffies +
2933 msecs_to_jiffies(SDIO_CLOSE_FLUSH_TIMEOUT_MSEC);
2934 /* flush rx packets of the channel */
Konstantin Dorfman52890522011-10-05 11:03:19 +02002935 if (flush_flag) {
2936 do {
2937 while (ch->read_avail > 0) {
2938 flush_len = ch->read_avail;
2939 ret = sdio_read_internal(ch,
2940 sdio_al_dev->rx_flush_buf,
2941 flush_len);
2942 if (ret) {
2943 sdio_al_loge(&sdio_al->gen_log,
2944 MODULE_NAME ":%s sdio_read"
2945 " failed: %d, ch %s\n",
2946 __func__, ret,
2947 ch->name);
2948 return ret;
2949 }
Yaniv Gardic4663632011-08-31 19:55:38 +03002950
Konstantin Dorfman52890522011-10-05 11:03:19 +02002951 if (time_after(jiffies, flush_expires) != 0) {
2952 sdio_al_loge(&sdio_al->gen_log,
2953 MODULE_NAME ":%s flush rx "
2954 "packets timeout: ch %s\n",
Krishna Kondaa7af6062011-09-01 18:34:38 -07002955 __func__, ch->name);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002956 sdio_al_get_into_err_state(sdio_al_dev);
2957 return -EBUSY;
2958 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002959 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02002960 msleep(100);
2961 if (ch->signature != SDIO_AL_SIGNATURE) {
2962 sdio_al_loge(&sdio_al->gen_log,
2963 MODULE_NAME ":%s: after sleep,"
2964 " invalid signature"
2965 " 0x%x\n", __func__,
2966 ch->signature);
2967 return -ENODEV;
2968 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002969 if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
2970 __func__))
Konstantin Dorfman52890522011-10-05 11:03:19 +02002971 return -ENODEV;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002972
Konstantin Dorfman52890522011-10-05 11:03:19 +02002973 ret = read_mailbox(sdio_al_dev, false);
2974 if (ret) {
2975 sdio_al_loge(&sdio_al->gen_log,
2976 MODULE_NAME ":%s: failed to"
2977 " read mailbox", __func__);
2978 goto error_exit;
2979 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002980 sdio_al_release_mutex(ch->sdio_al_dev, __func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002981 } while (ch->read_avail > 0);
2982 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002983 if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
2984 __func__))
2985 return -ENODEV;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002986 /* disable function to be able to open the channel again */
2987 ret = sdio_disable_func(ch->func);
2988 if (ret) {
Konstantin Dorfman52890522011-10-05 11:03:19 +02002989 sdio_al_loge(&sdio_al->gen_log,
2990 MODULE_NAME ":Fail to disable Func#%d\n",
2991 ch->func->num);
2992 goto error_exit;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03002993 }
2994 ch->state = SDIO_CHANNEL_STATE_CLOSED;
Maya Erez7ad06d82011-10-02 15:47:57 +02002995 CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":%s: Ch %s closed "
2996 "successfully\n", __func__, ch->name);
Konstantin Dorfman52890522011-10-05 11:03:19 +02002997
2998error_exit:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02002999 sdio_al_release_mutex(ch->sdio_al_dev, __func__);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003000
3001 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003002}
Konstantin Dorfman52890522011-10-05 11:03:19 +02003003
3004/**
3005 * Close SDIO Channel.
3006 *
3007 */
3008int sdio_close(struct sdio_channel *ch)
3009{
3010 return channel_close(ch, true);
3011}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003012EXPORT_SYMBOL(sdio_close);
3013
3014/**
3015 * Get the number of available bytes to write.
3016 *
3017 */
3018int sdio_write_avail(struct sdio_channel *ch)
3019{
3020 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003021 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3022 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003023 return -ENODEV;
3024 }
3025 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003026 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
3027 "Invalid signature 0x%x\n", __func__,
3028 ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003029 return -ENODEV;
3030 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003031 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003032 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
3033 "channel %s state is not open (%d)\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003034 __func__, ch->name, ch->state);
3035 return -ENODEV;
3036 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003037 pr_debug(MODULE_NAME ":sdio_write_avail %s 0x%x\n",
3038 ch->name, ch->write_avail);
3039
3040 return ch->write_avail;
3041}
3042EXPORT_SYMBOL(sdio_write_avail);
3043
3044/**
3045 * Get the number of available bytes to read.
3046 *
3047 */
3048int sdio_read_avail(struct sdio_channel *ch)
3049{
3050 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003051 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3052 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003053 return -ENODEV;
3054 }
3055 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003056 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
3057 "Invalid signature 0x%x\n", __func__,
3058 ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003059 return -ENODEV;
3060 }
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003061 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003062 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
3063 "channel %s state is not open (%d)\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003064 __func__, ch->name, ch->state);
3065 return -ENODEV;
3066 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003067 pr_debug(MODULE_NAME ":sdio_read_avail %s 0x%x\n",
3068 ch->name, ch->read_avail);
3069
3070 return ch->read_avail;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003071}
3072EXPORT_SYMBOL(sdio_read_avail);
3073
Maya Erez5795e0d2011-09-12 20:20:06 +03003074static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len)
3075{
3076 int ret = 0;
3077 struct sdio_al_device *sdio_al_dev = NULL;
3078
3079 if (!ch) {
Konstantin Dorfman52890522011-10-05 11:03:19 +02003080 sdio_al_loge(ch->sdio_al_dev->dev_log,
3081 MODULE_NAME ":%s: NULL channel\n", __func__);
Maya Erez5795e0d2011-09-12 20:20:06 +03003082 return -ENODEV;
3083 }
3084
3085 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003086 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
3087 return -ENODEV;
Maya Erez5795e0d2011-09-12 20:20:06 +03003088
3089 ret = sdio_memcpy_fromio(ch->func, sdio_al_dev->rx_flush_buf,
3090 PIPE_RX_FIFO_ADDR, len);
3091
3092 if (ret) {
Konstantin Dorfman52890522011-10-05 11:03:19 +02003093 sdio_al_loge(ch->sdio_al_dev->dev_log,
3094 MODULE_NAME ":ch %s: %s err=%d, len=%d\n",
Maya Erez5795e0d2011-09-12 20:20:06 +03003095 ch->name, __func__, -ret, len);
3096 sdio_al_dev->is_err = true;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003097 sdio_al_release_mutex(sdio_al_dev, __func__);
Maya Erez5795e0d2011-09-12 20:20:06 +03003098 return ret;
3099 }
3100
3101 restart_inactive_time(sdio_al_dev);
3102
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003103 sdio_al_release_mutex(sdio_al_dev, __func__);
Maya Erez5795e0d2011-09-12 20:20:06 +03003104
3105 return 0;
3106}
3107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108/**
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003109 * Internal read from SDIO Channel.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003110 *
3111 * Reading from the pipe will trigger interrupt if there are
3112 * other pending packets on the SDIO-Client.
3113 *
3114 */
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003115static int sdio_read_internal(struct sdio_channel *ch, void *data, int len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003116{
3117 int ret = 0;
3118 struct sdio_al_device *sdio_al_dev = NULL;
3119
3120 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003121 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3122 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003123 return -ENODEV;
3124 }
3125 if (!data) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003126 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
3127 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003128 return -ENODEV;
3129 }
3130 if (len == 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003131 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
3132 " to read 0 bytes\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003133 return -EINVAL;
3134 }
3135
3136 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003137 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
3138 "signature 0x%x\n", __func__, ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003139 return -ENODEV;
3140 }
3141
3142 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003143 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003144 return -ENODEV;
3145
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003146 if (sdio_al_dev->is_err) {
3147 SDIO_AL_ERR(__func__);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003148 ret = -ENODEV;
3149 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003150 }
3151
3152 /* lpm policy says we can't go to sleep when we have pending rx data,
3153 so either we had rx interrupt and woken up, or we never went to
3154 sleep */
3155 if (sdio_al_dev->is_ok_to_sleep) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003156 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: called "
3157 "when is_ok_to_sleep is set for ch %s, len=%d,"
3158 " last_any_read_avail=%d, last_read_avail=%d, "
3159 "last_old_read_avail=%d", __func__, ch->name,
3160 len, ch->statistics.last_any_read_avail,
3161 ch->statistics.last_read_avail,
3162 ch->statistics.last_old_read_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163 }
3164 BUG_ON(sdio_al_dev->is_ok_to_sleep);
3165
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003166 if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
3167 (ch->state != SDIO_CHANNEL_STATE_CLOSING)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003168 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s wrong "
3169 "channel %s state %d\n",
3170 __func__, ch->name, ch->state);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003171 ret = -EINVAL;
3172 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003173 }
3174
Krishna Kondaa7af6062011-09-01 18:34:38 -07003175 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s read %d "
3176 "avail %d.\n", ch->name, len, ch->read_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003177
3178 restart_inactive_time(sdio_al_dev);
3179
3180 if ((ch->is_packet_mode) && (len != ch->read_avail)) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003181 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_read ch "
3182 "%s len != read_avail\n", ch->name);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003183 ret = -EINVAL;
3184 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003185 }
3186
3187 if (len > ch->read_avail) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003188 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
3189 "reading more bytes (%d) than the avail(%d).\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003190 ch->name, len, ch->read_avail);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003191 ret = -ENOMEM;
3192 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003193 }
3194
3195 ret = sdio_memcpy_fromio(ch->func, data, PIPE_RX_FIFO_ADDR, len);
3196
3197 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003198 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ch %s: "
3199 "sdio_read err=%d, len=%d, read_avail=%d, "
3200 "last_read_avail=%d, last_old_read_avail=%d\n",
Maya Erezd9cc2292011-08-04 09:20:31 +03003201 ch->name, -ret, len, ch->read_avail,
3202 ch->statistics.last_read_avail,
3203 ch->statistics.last_old_read_avail);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003204 sdio_al_get_into_err_state(sdio_al_dev);
3205 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003206 }
3207
3208 ch->statistics.total_read_times++;
3209
3210 /* Remove handled packet from the list regardless if ret is ok */
3211 if (ch->is_packet_mode)
3212 remove_handled_rx_packet(ch);
3213 else
3214 ch->read_avail -= len;
3215
3216 ch->total_rx_bytes += len;
Krishna Kondaa7af6062011-09-01 18:34:38 -07003217 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s read %d "
3218 "avail %d total %d.\n", ch->name, len,
3219 ch->read_avail, ch->total_rx_bytes);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003220
3221 if ((ch->read_avail == 0) && !(ch->is_packet_mode))
3222 ask_reading_mailbox(sdio_al_dev);
3223
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003224exit:
3225 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003226
3227 return ret;
3228}
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003229
3230/**
3231 * Read from SDIO Channel.
3232 *
3233 * Reading from the pipe will trigger interrupt if there are
3234 * other pending packets on the SDIO-Client.
3235 *
3236 */
3237int sdio_read(struct sdio_channel *ch, void *data, int len)
3238{
3239 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003240 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3241 "channel\n", __func__);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003242 return -ENODEV;
3243 }
3244 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003245 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
3246 "Invalid signature 0x%x\n", __func__, ch->signature);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003247 return -ENODEV;
3248 }
3249 if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
3250 return sdio_read_internal(ch, data, len);
3251 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003252 sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME
3253 ":%s: Invalid channel %s state %d\n",
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003254 __func__, ch->name, ch->state);
3255 }
3256 return -ENODEV;
3257}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003258EXPORT_SYMBOL(sdio_read);
3259
3260/**
3261 * Write to SDIO Channel.
3262 *
3263 */
3264int sdio_write(struct sdio_channel *ch, const void *data, int len)
3265{
3266 int ret = 0;
3267 struct sdio_al_device *sdio_al_dev = NULL;
3268
3269 if (!ch) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003270 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
3271 "channel\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003272 return -ENODEV;
3273 }
3274 if (!data) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003275 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
3276 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003277 return -ENODEV;
3278 }
3279 if (len == 0) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003280 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
3281 " to write 0 bytes\n", ch->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003282 return -EINVAL;
3283 }
3284
3285 if (ch->signature != SDIO_AL_SIGNATURE) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003286 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
3287 "signature 0x%x\n", __func__, ch->signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003288 return -ENODEV;
3289 }
3290
3291 sdio_al_dev = ch->sdio_al_dev;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003292 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003293 return -ENODEV;
3294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003295 WARN_ON(len > ch->write_avail);
3296
3297 if (sdio_al_dev->is_err) {
3298 SDIO_AL_ERR(__func__);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003299 ret = -ENODEV;
3300 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301 }
3302
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003303 if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003304 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":writing to "
3305 "closed channel %s\n", ch->name);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003306 ret = -EINVAL;
3307 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003308 }
3309
3310 if (sdio_al_dev->is_ok_to_sleep) {
Maya Erez7b1ebd22011-08-20 20:53:24 +03003311 ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003312 if (ret)
3313 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003314 } else {
3315 restart_inactive_time(sdio_al_dev);
3316 }
3317
Krishna Kondaa7af6062011-09-01 18:34:38 -07003318 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s write %d "
3319 "avail %d.\n", ch->name, len, ch->write_avail);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003320
3321 if (len > ch->write_avail) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003322 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
3323 "write more bytes (%d) than available %d.\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003324 ch->name, len, ch->write_avail);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003325 ret = -ENOMEM;
3326 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003327 }
3328
3329 ret = sdio_ch_write(ch, data, len);
3330 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003331 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_write "
3332 "on channel %s err=%d\n", ch->name, -ret);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003333 goto exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003334 }
3335
3336 ch->total_tx_bytes += len;
Krishna Kondaa7af6062011-09-01 18:34:38 -07003337 DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s write %d "
3338 "avail %d total %d.\n", ch->name, len,
3339 ch->write_avail, ch->total_tx_bytes);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003340
3341 /* Round up to whole buffer size */
3342 len = ROUND_UP(len, ch->peer_tx_buf_size);
3343 /* Protect from wraparound */
3344 len = min(len, (int) ch->write_avail);
3345 ch->write_avail -= len;
3346
3347 if (ch->write_avail < ch->min_write_avail)
3348 ask_reading_mailbox(sdio_al_dev);
3349
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003350exit:
3351 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003352
3353 return ret;
3354}
3355EXPORT_SYMBOL(sdio_write);
3356
3357static int __devinit msm_sdio_al_probe(struct platform_device *pdev)
3358{
3359 if (!sdio_al) {
3360 pr_err(MODULE_NAME ": %s: NULL sdio_al\n", __func__);
3361 return -ENODEV;
3362 }
3363
3364 sdio_al->pdata = pdev->dev.platform_data;
3365 return 0;
3366}
3367
3368static int __devexit msm_sdio_al_remove(struct platform_device *pdev)
3369{
3370 return 0;
3371}
3372
Konstantin Dorfman52890522011-10-05 11:03:19 +02003373static void sdio_al_close_all_channels(struct sdio_al_device *sdio_al_dev)
Maya Erez6862b142011-08-22 09:07:07 +03003374{
Konstantin Dorfman52890522011-10-05 11:03:19 +02003375 int j;
Maya Erez6862b142011-08-22 09:07:07 +03003376 int ret;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003377 struct sdio_channel *ch = NULL;
Maya Erez6862b142011-08-22 09:07:07 +03003378
Konstantin Dorfman52890522011-10-05 11:03:19 +02003379 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
Maya Erez6862b142011-08-22 09:07:07 +03003380
Konstantin Dorfman52890522011-10-05 11:03:19 +02003381 if (!sdio_al_dev) {
3382 sdio_al_loge(sdio_al_dev->dev_log,
3383 MODULE_NAME ": %s: NULL device", __func__);
3384 return;
3385 }
3386 for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
3387 ch = &sdio_al_dev->channel[j];
3388
3389 if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
3390 sdio_al_loge(sdio_al_dev->dev_log,
3391 MODULE_NAME ": %s: Call to sdio_close() for"
3392 " ch %s\n", __func__, ch->name);
3393 ret = channel_close(ch, false);
3394 if (ret) {
3395 sdio_al_loge(sdio_al_dev->dev_log,
3396 MODULE_NAME ": %s: failed sdio_close()"
3397 " for ch %s (%d)\n",
3398 __func__, ch->name, ret);
3399 }
3400 } else {
3401 pr_debug(MODULE_NAME ": %s: skip sdio_close() ch %s"
3402 " (state=%d)\n", __func__,
3403 ch->name, ch->state);
Maya Erez6862b142011-08-22 09:07:07 +03003404 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02003405 }
3406}
3407
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003408static void sdio_al_invalidate_sdio_clients(struct sdio_al_device *sdio_al_dev,
3409 struct platform_device **pdev_arr)
3410{
3411 int j;
3412
3413 pr_debug(MODULE_NAME ": %s: Notifying SDIO clients for card %d",
3414 __func__, sdio_al_dev->host->index);
3415 for (j = 0; j < SDIO_AL_MAX_CHANNELS; ++j) {
3416 if (sdio_al_dev->channel[j].state ==
3417 SDIO_CHANNEL_STATE_INVALID)
3418 continue;
3419 pdev_arr[j] = sdio_al_dev->channel[j].pdev;
3420 sdio_al_dev->channel[j].signature = 0x0;
3421 sdio_al_dev->channel[j].state =
3422 SDIO_CHANNEL_STATE_INVALID;
3423 }
3424}
3425
3426static void sdio_al_modem_reset_operations(struct sdio_al_device
Konstantin Dorfman52890522011-10-05 11:03:19 +02003427 *sdio_al_dev)
3428{
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003429 int ret = 0;
3430 struct sdio_func *func1 = NULL;
3431 struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
3432 int j;
3433
Konstantin Dorfman52890522011-10-05 11:03:19 +02003434 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
3435
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003436 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Konstantin Dorfman52890522011-10-05 11:03:19 +02003437 return;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003438
3439 if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
3440 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: "
3441 "NULL func1 for card %d", __func__,
3442 sdio_al_dev->host->index);
3443 goto exit_err;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003444 }
Maya Erez6862b142011-08-22 09:07:07 +03003445
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003446 if (sdio_al_dev->state == CARD_REMOVED) {
3447 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
3448 "card %d is already removed", __func__,
3449 sdio_al_dev->host->index);
3450 goto exit_err;
3451 }
3452
3453 if (sdio_al_dev->state == MODEM_RESTART) {
3454 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: "
3455 "card %d was already notified for modem reset",
3456 __func__, sdio_al_dev->host->index);
3457 goto exit_err;
3458 }
3459
3460 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: Set the "
3461 "state to MODEM_RESTART for card %d",
3462 __func__, sdio_al_dev->host->index);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003463 sdio_al_dev->state = MODEM_RESTART;
3464 sdio_al_dev->is_ready = false;
Maya Erez6862b142011-08-22 09:07:07 +03003465
Konstantin Dorfman52890522011-10-05 11:03:19 +02003466 /* Stop mailbox timer */
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003467 stop_and_del_timer(sdio_al_dev);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003468
Konstantin Dorfman52890522011-10-05 11:03:19 +02003469 if ((sdio_al_dev->is_ok_to_sleep) &&
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003470 (!sdio_al_dev->is_err)) {
3471 pr_debug(MODULE_NAME ": %s: wakeup modem for "
3472 "card %d", __func__,
3473 sdio_al_dev->host->index);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003474 ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
Maya Erez6862b142011-08-22 09:07:07 +03003475 }
3476
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003477 if (!ret && (!sdio_al_dev->is_err)) {
3478 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
3479 ": %s: sdio_release_irq for card %d",
3480 __func__,
3481 sdio_al_dev->host->index);
3482 func1 = sdio_al_dev->card->sdio_func[0];
3483 sdio_release_irq(sdio_al_dev->card->sdio_func[0]);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003484 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003485
3486 memset(pdev_arr, 0, sizeof(pdev_arr));
3487 sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
3488
3489 sdio_al_release_mutex(sdio_al_dev, __func__);
3490
3491 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
3492 "clients for card %d",
3493 __func__, sdio_al_dev->host->index);
3494 for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
3495 if (!pdev_arr[j])
3496 continue;
3497 platform_device_unregister(pdev_arr[j]);
3498 }
3499 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
3500 "SDIO clients for card %d",
3501 __func__, sdio_al_dev->host->index);
3502
3503 return;
3504
3505exit_err:
3506 sdio_al_release_mutex(sdio_al_dev, __func__);
3507 return;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003508}
3509
3510#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
3511static void sdio_al_reset(void)
3512{
3513 int i;
3514 struct sdio_al_device *sdio_al_dev;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003515
3516 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
3517
Maya Erez6862b142011-08-22 09:07:07 +03003518 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
Maya Erez6862b142011-08-22 09:07:07 +03003519 if (sdio_al->devices[i] == NULL) {
3520 pr_debug(MODULE_NAME ": %s: NULL device in index %d",
Konstantin Dorfman52890522011-10-05 11:03:19 +02003521 __func__, i);
Maya Erez6862b142011-08-22 09:07:07 +03003522 continue;
3523 }
3524 sdio_al_dev = sdio_al->devices[i];
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003525 sdio_al_modem_reset_operations(sdio_al->devices[i]);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003526 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003527
3528 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s completed", __func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003529}
3530#endif
Maya Erez6862b142011-08-22 09:07:07 +03003531
Konstantin Dorfman52890522011-10-05 11:03:19 +02003532static void msm_sdio_al_shutdown(struct platform_device *pdev)
3533{
3534 int i;
Konstantin Dorfman52890522011-10-05 11:03:19 +02003535 struct sdio_al_device *sdio_al_dev;
3536
3537 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME
3538 "Initiating msm_sdio_al_shutdown...");
3539
3540 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
3541 if (sdio_al->devices[i] == NULL) {
3542 pr_debug(MODULE_NAME ": %s: NULL device in index %d",
3543 __func__, i);
3544 continue;
Maya Erez8afd5642011-08-24 15:57:06 +03003545 }
Konstantin Dorfman52890522011-10-05 11:03:19 +02003546 sdio_al_dev = sdio_al->devices[i];
Maya Erez6862b142011-08-22 09:07:07 +03003547
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003548 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
3549 return;
Maya Erez6862b142011-08-22 09:07:07 +03003550
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003551 if (sdio_al_dev->ch_close_supported)
3552 sdio_al_close_all_channels(sdio_al_dev);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003553
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003554 sdio_al_release_mutex(sdio_al_dev, __func__);
Konstantin Dorfman52890522011-10-05 11:03:19 +02003555
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003556 sdio_al_modem_reset_operations(sdio_al_dev);
Maya Erez6862b142011-08-22 09:07:07 +03003557 }
Krishna Kondaa7af6062011-09-01 18:34:38 -07003558 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
3559 "msm_sdio_al_shutdown complete.", __func__);
Maya Erez6862b142011-08-22 09:07:07 +03003560}
3561
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003562static struct platform_driver msm_sdio_al_driver = {
3563 .probe = msm_sdio_al_probe,
3564 .remove = __exit_p(msm_sdio_al_remove),
Maya Erez6862b142011-08-22 09:07:07 +03003565 .shutdown = msm_sdio_al_shutdown,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003566 .driver = {
3567 .name = "msm_sdio_al",
3568 },
3569};
3570
3571/**
3572 * Initialize SDIO_AL channels.
3573 *
3574 */
3575static int init_channels(struct sdio_al_device *sdio_al_dev)
3576{
3577 int ret = 0;
3578 int i;
3579
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003580 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003581 return -ENODEV;
3582
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003583 ret = read_sdioc_software_header(sdio_al_dev,
3584 sdio_al_dev->sdioc_sw_header);
3585 if (ret)
3586 goto exit;
3587
3588 ret = sdio_al_setup(sdio_al_dev);
3589 if (ret)
3590 goto exit;
3591
3592 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
3593 int ch_name_size;
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003594 if (sdio_al_dev->channel[i].state == SDIO_CHANNEL_STATE_INVALID)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003595 continue;
3596 if (sdio_al->unittest_mode) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597 memset(sdio_al_dev->channel[i].ch_test_name, 0,
3598 sizeof(sdio_al_dev->channel[i].ch_test_name));
3599 ch_name_size = strnlen(sdio_al_dev->channel[i].name,
3600 CHANNEL_NAME_SIZE);
3601 strncpy(sdio_al_dev->channel[i].ch_test_name,
3602 sdio_al_dev->channel[i].name,
3603 ch_name_size);
3604 strncat(sdio_al_dev->channel[i].ch_test_name +
3605 ch_name_size,
3606 SDIO_TEST_POSTFIX,
3607 SDIO_TEST_POSTFIX_SIZE);
3608 pr_debug(MODULE_NAME ":pdev.name = %s\n",
3609 sdio_al_dev->channel[i].ch_test_name);
3610 sdio_al_dev->channel[i].pdev = platform_device_alloc(
3611 sdio_al_dev->channel[i].ch_test_name, -1);
3612 } else {
3613 pr_debug(MODULE_NAME ":pdev.name = %s\n",
3614 sdio_al_dev->channel[i].name);
3615 sdio_al_dev->channel[i].pdev = platform_device_alloc(
3616 sdio_al_dev->channel[i].name, -1);
3617 }
3618 if (!sdio_al_dev->channel[i].pdev) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003619 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
3620 ":NULL platform device for ch %s",
3621 sdio_al_dev->channel[i].name);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003622 sdio_al_dev->channel[i].state =
3623 SDIO_CHANNEL_STATE_INVALID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003624 continue;
3625 }
3626 ret = platform_device_add(sdio_al_dev->channel[i].pdev);
3627 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003628 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
3629 ":platform_device_add failed, "
3630 "ret=%d\n", ret);
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03003631 sdio_al_dev->channel[i].state =
3632 SDIO_CHANNEL_STATE_INVALID;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003633 }
3634 }
3635
3636exit:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003637 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003638 return ret;
3639}
3640
3641/**
3642 * Initialize SDIO_AL channels according to the client setup.
3643 * This function also check if the client is in boot mode and
3644 * flashless boot is required to be activated or the client is
3645 * up and running.
3646 *
3647 */
3648static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev)
3649{
3650 int ret = 0;
3651 struct sdio_func *func1;
3652 int signature = 0;
3653
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003654 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003655 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003657 if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
3658 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":NULL card or "
3659 "func1\n");
3660 sdio_al_release_mutex(sdio_al_dev, __func__);
3661 return -ENODEV;
3662 }
3663 func1 = sdio_al_dev->card->sdio_func[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003664
3665 /* Read the header signature to determine the status of the MDM
3666 * SDIO Client
3667 */
3668 signature = sdio_readl(func1, SDIOC_SW_HEADER_ADDR, &ret);
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003669 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003670 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003671 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
3672 "signature from sw header.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003673 return ret;
3674 }
3675
3676 switch (signature) {
3677 case PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE:
3678 if (sdio_al_dev == sdio_al->bootloader_dev) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003679 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":setup "
3680 "bootloader on card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003681 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003682 return sdio_al_bootloader_setup();
3683 } else {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003684 sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":wait "
3685 "for bootloader completion "
3686 "on card %d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003687 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003688 return sdio_al_wait_for_bootloader_comp(sdio_al_dev);
3689 }
3690 case PEER_SDIOC_SW_MAILBOX_SIGNATURE:
3691 case PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE:
3692 return init_channels(sdio_al_dev);
3693 default:
Krishna Kondaa7af6062011-09-01 18:34:38 -07003694 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
3695 "signature 0x%x\n", signature);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003696 return -EINVAL;
3697 }
3698
3699 return 0;
3700}
3701
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003702static void clean_sdio_al_device_data(struct sdio_al_device *sdio_al_dev)
3703{
3704 sdio_al_dev->is_ready = 0;
3705 sdio_al_dev->bootloader_done = 0;
3706 sdio_al_dev->lpm_chan = 0;
3707 sdio_al_dev->is_ok_to_sleep = 0;
3708 sdio_al_dev->inactivity_time = 0;
3709 sdio_al_dev->poll_delay_msec = 0;
3710 sdio_al_dev->is_timer_initialized = 0;
3711 sdio_al_dev->is_err = 0;
3712 sdio_al_dev->is_suspended = 0;
3713 sdio_al_dev->flashless_boot_on = 0;
3714 sdio_al_dev->ch_close_supported = 0;
3715 sdio_al_dev->print_after_interrupt = 0;
3716 memset(sdio_al_dev->sdioc_sw_header, 0,
3717 sizeof(*sdio_al_dev->sdioc_sw_header));
3718 memset(sdio_al_dev->mailbox, 0, sizeof(*sdio_al_dev->mailbox));
3719 memset(sdio_al_dev->rx_flush_buf, 0,
3720 sizeof(*sdio_al_dev->rx_flush_buf));
3721}
3722
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003723/*
3724 * SDIO driver functions
3725 */
3726static int sdio_al_sdio_probe(struct sdio_func *func,
3727 const struct sdio_device_id *sdio_dev_id)
3728{
3729 int ret = 0;
3730 struct sdio_al_device *sdio_al_dev = NULL;
3731 int i;
3732 struct mmc_card *card = NULL;
3733
3734 if (!func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003735 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
3736 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737 return -ENODEV;
3738 }
3739 card = func->card;
3740
3741 if (!card) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003742 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
3743 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003744 return -ENODEV;
3745 }
3746
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003747 if (!card->sdio_func[0]) {
3748 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
3749 "func1\n",
3750 __func__);
3751 return -ENODEV;
3752 }
3753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003754 if (card->sdio_funcs < SDIO_AL_MAX_FUNCS) {
3755 dev_info(&card->dev,
3756 "SDIO-functions# %d less than expected.\n",
3757 card->sdio_funcs);
3758 return -ENODEV;
3759 }
3760
3761 /* Check if there is already a device for this card */
3762 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
3763 if (sdio_al->devices[i] == NULL)
3764 continue;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003765 if (sdio_al->devices[i]->host == card->host) {
3766 sdio_al_dev = sdio_al->devices[i];
3767 if (sdio_al_dev->state == CARD_INSERTED)
3768 return 0;
3769 clean_sdio_al_device_data(sdio_al_dev);
3770 break;
3771 }
3772 }
3773
3774 if (!sdio_al_dev) {
3775 sdio_al_dev = kzalloc(sizeof(struct sdio_al_device),
3776 GFP_KERNEL);
3777 if (sdio_al_dev == NULL)
3778 return -ENOMEM;
3779
3780 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
3781 if (sdio_al->devices[i] == NULL) {
3782 sdio_al->devices[i] = sdio_al_dev;
3783 sdio_al_dev->dev_log = &sdio_al->device_log[i];
3784 spin_lock_init(&sdio_al_dev->dev_log->log_lock);
3785 #ifdef CONFIG_DEBUG_FS
3786 sdio_al_dbgfs_log[i].data =
3787 sdio_al_dev->dev_log->buffer;
3788 sdio_al_dbgfs_log[i].size =
3789 SDIO_AL_DEBUG_LOG_SIZE;
3790 #endif
3791 break;
3792 }
3793 if (i == MAX_NUM_OF_SDIO_DEVICES) {
3794 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":No space "
3795 "in devices array for the device\n");
3796 return -ENOMEM;
3797 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003798 }
3799
3800 dev_info(&card->dev, "SDIO Card claimed.\n");
Maya Erezc7f63282011-10-11 12:15:23 +02003801 sdio_al->skip_print_info = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003803 sdio_al_dev->state = CARD_INSERTED;
3804
3805 if (card->host->index == SDIO_BOOTLOADER_CARD_INDEX)
3806 sdio_al->bootloader_dev = sdio_al_dev;
3807
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003808 sdio_al_dev->is_ready = false;
3809
3810 sdio_al_dev->signature = SDIO_AL_SIGNATURE;
3811
3812 sdio_al_dev->is_suspended = 0;
3813 sdio_al_dev->is_timer_initialized = false;
3814
3815 sdio_al_dev->lpm_chan = INVALID_SDIO_CHAN;
3816
3817 sdio_al_dev->card = card;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003818 sdio_al_dev->host = card->host;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003819
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003820 if (!sdio_al_dev->mailbox) {
3821 sdio_al_dev->mailbox = kzalloc(sizeof(struct sdio_mailbox),
3822 GFP_KERNEL);
3823 if (sdio_al_dev->mailbox == NULL)
3824 return -ENOMEM;
3825 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003826
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003827 if (!sdio_al_dev->sdioc_sw_header) {
3828 sdio_al_dev->sdioc_sw_header
3829 = kzalloc(sizeof(*sdio_al_dev->sdioc_sw_header),
3830 GFP_KERNEL);
3831 if (sdio_al_dev->sdioc_sw_header == NULL)
3832 return -ENOMEM;
3833 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003834
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003835 if (!sdio_al_dev->rx_flush_buf) {
3836 sdio_al_dev->rx_flush_buf = kzalloc(RX_FLUSH_BUFFER_SIZE,
3837 GFP_KERNEL);
3838 if (sdio_al_dev->rx_flush_buf == NULL) {
3839 sdio_al_loge(&sdio_al->gen_log,
3840 MODULE_NAME ":Fail to allocate "
3841 "rx_flush_buf for card %d\n",
3842 card->host->index);
3843 return -ENOMEM;
3844 }
Maya Erez5795e0d2011-09-12 20:20:06 +03003845 }
3846
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003847 sdio_al_dev->timer.data = (unsigned long)sdio_al_dev;
3848
3849 wake_lock_init(&sdio_al_dev->wake_lock, WAKE_LOCK_SUSPEND, MODULE_NAME);
3850 /* Don't allow sleep until all required clients register */
3851 sdio_al_vote_for_sleep(sdio_al_dev, 0);
3852
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003853 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
3854 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003855
3856 /* Init Func#1 */
Yaniv Gardi9a952d92011-09-06 13:46:30 +03003857 ret = sdio_al_enable_func_retry(card->sdio_func[0], "Init Func#1");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003858 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003859 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
3860 "enable Func#%d\n", card->sdio_func[0]->num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003861 goto exit;
3862 }
3863
3864 /* Patch Func CIS tuple issue */
3865 ret = sdio_set_block_size(card->sdio_func[0], SDIO_AL_BLOCK_SIZE);
3866 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003867 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to set "
3868 "block size, Func#%d\n", card->sdio_func[0]->num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003869 goto exit;
3870 }
3871 sdio_al_dev->card->sdio_func[0]->max_blksize = SDIO_AL_BLOCK_SIZE;
3872
3873 sdio_al_dev->workqueue = create_singlethread_workqueue("sdio_al_wq");
3874 sdio_al_dev->sdio_al_work.sdio_al_dev = sdio_al_dev;
3875 init_waitqueue_head(&sdio_al_dev->wait_mbox);
3876
3877 ret = sdio_al_client_setup(sdio_al_dev);
3878
3879exit:
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003880 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003881 return ret;
3882}
3883
3884static void sdio_al_sdio_remove(struct sdio_func *func)
3885{
3886 struct sdio_al_device *sdio_al_dev = NULL;
3887 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003888 struct mmc_card *card = NULL;
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003889 struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003890
3891 if (!func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003892 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
3893 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003894 return;
3895 }
3896 card = func->card;
3897
3898 if (!card) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003899 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
3900 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003901 return;
3902 }
3903
3904 /* Find the sdio_al_device of this card */
3905 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
3906 if (sdio_al->devices[i] == NULL)
3907 continue;
3908 if (sdio_al->devices[i]->card == card) {
3909 sdio_al_dev = sdio_al->devices[i];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003910 break;
3911 }
3912 }
3913 if (sdio_al_dev == NULL) {
3914 pr_debug(MODULE_NAME ":%s :NULL sdio_al_dev for card %d\n",
3915 __func__, card->host->index);
3916 return;
3917 }
3918
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003919 if (sdio_al_claim_mutex(sdio_al_dev, __func__))
3920 return;
3921
3922 if (sdio_al_dev->state == CARD_REMOVED) {
3923 sdio_al_release_mutex(sdio_al_dev, __func__);
3924 return;
3925 }
3926
3927 if (!card->sdio_func[0]) {
3928 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
3929 "func1\n", __func__);
3930 sdio_al_release_mutex(sdio_al_dev, __func__);
3931 return;
3932 }
3933
Krishna Kondaa7af6062011-09-01 18:34:38 -07003934 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s for card %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003935 __func__, card->host->index);
3936
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003937 sdio_al_dev->state = CARD_REMOVED;
3938
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003939 memset(pdev_arr, 0, sizeof(pdev_arr));
3940 sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003941
Krishna Kondaa7af6062011-09-01 18:34:38 -07003942 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: ask_reading_mailbox "
3943 "for card %d\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003944 sdio_al_dev->is_ready = false; /* Flag worker to exit */
3945 sdio_al_dev->ask_mbox = false;
3946 ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
3947
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003948 stop_and_del_timer(sdio_al_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003949
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003950 sdio_al_release_mutex(sdio_al_dev, __func__);
3951
3952 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
3953 "clients for card %d",
3954 __func__, sdio_al_dev->host->index);
3955 for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
3956 if (!pdev_arr[i])
3957 continue;
3958 platform_device_unregister(pdev_arr[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003959 }
Maya Erez0fdb5ad2011-10-09 19:16:27 +02003960 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
3961 "SDIO clients for card %d",
3962 __func__, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003963
Krishna Kondaa7af6062011-09-01 18:34:38 -07003964 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: vote for sleep for "
3965 "card %d\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003966 sdio_al_vote_for_sleep(sdio_al_dev, 1);
3967
Krishna Kondaa7af6062011-09-01 18:34:38 -07003968 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: flush_workqueue for "
3969 "card %d\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003970 flush_workqueue(sdio_al_dev->workqueue);
3971 destroy_workqueue(sdio_al_dev->workqueue);
3972 wake_lock_destroy(&sdio_al_dev->wake_lock);
3973
Krishna Kondaa7af6062011-09-01 18:34:38 -07003974 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: sdio card %d removed."
3975 "\n", __func__, card->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003976}
3977
3978static void sdio_print_mailbox(char *prefix_str, struct sdio_mailbox *mailbox)
3979{
3980 int k = 0;
3981 char buf[256];
3982 char buf1[10];
3983
3984 if (!mailbox) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07003985 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": mailbox is "
3986 "NULL\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003987 return;
3988 }
3989
Krishna Kondaa7af6062011-09-01 18:34:38 -07003990 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: pipes 0_7: eot=0x%x,"
3991 " thresh=0x%x, overflow=0x%x, "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003992 "underflow=0x%x, mask_thresh=0x%x\n",
3993 prefix_str, mailbox->eot_pipe_0_7,
3994 mailbox->thresh_above_limit_pipe_0_7,
3995 mailbox->overflow_pipe_0_7,
3996 mailbox->underflow_pipe_0_7,
3997 mailbox->mask_thresh_above_limit_pipe_0_7);
3998
3999 memset(buf, 0, sizeof(buf));
4000 strncat(buf, ": bytes_avail:", sizeof(buf));
4001
4002 for (k = 0 ; k < SDIO_AL_ACTIVE_PIPES ; ++k) {
4003 snprintf(buf1, sizeof(buf1), "%d, ",
4004 mailbox->pipe_bytes_avail[k]);
4005 strncat(buf, buf1, sizeof(buf));
4006 }
4007
Krishna Kondaa7af6062011-09-01 18:34:38 -07004008 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME "%s", buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004009}
4010
4011static void sdio_al_print_info(void)
4012{
4013 int i = 0;
4014 int j = 0;
4015 int ret = 0;
4016 struct sdio_mailbox *mailbox = NULL;
4017 struct sdio_mailbox *hw_mailbox = NULL;
4018 struct peer_sdioc_channel_config *ch_config = NULL;
4019 struct sdio_func *func1 = NULL;
4020 struct sdio_func *lpm_func = NULL;
4021 int offset = 0;
4022 int is_ok_to_sleep = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004023 char buf[50];
4024
Maya Erezc7f63282011-10-11 12:15:23 +02004025 if (sdio_al->skip_print_info == 1)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004026 return;
4027
Maya Erezc7f63282011-10-11 12:15:23 +02004028 sdio_al->skip_print_info = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004029
Krishna Kondaa7af6062011-09-01 18:34:38 -07004030 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - SDIO DEBUG INFO\n",
4031 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004032
4033 if (!sdio_al) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004034 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - ERROR - "
4035 "sdio_al is NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004036 return;
4037 }
4038
Krishna Kondaa7af6062011-09-01 18:34:38 -07004039 sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": GPIO mdm2ap_status=%d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040 sdio_al->pdata->get_mdm2ap_status());
4041
4042 for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
4043 struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
4044
4045 if (sdio_al_dev == NULL) {
4046 continue;
4047 }
4048
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004049 if (!sdio_al_dev->host) {
4050 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Host"
4051 " is NULL\n);");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004052 continue;
4053 }
4054
4055 snprintf(buf, sizeof(buf), "Card#%d: Shadow HW MB",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004056 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057
4058 /* printing Shadowing HW Mailbox*/
4059 mailbox = sdio_al_dev->mailbox;
4060 sdio_print_mailbox(buf, mailbox);
4061
Krishna Kondaa7af6062011-09-01 18:34:38 -07004062 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063 "is_ok_to_sleep=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004064 sdio_al_dev->host->index,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 sdio_al_dev->is_ok_to_sleep);
4066
4067
Krishna Kondaa7af6062011-09-01 18:34:38 -07004068 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004069 "Shadow channels SW MB:",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004070 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004071
4072 /* printing Shadowing SW Mailbox per channel*/
4073 for (i = 0 ; i < SDIO_AL_MAX_CHANNELS ; ++i) {
4074 struct sdio_channel *ch = &sdio_al_dev->channel[i];
4075
4076 if (ch == NULL) {
4077 continue;
4078 }
4079
Konstantin Dorfmanee2e3082011-08-16 15:12:01 +03004080 if (ch->state == SDIO_CHANNEL_STATE_INVALID)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004081 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082
4083 ch_config = &sdio_al_dev->channel[i].ch_config;
4084
Krishna Kondaa7af6062011-09-01 18:34:38 -07004085 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4086 ": Ch %s: max_rx_thres=0x%x, "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004087 "max_tx_thres=0x%x, tx_buf=0x%x, "
4088 "is_packet_mode=%d, "
4089 "max_packet=0x%x, min_write=0x%x",
4090 ch->name, ch_config->max_rx_threshold,
4091 ch_config->max_tx_threshold,
4092 ch_config->tx_buf_size,
4093 ch_config->is_packet_mode,
4094 ch_config->max_packet_size,
4095 ch->min_write_avail);
4096
Krishna Kondaa7af6062011-09-01 18:34:38 -07004097 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4098 ": total_rx=0x%x, total_tx=0x%x, "
4099 "read_avail=0x%x, write_avail=0x%x, "
4100 "rx_pending=0x%x, num_reads=0x%x, "
4101 "num_notifs=0x%x", ch->total_rx_bytes,
4102 ch->total_tx_bytes, ch->read_avail,
4103 ch->write_avail, ch->rx_pending_bytes,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004104 ch->statistics.total_read_times,
4105 ch->statistics.total_notifs);
4106 } /* end loop over all channels */
4107
4108 } /* end loop over all devices */
4109
4110 /* reading from client and printing is_host_ok_to_sleep per device */
4111 for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
4112 struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
4113
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004114 if (sdio_al_verify_func1(sdio_al_dev, __func__))
4115 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004116
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004117 if (!sdio_al_dev->host) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004118 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4119 ": Host is NULL");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004120 continue;
4121 }
4122
4123 if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004124 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4125 ": %s - for Card#%d, is lpm_chan=="
4126 "INVALID_SDIO_CHAN. continuing...",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004127 __func__, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004128 continue;
4129 }
4130
4131 offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
4132 sizeof(struct peer_sdioc_channel_config) *
4133 sdio_al_dev->lpm_chan+
4134 offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
4135
4136 lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->
4137 lpm_chan+1];
4138 if (!lpm_func) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004139 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4140 ": %s - lpm_func is NULL for card#%d"
4141 " continuing...\n", __func__,
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004142 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004143 continue;
4144 }
4145
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004146 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
4147 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004148 ret = sdio_memcpy_fromio(lpm_func,
4149 &is_ok_to_sleep,
4150 SDIOC_SW_MAILBOX_ADDR+offset,
4151 sizeof(int));
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004152 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004153
4154 if (ret)
Krishna Kondaa7af6062011-09-01 18:34:38 -07004155 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4156 ": %s - fail to read "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004157 "is_HOST_ok_to_sleep from mailbox for card %d",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004158 __func__, sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004159 else
Krishna Kondaa7af6062011-09-01 18:34:38 -07004160 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4161 ": Card#%d: "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004162 "is_HOST_ok_to_sleep=%d\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004163 sdio_al_dev->host->index,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004164 is_ok_to_sleep);
4165 }
4166
4167 for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
4168 struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
4169
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004170 if (!sdio_al_dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004171 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004172
4173 /* Reading HW Mailbox */
4174 hw_mailbox = sdio_al_dev->mailbox;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004175
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004176 if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
4177 return;
4178
4179 if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
4180 sdio_al_release_mutex(sdio_al_dev, __func__);
4181 return;
4182 }
4183 func1 = sdio_al_dev->card->sdio_func[0];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184 ret = sdio_memcpy_fromio(func1, hw_mailbox,
4185 HW_MAILBOX_ADDR, sizeof(*hw_mailbox));
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004186 sdio_al_release_mutex(sdio_al_dev, __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004187
4188 if (ret) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004189 sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
4190 ": fail to read "
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004191 "mailbox for card#%d. "
4192 "continuing...\n",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004193 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004194 continue;
4195 }
4196
4197 snprintf(buf, sizeof(buf), "Card#%d: Current HW MB",
Maya Erez0fdb5ad2011-10-09 19:16:27 +02004198 sdio_al_dev->host->index);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004199
4200 /* Printing HW Mailbox */
4201 sdio_print_mailbox(buf, hw_mailbox);
4202 }
4203}
4204
4205static struct sdio_device_id sdio_al_sdioid[] = {
4206 {.class = 0, .vendor = 0x70, .device = 0x2460},
4207 {.class = 0, .vendor = 0x70, .device = 0x0460},
4208 {.class = 0, .vendor = 0x70, .device = 0x23F1},
4209 {.class = 0, .vendor = 0x70, .device = 0x23F0},
4210 {}
4211};
4212
4213static struct sdio_driver sdio_al_sdiofn_driver = {
4214 .name = "sdio_al_sdiofn",
4215 .id_table = sdio_al_sdioid,
4216 .probe = sdio_al_sdio_probe,
4217 .remove = sdio_al_sdio_remove,
4218};
4219
4220#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
4221/*
4222 * Callback for notifications from restart mudule.
4223 * This function handles only the BEFORE_RESTART notification.
4224 * Stop all the activity on the card and notify our clients.
4225 */
4226static int sdio_al_subsys_notifier_cb(struct notifier_block *this,
4227 unsigned long notif_type,
4228 void *data)
4229{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004230 if (notif_type != SUBSYS_BEFORE_SHUTDOWN) {
Krishna Kondaa7af6062011-09-01 18:34:38 -07004231 sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: got "
4232 "notification %ld", __func__, notif_type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004233 return NOTIFY_DONE;
4234 }
4235
Konstantin Dorfman52890522011-10-05 11:03:19 +02004236 sdio_al_reset();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004237 return NOTIFY_OK;
4238}
4239
4240static struct notifier_block sdio_al_nb = {
4241 .notifier_call = sdio_al_subsys_notifier_cb,
4242};
4243#endif
4244
4245/**
4246 * Module Init.
4247 *
4248 * @warn: allocate sdio_al context before registering driver.
4249 *
4250 */
4251static int __init sdio_al_init(void)
4252{
4253 int ret = 0;
4254 int i;
4255
4256 pr_debug(MODULE_NAME ":sdio_al_init\n");
4257
4258 pr_info(MODULE_NAME ":SDIO-AL SW version %s\n",
4259 DRV_VERSION);
4260
4261 sdio_al = kzalloc(sizeof(struct sdio_al), GFP_KERNEL);
4262 if (sdio_al == NULL)
4263 return -ENOMEM;
4264
4265 for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
4266 sdio_al->devices[i] = NULL;
4267
4268 sdio_al->unittest_mode = false;
4269
4270 sdio_al->debug.debug_lpm_on = debug_lpm_on;
4271 sdio_al->debug.debug_data_on = debug_data_on;
Maya Erez7ad06d82011-10-02 15:47:57 +02004272 sdio_al->debug.debug_close_on = debug_close_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004273
4274#ifdef CONFIG_DEBUG_FS
4275 sdio_al_debugfs_init();
4276#endif
4277
4278
4279#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
4280 sdio_al->subsys_notif_handle = subsys_notif_register_notifier(
4281 "external_modem", &sdio_al_nb);
4282#endif
4283
4284 ret = platform_driver_register(&msm_sdio_al_driver);
4285 if (ret) {
4286 pr_err(MODULE_NAME ": platform_driver_register failed: %d\n",
4287 ret);
4288 goto exit;
4289 }
4290
4291 sdio_register_driver(&sdio_al_sdiofn_driver);
Krishna Kondaa7af6062011-09-01 18:34:38 -07004292
4293 spin_lock_init(&sdio_al->gen_log.log_lock);
4294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004295exit:
4296 if (ret)
4297 kfree(sdio_al);
4298 return ret;
4299}
4300
4301/**
4302 * Module Exit.
4303 *
4304 * Free allocated memory.
4305 * Disable SDIO-Card.
4306 * Unregister driver.
4307 *
4308 */
4309static void __exit sdio_al_exit(void)
4310{
4311 if (sdio_al == NULL)
4312 return;
4313
4314 pr_debug(MODULE_NAME ":sdio_al_exit\n");
4315
4316#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
4317 subsys_notif_unregister_notifier(
4318 sdio_al->subsys_notif_handle, &sdio_al_nb);
4319#endif
4320
4321 sdio_al_tear_down();
4322
4323 sdio_unregister_driver(&sdio_al_sdiofn_driver);
4324
4325 kfree(sdio_al);
4326
4327#ifdef CONFIG_DEBUG_FS
4328 sdio_al_debugfs_cleanup();
4329#endif
4330
4331 platform_driver_unregister(&msm_sdio_al_driver);
4332
4333 pr_debug(MODULE_NAME ":sdio_al_exit complete\n");
4334}
4335
4336module_init(sdio_al_init);
4337module_exit(sdio_al_exit);
4338
4339MODULE_LICENSE("GPL v2");
4340MODULE_DESCRIPTION("SDIO Abstraction Layer");
4341MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
4342MODULE_VERSION(DRV_VERSION);
4343