Merge remote-tracking branch 'codeaurora/kk_2.7_rb1.30' into cm-11.0
Conflicts:
arch/arm/mach-msm/acpuclock-krait.c
drivers/media/video/msm/actuators/msm_actuator.c
drivers/media/video/msm/flash.c
drivers/media/video/msm/msm_camera.c
drivers/media/video/msm/server/msm_cam_server.c
drivers/media/video/msm/vfe/msm_vfe32.c
drivers/uio/uio.c
drivers/video/au1100fb.c
drivers/video/au1200fb.c
include/media/msm_isp.h
include/media/radio-iris.h
net/ipv4/ping.c
Change-Id: Ic027f55c9667ecccaa35ee4a96ad77dbb1e8708f
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 4ba55de..4084a90 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -186,3 +186,5 @@
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
CONFIG_CRC_CCITT=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/full_msm8960-perf_defconfig b/arch/arm/configs/full_msm8960-perf_defconfig
index 2b3fbd8..6011039 100644
--- a/arch/arm/configs/full_msm8960-perf_defconfig
+++ b/arch/arm/configs/full_msm8960-perf_defconfig
@@ -512,3 +512,5 @@
CONFIG_PRIMA_WLAN_BTAMP=y
CONFIG_PRIMA_WLAN_LFR=y
CONFIG_PRIMA_WLAN_OKC=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index a8abb30..9736680 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -346,3 +346,5 @@
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRC_CCITT=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 1bf888b..da883dc 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -379,3 +379,5 @@
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 8c1b6a7..2d9d0fe 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -450,3 +450,5 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 61f28a7..0c2b7bb 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -266,6 +266,7 @@
CONFIG_BT_HCIUART_ATH3K=y
CONFIG_MSM_BT_POWER=y
CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
# CONFIG_CFG80211_WEXT is not set
CONFIG_RFKILL=y
CONFIG_GENLOCK=y
@@ -549,3 +550,5 @@
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_DEVMEM=n
+CONFIG_DEVKMEM=n
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 2eb0c2c..7013a5c 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -148,6 +148,7 @@
#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
#define TIF_SYSCALL_TRACE 8
#define TIF_SYSCALL_AUDIT 9
+#define TIF_SYSCALL_RESTARTSYS 10
#define TIF_POLLING_NRFLAG 16
#define TIF_USING_IWMMXT 17
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
@@ -163,9 +164,11 @@
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
+#define _TIF_SYSCALL_RESTARTSYS (1 << TIF_SYSCALL_RESTARTSYS)
/* Checks for any syscall work in entry-common.S */
-#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
+#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
+ _TIF_SYSCALL_RESTARTSYS)
/*
* Change these and you break ASM code in entry-common.S
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index c6c6be7..6533c4b 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -24,6 +24,7 @@
#include <linux/hw_breakpoint.h>
#include <linux/regset.h>
#include <linux/audit.h>
+#include <linux/unistd.h>
#include <asm/pgtable.h>
#include <asm/traps.h>
@@ -916,6 +917,8 @@
audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
+ if (why == 0 && test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS))
+ scno = __NR_restart_syscall - __NR_SYSCALL_BASE;
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return scno;
if (!(current->ptrace & PT_PTRACED))
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index d96ac36..09b37d1 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -649,12 +649,10 @@
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
+ case -ERESTART_RESTARTBLOCK:
regs->ARM_r0 = regs->ARM_ORIG_r0;
regs->ARM_pc = restart_addr;
break;
- case -ERESTART_RESTARTBLOCK:
- regs->ARM_r0 = -EINTR;
- break;
}
}
@@ -675,12 +673,14 @@
* debugger has chosen to restart at a different PC.
*/
if (regs->ARM_pc == restart_addr) {
- if (retval == -ERESTARTNOHAND
+ if (retval == -ERESTARTNOHAND ||
+ retval == -ERESTART_RESTARTBLOCK
|| (retval == -ERESTARTSYS
&& !(ka.sa.sa_flags & SA_RESTART))) {
regs->ARM_r0 = -EINTR;
regs->ARM_pc = continue_addr;
}
+ clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
}
if (test_thread_flag(TIF_RESTORE_SIGMASK))
@@ -708,38 +708,15 @@
* ignore the restart.
*/
if (retval == -ERESTART_RESTARTBLOCK
- && regs->ARM_pc == continue_addr) {
- if (thumb_mode(regs)) {
- regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
- regs->ARM_pc -= 2;
- } else {
-#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
- regs->ARM_r7 = __NR_restart_syscall;
- regs->ARM_pc -= 4;
-#else
- u32 __user *usp;
-
- regs->ARM_sp -= 4;
- usp = (u32 __user *)regs->ARM_sp;
-
- if (put_user(regs->ARM_pc, usp) == 0) {
- regs->ARM_pc = KERN_RESTART_CODE;
- } else {
- regs->ARM_sp += 4;
- force_sigsegv(0, current);
- }
-#endif
- }
- }
-
- /* If there's no signal to deliver, we just put the saved sigmask
- * back.
- */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
- }
+ && regs->ARM_pc == restart_addr)
+ set_thread_flag(TIF_SYSCALL_RESTARTSYS);
}
+
+ /* If there's no signal to deliver, we just put the saved sigmask
+ * back.
+ */
+ if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+ set_current_blocked(¤t->saved_sigmask);
}
asmlinkage void
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index a5c7097..d45d269 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1315,20 +1315,6 @@
Enables the PCIe functionality by configures PCIe core on
MSM chipset and by enabling the ARM PCI framework extension.
-config MSM_RPC_SDIO_XPRT
- depends on MSM_SDIO_AL
- default y
- bool "MSM SDIO XPRT Layer"
- help
- SDIO Transport Layer for RPC Rouer
-
-config MSM_RPC_SDIO_DEBUG
- depends on MSM_RPC_SDIO_XPRT
- default y
- bool "MSM SDIO XPRT debug support"
- help
- Support for debugging SDIO XPRT
-
config MSM_SMD_DEBUG
depends on MSM_SMD
default y
@@ -1337,21 +1323,6 @@
Support for debugging the SMD for communication
between the ARM9 and ARM11
-config MSM_SDIO_AL
- depends on ((ARCH_MSM7X30 || MACH_MSM8X60_FUSN_FFA || MACH_TYPE_MSM8X60_FUSION) && HAS_WAKELOCK)
- default y
- tristate "SDIO-Abstraction-Layer"
- help
- Support MSM<->MDM Communication over SDIO bus.
- MDM SDIO-Client should have pipes support.
-
-config MSM_SDIO_DMUX
- bool "SDIO Data Mux Driver"
- depends on MSM_SDIO_AL
- default n
- help
- Support Muxed Data Channels over SDIO interface.
-
config MSM_BAM_DMUX
bool "BAM Data Mux Driver"
depends on SPS
@@ -1411,16 +1382,6 @@
If in doubt, say yes.
-config MSM_SDIO_TTY
- bool "SDIO TTY Driver"
- depends on MSM_SDIO_AL
- default n
- help
- Provides a TTY driver SDIO TTY
- This driver can be used by user space
- applications for passing data through the
- SDIO interface.
-
config MSM_HSIC_TTY
bool "HSIC TTY Driver"
default n
@@ -1457,13 +1418,6 @@
If in doubt, say yes.
-config MSM_SDIO_CMUX
- bool "SDIO CMUX Driver"
- depends on MSM_SDIO_AL
- default n
- help
- Provides a Muxed port interface over SDIO QMI
-
config MSM_DSPS
bool "Sensors DSPS driver"
depends on (MSM_PIL && (ARCH_MSM8X60 || ARCH_MSM8960))
@@ -1476,13 +1430,6 @@
The number of clocks and their name may vary between targets.
It also triggers the PIL to load the DSPS firmware.
-config MSM_SDIO_CTL
- bool "SDIO CTL Driver"
- depends on MSM_SDIO_CMUX
- default n
- help
- Provides a binary SDIO control port interface.
-
config MSM_ONCRPCROUTER
depends on MSM_SMD
default n
@@ -1610,15 +1557,6 @@
Collects performance statistics and shows this information
through a debugfs file rmt_storage_stats.
-config MSM_SDIO_SMEM
- depends on MSM_SDIO_AL
- default n
- bool "SDIO SMEM for remote storage"
- help
- Copies data from remote MDM9K memory to local MSM8x60
- memory. Used by remote storage client to shadow
- MDM9K filesystem.
-
config MSM_DALRPC
bool "DAL RPC support"
default n
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index a7eecf8..9a8b84e 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -89,10 +89,6 @@
obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o
-obj-$(CONFIG_MSM_SDIO_AL) += sdio_al.o
-obj-$(CONFIG_MSM_SDIO_AL) += sdio_al_test.o
-obj-$(CONFIG_MSM_SDIO_AL) += sdio_al_dloader.o
-obj-$(CONFIG_MSM_SDIO_DMUX) += sdio_dmux.o
obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o
obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o
obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging.o
@@ -126,13 +122,10 @@
endif
obj-$(CONFIG_MSM_HSIC_TTY) += hsic_tty.o
-obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
obj-$(CONFIG_MSM_SMD_PKT) += smd_pkt.o
-obj-$(CONFIG_MSM_SDIO_CMUX) += sdio_cmux.o
obj-$(CONFIG_MSM_DSPS) += msm_dsps.o
-obj-$(CONFIG_MSM_SDIO_CTL) += sdio_ctl.o
obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o
obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o
obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
@@ -147,7 +140,6 @@
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_xdr.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += rpcrouter_smd_xprt.o
-obj-$(CONFIG_MSM_RPC_SDIO_XPRT) += rpcrouter_sdio_xprt.o
obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o
obj-$(CONFIG_MSM_RPC_PROC_COMM_TEST) += proc_comm_test.o
obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o ping_apps_server.o
@@ -319,7 +311,6 @@
obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o
obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o
-obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o
obj-$(CONFIG_MSM_RPM) += rpm.o
ifdef CONFIG_MSM_RPM
obj-$(CONFIG_ARCH_APQ8064) += rpm_resources.o
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index e3a3f54..d22ab41 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -924,7 +924,7 @@
int i;
/* Construct the freq_table tables from acpu_freq_tbl. */
for (i = 0, freq_cnt = 0; drv.acpu_freq_tbl[i].speed.khz != 0
- && freq_cnt < ARRAY_SIZE(*freq_table); i++) {
+ && freq_cnt < ARRAY_SIZE(*freq_table)-1; i++) {
if (drv.acpu_freq_tbl[i].use_for_scaling) {
freq_table[cpu][freq_cnt].index = freq_cnt;
freq_table[cpu][freq_cnt].frequency
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 991ccef..ea1f65d 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -215,9 +215,10 @@
static void bam_mux_write_done(struct work_struct *work);
static void handle_bam_mux_cmd(struct work_struct *work);
static void rx_timer_work_func(struct work_struct *work);
+static void queue_rx_work_func(struct work_struct *work);
static DECLARE_WORK(rx_timer_work, rx_timer_work_func);
-static struct delayed_work queue_rx_work;
+static DECLARE_WORK(queue_rx_work, queue_rx_work_func);
static struct workqueue_struct *bam_mux_rx_workqueue;
static struct workqueue_struct *bam_mux_tx_workqueue;
@@ -384,7 +385,7 @@
spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
}
-static void queue_rx(void)
+static void __queue_rx(gfp_t alloc_flags)
{
void *ptr;
struct rx_pkt_info *info;
@@ -399,23 +400,23 @@
if (in_global_reset)
goto fail;
- info = kmalloc(sizeof(struct rx_pkt_info),
- GFP_NOWAIT | __GFP_NOWARN);
+ info = kmalloc(sizeof(struct rx_pkt_info), alloc_flags);
if (!info) {
DMUX_LOG_KERR(
- "%s: unable to alloc rx_pkt_info, will retry later\n",
- __func__);
+ "%s: unable to alloc rx_pkt_info w/ flags %x, will retry later\n",
+ __func__,
+ alloc_flags);
goto fail;
}
INIT_WORK(&info->work, handle_bam_mux_cmd);
- info->skb = __dev_alloc_skb(BUFFER_SIZE,
- GFP_NOWAIT | __GFP_NOWARN);
+ info->skb = __dev_alloc_skb(BUFFER_SIZE, alloc_flags);
if (info->skb == NULL) {
DMUX_LOG_KERR(
- "%s: unable to alloc skb, will retry later\n",
- __func__);
+ "%s: unable to alloc skb w/ flags %x, will retry later\n",
+ __func__,
+ alloc_flags);
goto fail_info;
}
ptr = skb_put(info->skb, BUFFER_SIZE);
@@ -457,15 +458,30 @@
kfree(info);
fail:
- if (rx_len_cached == 0 && !in_global_reset) {
+ if (!in_global_reset) {
DMUX_LOG_KERR("%s: rescheduling\n", __func__);
- schedule_delayed_work(&queue_rx_work, msecs_to_jiffies(100));
+ schedule_work(&queue_rx_work);
}
}
+static void queue_rx(void)
+{
+ /*
+ * Hot path. Delays waiting for the allocation to find memory if its
+ * not immediately available, and delays from logging allocation
+ * failures which cannot be tolerated at this time.
+ */
+ __queue_rx(GFP_NOWAIT | __GFP_NOWARN);
+}
+
static void queue_rx_work_func(struct work_struct *work)
{
- queue_rx();
+ /*
+ * Cold path. Delays can be tolerated. Use of GFP_KERNEL should
+ * guarentee the requested memory will be found, after some ammount of
+ * delay.
+ */
+ __queue_rx(GFP_KERNEL);
}
static void bam_mux_process_data(struct sk_buff *rx_skb)
@@ -1843,8 +1859,6 @@
bam_ops->sps_disconnect_ptr(bam_rx_pipe);
__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
- BAM_DMUX_LOG("%s: device reset\n", __func__);
- sps_device_reset(a2_device_handle);
} else {
ssr_skipped_disconnect = 1;
}
@@ -2477,7 +2491,6 @@
init_completion(&shutdown_completion);
complete_all(&shutdown_completion);
INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
- INIT_DELAYED_WORK(&queue_rx_work, queue_rx_work_func);
wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
init_srcu_struct(&bam_dmux_srcu);
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index cdcc2cd..b07e2fd 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -346,6 +346,7 @@
ARRAY_SIZE(sdc1_sup_clk_rates_all);
}
apq8064_add_sdcc(1, apq8064_sdc1_pdata);
+ apq8064_add_uio();
}
if (apq8064_sdc2_pdata)
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 256fac9..cab700d 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -78,6 +78,7 @@
struct mmc_platform_data;
int __init apq8064_add_sdcc(unsigned int controller,
struct mmc_platform_data *plat);
+int __init apq8064_add_uio(void);
void apq8064_init_mmc(void);
void apq8064_init_gpiomux(void);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 9d5acf7..8141869 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -1894,6 +1894,30 @@
return platform_device_register(pdev);
}
+#define MSM_UIO_RMTFS_BASE 0x8FF00000
+#define MSM_UIO_RMTFS_END (MSM_UIO_RMTFS_BASE + 0x40000)
+
+static struct resource msm_device_uio_rmtfs_rsc[] = {
+ {
+ .name = "rmtfs",
+ .flags = IORESOURCE_MEM,
+ .start = MSM_UIO_RMTFS_BASE,
+ .end = MSM_UIO_RMTFS_END - 1,
+ },
+};
+
+struct platform_device apq8064_device_uio_rmtfs = {
+ .name = "msm_sharedmem",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm_device_uio_rmtfs_rsc),
+ .resource = msm_device_uio_rmtfs_rsc,
+};
+
+int __init apq8064_add_uio()
+{
+ return platform_device_register(&apq8064_device_uio_rmtfs);
+}
+
static struct resource resources_sps[] = {
{
.name = "pipe_mem",
diff --git a/arch/arm/mach-msm/dfe-fsm9xxx.c b/arch/arm/mach-msm/dfe-fsm9xxx.c
index 66272d2..3470710 100644
--- a/arch/arm/mach-msm/dfe-fsm9xxx.c
+++ b/arch/arm/mach-msm/dfe-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -50,6 +50,8 @@
HH_IRQ_FIFO_SIZE) == \
(pdev)->irq_fifo_head)
+#define UINT32_MAX (0xFFFFFFFFU)
+
static struct hh_dev_node_info {
spinlock_t hh_lock;
char irq_fifo[HH_IRQ_FIFO_SIZE];
@@ -220,8 +222,9 @@
return -EFAULT;
if (!HH_OFFSET_VALID(param.offset))
return -EINVAL;
- if (param.num == 0)
- break;
+ if ((param.num == 0) ||
+ (param.num >= (UINT32_MAX / sizeof(unsigned int))))
+ return -EINVAL;
req_sz = sizeof(unsigned int) * param.num;
if (pdfi->array_num < param.num) {
@@ -270,8 +273,10 @@
if (copy_from_user(¶m, argp, sizeof param))
return -EFAULT;
- if (param.num == 0)
- break;
+ if ((param.num == 0) ||
+ (param.num >= (UINT32_MAX /
+ sizeof(struct dfe_command_entry))))
+ return -EINVAL;
req_sz = sizeof(struct dfe_command_entry) * param.num;
if (pdfi->cmd_num < param.num) {
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 9b34155..9af8a7e 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -434,7 +434,7 @@
unsigned int len)
{
struct sk_buff *temp;
- int offset = 0, buf_len = 0, copy_len;
+ unsigned int offset = 0, buf_len = 0, copy_len;
void *buf;
if (!skb_head) {
diff --git a/arch/arm/mach-msm/msm-buspm-dev.h b/arch/arm/mach-msm/msm-buspm-dev.h
index 5754771..1a24b66 100644
--- a/arch/arm/mach-msm/msm-buspm-dev.h
+++ b/arch/arm/mach-msm/msm-buspm-dev.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011,2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -23,7 +23,7 @@
/* Read/write data into kernel buffer */
struct buspm_xfer_req {
- int size; /* Size of this request, in bytes */
+ unsigned int size; /* Size of this request, in bytes */
void *data; /* Data buffer to transfer data to/from */
};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_config.c b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
index c6fa250..d51aa9b 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_config.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
@@ -36,6 +36,10 @@
struct msm_bus_fabric_device *fabdev;
priv_id = msm_bus_board_get_iid(master_port);
+ if (priv_id == -ENXIO) {
+ MSM_BUS_ERR("Error in getting the iid \n");
+ return -ENODEV;
+ }
MSM_BUS_DBG("master_port: %d iid: %d fabid%d\n",
master_port, priv_id, GET_FABID(priv_id));
fabdev = msm_bus_get_fabric_device(GET_FABID(priv_id));
@@ -62,6 +66,10 @@
struct msm_bus_fabric_device *fabdev;
priv_id = msm_bus_board_get_iid(master_port);
+ if (priv_id == -ENXIO) {
+ MSM_BUS_ERR("Error in getting the iid \n");
+ return -ENODEV;
+ }
MSM_BUS_DBG("master_port: %d iid: %d fabid: %d\n",
master_port, priv_id, GET_FABID(priv_id));
fabdev = msm_bus_get_fabric_device(GET_FABID(priv_id));
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index b8e55f9..42a2638 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2012, 2014 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -395,7 +395,7 @@
uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
(sizeof(unsigned char) +
(sizeof(struct meta_out_dsp)*(audio->buf_cfg.frames_per_buf)));
-
+ memset(&meta, 0, sizeof(meta));
pr_debug("%s:session id %d: read - %d\n", __func__, audio->ac->session,
count);
if (!audio->enabled)
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index eb0c80c..43d0e29 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -1110,6 +1110,7 @@
switch (cmd) {
case AUDIO_GET_STATS: {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(struct msm_audio_stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *)arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
deleted file mode 100644
index 71ab566..0000000
--- a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/uaccess.h>
-#include <linux/dma-mapping.h>
-#include <linux/msm_audio.h>
-#include <mach/msm_hdmi_audio.h>
-#include <mach/audio_dma_msm8k.h>
-#include <sound/dai.h>
-#include "q6core.h"
-
-#define DMA_ALLOC_BUF_SZ (SZ_4K * 16)
-
-#define HDMI_AUDIO_FIFO_WATER_MARK 4
-
-struct audio_buffer {
- dma_addr_t phys;
- void *data;
- uint32_t size;
- uint32_t used; /* 1 = CPU is waiting for DMA to consume this buf */
- uint32_t actual_size; /* actual number of bytes read by DMA */
-};
-
-struct lpa_if {
- struct mutex lock;
- struct msm_audio_config cfg;
- struct audio_buffer audio_buf[6];
- int cpu_buf; /* next buffer the CPU will touch */
- int dma_buf; /* next buffer the DMA will touch */
- u8 *buffer;
- dma_addr_t buffer_phys;
- u32 dma_ch;
- wait_queue_head_t wait;
- u32 config;
- u32 dma_period_sz;
- unsigned int num_periods;
-};
-
-static struct lpa_if *lpa_if_ptr;
-
-static unsigned int dma_buf_index;
-
-static irqreturn_t lpa_if_irq(int intrsrc, void *data)
-{
- struct lpa_if *lpa_if = data;
- int dma_ch = 0;
- unsigned int pending;
-
- if (lpa_if)
- dma_ch = lpa_if->dma_ch;
- else {
- pr_err("invalid lpa_if\n");
- return IRQ_NONE;
- }
-
- pending = (intrsrc
- & (UNDER_CH(dma_ch) | PER_CH(dma_ch) | ERR_CH(dma_ch)));
-
- if (pending & UNDER_CH(dma_ch))
- pr_err("under run\n");
- if (pending & ERR_CH(dma_ch))
- pr_err("DMA %x Master Error\n", dma_ch);
-
- if (pending & PER_CH(dma_ch)) {
-
- lpa_if->audio_buf[lpa_if->dma_buf].used = 0;
-
- pr_debug("dma_buf %d used %d\n", lpa_if->dma_buf,
- lpa_if->audio_buf[lpa_if->dma_buf].used);
- lpa_if->dma_buf++;
- lpa_if->dma_buf = lpa_if->dma_buf % lpa_if->cfg.buffer_count;
-
- if (lpa_if->dma_buf == lpa_if->cpu_buf)
- pr_err("Err:both dma_buf and cpu_buf are on same index\n");
- wake_up(&lpa_if->wait);
- }
- return IRQ_HANDLED;
-}
-
-
-int lpa_if_start(struct lpa_if *lpa_if)
-{
- pr_debug("buf1 0x%x, buf2 0x%x dma_ch %d\n",
- (unsigned int)lpa_if->audio_buf[0].data,
- (unsigned int)lpa_if->audio_buf[1].data, lpa_if->dma_ch);
-
- dai_start_hdmi(lpa_if->dma_ch);
-
- hdmi_audio_enable(1, HDMI_AUDIO_FIFO_WATER_MARK);
-
- hdmi_audio_packet_enable(1);
- return 0;
-}
-
-int lpa_if_config(struct lpa_if *lpa_if)
-{
- struct dai_dma_params dma_params;
-
- dma_params.src_start = lpa_if->buffer_phys;
- dma_params.buffer = lpa_if->buffer;
- dma_params.buffer_size = lpa_if->dma_period_sz * lpa_if->num_periods;
- dma_params.period_size = lpa_if->dma_period_sz;
- dma_params.channels = 2;
-
- lpa_if->dma_ch = 4;
- dai_set_params(lpa_if->dma_ch, &dma_params);
-
- register_dma_irq_handler(lpa_if->dma_ch, lpa_if_irq, (void *)lpa_if);
-
- mb();
- pr_debug("lpa_if 0x%08x buf_vir 0x%08x buf_phys 0x%08x "
- "config %u\n", (u32)lpa_if, (u32) (lpa_if->buffer),
- lpa_if->buffer_phys, lpa_if->config);
-
- pr_debug("user_buf_cnt %u user_buf_size %u\n",
- lpa_if->cfg.buffer_count, lpa_if->cfg.buffer_size);
-
- lpa_if->config = 1;
-
- lpa_if_start(lpa_if);
-
- return 0;
-}
-
-
-static long lpa_if_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct lpa_if *lpa_if = file->private_data;
- int rc = 0;
- unsigned int i;
- pr_debug("cmd %u\n", cmd);
-
- mutex_lock(&lpa_if->lock);
-
- switch (cmd) {
- case AUDIO_START:
- pr_debug("AUDIO_START\n");
-
- if (dma_buf_index == 2) {
- if (!lpa_if->config) {
- rc = lpa_if_config(lpa_if);
- if (rc)
- pr_err("lpa_if_config failed\n");
- }
- } else {
- pr_err("did not receved two buffer for "
- "AUDIO_STAR\n");
- rc = -EPERM;
- }
- break;
-
- case AUDIO_STOP:
- pr_debug("AUDIO_STOP\n");
- break;
-
- case AUDIO_FLUSH:
- pr_debug("AUDIO_FLUSH\n");
- break;
-
-
- case AUDIO_GET_CONFIG:
- pr_debug("AUDIO_GET_CONFIG\n");
- if (copy_to_user((void *)arg, &lpa_if->cfg,
- sizeof(struct msm_audio_config))) {
- rc = -EFAULT;
- }
- break;
- case AUDIO_SET_CONFIG: {
- /* Setting default rate as 48khz */
- unsigned int cur_sample_rate =
- HDMI_SAMPLE_RATE_48KHZ;
- struct msm_audio_config config;
-
- pr_debug("AUDIO_SET_CONFIG\n");
- if (copy_from_user(&config, (void *)arg, sizeof(config))) {
- rc = -EFAULT;
- break;
- }
- lpa_if->dma_period_sz = config.buffer_size;
- if ((lpa_if->dma_period_sz * lpa_if->num_periods) >
- DMA_ALLOC_BUF_SZ) {
- pr_err("Dma buffer size greater than allocated size\n");
- return -EINVAL;
- }
- pr_debug("Dma_period_sz %d\n", lpa_if->dma_period_sz);
- if (lpa_if->dma_period_sz < (2 * SZ_4K))
- lpa_if->num_periods = 6;
- pr_debug("No. of Periods %d\n", lpa_if->num_periods);
-
- lpa_if->cfg.buffer_count = lpa_if->num_periods;
- lpa_if->cfg.buffer_size = lpa_if->dma_period_sz *
- lpa_if->num_periods;
-
- for (i = 0; i < lpa_if->cfg.buffer_count; i++) {
- lpa_if->audio_buf[i].phys =
- lpa_if->buffer_phys + i * lpa_if->dma_period_sz;
- lpa_if->audio_buf[i].data =
- lpa_if->buffer + i * lpa_if->dma_period_sz;
- lpa_if->audio_buf[i].size = lpa_if->dma_period_sz;
- lpa_if->audio_buf[i].used = 0;
- }
-
- pr_debug("Sample rate %d\n", config.sample_rate);
- switch (config.sample_rate) {
- case 48000:
- cur_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
- break;
- case 44100:
- cur_sample_rate = HDMI_SAMPLE_RATE_44_1KHZ;
- break;
- case 32000:
- cur_sample_rate = HDMI_SAMPLE_RATE_32KHZ;
- break;
- case 88200:
- cur_sample_rate = HDMI_SAMPLE_RATE_88_2KHZ;
- break;
- case 96000:
- cur_sample_rate = HDMI_SAMPLE_RATE_96KHZ;
- break;
- case 176400:
- cur_sample_rate = HDMI_SAMPLE_RATE_176_4KHZ;
- break;
- case 192000:
- cur_sample_rate = HDMI_SAMPLE_RATE_192KHZ;
- break;
- default:
- cur_sample_rate = HDMI_SAMPLE_RATE_48KHZ;
- }
- if (cur_sample_rate != hdmi_msm_audio_get_sample_rate())
- hdmi_msm_audio_sample_rate_reset(cur_sample_rate);
- else
- pr_debug("Previous sample rate and current"
- "sample rate are same\n");
- break;
- }
- default:
- pr_err("UnKnown Ioctl\n");
- rc = -EINVAL;
- }
-
- mutex_unlock(&lpa_if->lock);
-
- return rc;
-}
-
-
-static int lpa_if_open(struct inode *inode, struct file *file)
-{
- pr_debug("\n");
-
- file->private_data = lpa_if_ptr;
- dma_buf_index = 0;
- lpa_if_ptr->cpu_buf = 2;
- lpa_if_ptr->dma_buf = 0;
- lpa_if_ptr->num_periods = 4;
-
- core_req_bus_bandwith(AUDIO_IF_BUS_ID, 100000, 0);
- mb();
-
- return 0;
-}
-
-static inline int rt_policy(int policy)
-{
- if (unlikely(policy == SCHED_FIFO) || unlikely(policy == SCHED_RR))
- return 1;
- return 0;
-}
-
-static inline int task_has_rt_policy(struct task_struct *p)
-{
- return rt_policy(p->policy);
-}
-static ssize_t lpa_if_write(struct file *file, const char __user *buf,
- size_t count, loff_t *pos)
-{
- struct lpa_if *lpa_if = file->private_data;
- struct audio_buffer *ab;
- const char __user *start = buf;
- int xfer, rc;
- struct sched_param s = { .sched_priority = 1 };
- int old_prio = current->rt_priority;
- int old_policy = current->policy;
- int cap_nice = cap_raised(current_cap(), CAP_SYS_NICE);
-
- /* just for this write, set us real-time */
- if (!task_has_rt_policy(current)) {
- struct cred *new = prepare_creds();
- cap_raise(new->cap_effective, CAP_SYS_NICE);
- commit_creds(new);
- if ((sched_setscheduler(current, SCHED_RR, &s)) < 0)
- pr_err("sched_setscheduler failed\n");
- }
- mutex_lock(&lpa_if->lock);
-
- if (dma_buf_index < 2) {
-
- ab = lpa_if->audio_buf + dma_buf_index;
-
- if (copy_from_user(ab->data, buf, count)) {
- pr_err("copy from user failed\n");
- rc = 0;
- goto end;
-
- }
- mb();
- pr_debug("prefill: count %u audio_buf[%u].size %u\n",
- count, dma_buf_index, ab->size);
-
- ab->used = 1;
- dma_buf_index++;
- rc = count;
- goto end;
- }
-
- if (lpa_if->config != 1) {
- pr_err("AUDIO_START did not happen\n");
- rc = 0;
- goto end;
- }
-
- while (count > 0) {
-
- ab = lpa_if->audio_buf + lpa_if->cpu_buf;
-
- rc = wait_event_timeout(lpa_if->wait, (ab->used == 0), 10 * HZ);
- if (!rc) {
- pr_err("wait_event_timeout failed\n");
- rc = buf - start;
- goto end;
- }
-
- xfer = count;
-
- if (xfer > lpa_if->dma_period_sz)
- xfer = lpa_if->dma_period_sz;
-
- if (copy_from_user(ab->data, buf, xfer)) {
- pr_err("copy from user failed\n");
- rc = buf - start;
- goto end;
- }
-
- mb();
- buf += xfer;
- count -= xfer;
- ab->used = 1;
-
- pr_debug("xfer %d, size %d, used %d cpu_buf %d\n",
- xfer, ab->size, ab->used, lpa_if->cpu_buf);
- lpa_if->cpu_buf++;
- lpa_if->cpu_buf = lpa_if->cpu_buf % lpa_if->cfg.buffer_count;
- }
- rc = buf - start;
-end:
- mutex_unlock(&lpa_if->lock);
- /* restore old scheduling policy */
- if (!rt_policy(old_policy)) {
- struct sched_param v = { .sched_priority = old_prio };
- if ((sched_setscheduler(current, old_policy, &v)) < 0)
- pr_err("sched_setscheduler failed\n");
- if (likely(!cap_nice)) {
- struct cred *new = prepare_creds();
- cap_lower(new->cap_effective, CAP_SYS_NICE);
- commit_creds(new);
- }
- }
- return rc;
-}
-
-static int lpa_if_release(struct inode *inode, struct file *file)
-{
- struct lpa_if *lpa_if = file->private_data;
-
- hdmi_audio_packet_enable(0);
-
- wait_for_dma_cnt_stop(lpa_if->dma_ch);
-
- hdmi_audio_enable(0, HDMI_AUDIO_FIFO_WATER_MARK);
-
- if (lpa_if->config) {
- unregister_dma_irq_handler(lpa_if->dma_ch);
- dai_stop_hdmi(lpa_if->dma_ch);
- lpa_if->config = 0;
- }
- core_req_bus_bandwith(AUDIO_IF_BUS_ID, 0, 0);
-
- if (hdmi_msm_audio_get_sample_rate() != HDMI_SAMPLE_RATE_48KHZ)
- hdmi_msm_audio_sample_rate_reset(HDMI_SAMPLE_RATE_48KHZ);
-
- return 0;
-}
-
-static const struct file_operations lpa_if_fops = {
- .owner = THIS_MODULE,
- .open = lpa_if_open,
- .write = lpa_if_write,
- .release = lpa_if_release,
- .unlocked_ioctl = lpa_if_ioctl,
-};
-
-struct miscdevice lpa_if_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "msm_lpa_if_out",
- .fops = &lpa_if_fops,
-};
-
-static int __init lpa_if_init(void)
-{
- int rc;
-
- lpa_if_ptr = kzalloc(sizeof(struct lpa_if), GFP_KERNEL);
- if (!lpa_if_ptr) {
- pr_info("No mem for lpa-if\n");
- return -ENOMEM;
- }
-
- mutex_init(&lpa_if_ptr->lock);
- init_waitqueue_head(&lpa_if_ptr->wait);
-
- lpa_if_ptr->buffer = dma_alloc_coherent(NULL, DMA_ALLOC_BUF_SZ,
- &(lpa_if_ptr->buffer_phys), GFP_KERNEL);
- if (!lpa_if_ptr->buffer) {
- pr_err("dma_alloc_coherent failed\n");
- kfree(lpa_if_ptr);
- return -ENOMEM;
- }
-
- pr_info("lpa_if_ptr 0x%08x buf_vir 0x%08x buf_phy 0x%08x "
- " buf_zise %u\n", (u32)lpa_if_ptr,
- (u32)(lpa_if_ptr->buffer), lpa_if_ptr->buffer_phys,
- DMA_ALLOC_BUF_SZ);
-
- rc = misc_register(&lpa_if_misc);
- if (rc < 0) {
- pr_err("misc_register failed\n");
-
- dma_free_coherent(NULL, DMA_ALLOC_BUF_SZ, lpa_if_ptr->buffer,
- lpa_if_ptr->buffer_phys);
- kfree(lpa_if_ptr);
- }
- return rc;
-}
-
-device_initcall(lpa_if_init);
diff --git a/arch/arm/mach-msm/rpcrouter_sdio_xprt.c b/arch/arm/mach-msm/rpcrouter_sdio_xprt.c
deleted file mode 100644
index e9818e5..0000000
--- a/arch/arm/mach-msm/rpcrouter_sdio_xprt.c
+++ /dev/null
@@ -1,655 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * RPCROUTER SDIO XPRT module.
- */
-
-#include <linux/platform_device.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include <linux/sched.h>
-#include <linux/poll.h>
-#include <linux/wakelock.h>
-#include <asm/uaccess.h>
-#include <linux/slab.h>
-
-#include <mach/sdio_al.h>
-#include "smd_rpcrouter.h"
-
-enum {
- MSM_SDIO_XPRT_DEBUG = 1U << 0,
- MSM_SDIO_XPRT_INFO = 1U << 1,
-};
-
-static int msm_sdio_xprt_debug_mask;
-module_param_named(debug_mask, msm_sdio_xprt_debug_mask,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#if defined(CONFIG_MSM_RPC_SDIO_DEBUG)
-#define SDIO_XPRT_DBG(x...) do { \
- if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_DEBUG) \
- printk(KERN_DEBUG x); \
- } while (0)
-
-#define SDIO_XPRT_INFO(x...) do { \
- if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_INFO) \
- printk(KERN_INFO x); \
- } while (0)
-#else
-#define SDIO_XPRT_DBG(x...) do { } while (0)
-#define SDIO_XPRT_INFO(x...) do { } while (0)
-#endif
-
-#define MAX_SDIO_WRITE_RETRY 5
-#define SDIO_BUF_SIZE (RPCROUTER_MSGSIZE_MAX + sizeof(struct rr_header) - 8)
-#define NUM_SDIO_BUFS 20
-#define MAX_TX_BUFS 10
-#define MAX_RX_BUFS 10
-
-struct sdio_xprt {
- struct sdio_channel *handle;
-
- struct list_head write_list;
- spinlock_t write_list_lock;
-
- struct list_head read_list;
- spinlock_t read_list_lock;
-
- struct list_head free_list;
- spinlock_t free_list_lock;
-
- struct wake_lock read_wakelock;
-};
-
-struct rpcrouter_sdio_xprt {
- struct rpcrouter_xprt xprt;
- struct sdio_xprt *channel;
-};
-
-static struct rpcrouter_sdio_xprt sdio_remote_xprt;
-
-static void sdio_xprt_read_data(struct work_struct *work);
-static DECLARE_DELAYED_WORK(work_read_data, sdio_xprt_read_data);
-static struct workqueue_struct *sdio_xprt_read_workqueue;
-
-struct sdio_buf_struct {
- struct list_head list;
- uint32_t size;
- uint32_t read_index;
- uint32_t write_index;
- unsigned char data[SDIO_BUF_SIZE];
-};
-
-static void sdio_xprt_write_data(struct work_struct *work);
-static DECLARE_WORK(work_write_data, sdio_xprt_write_data);
-static wait_queue_head_t write_avail_wait_q;
-static uint32_t num_free_bufs;
-static uint32_t num_tx_bufs;
-static uint32_t num_rx_bufs;
-
-static DEFINE_MUTEX(modem_reset_lock);
-static uint32_t modem_reset;
-
-static void free_sdio_xprt(struct sdio_xprt *chnl)
-{
- struct sdio_buf_struct *buf;
- unsigned long flags;
-
- if (!chnl) {
- printk(KERN_ERR "Invalid chnl to free\n");
- return;
- }
-
- spin_lock_irqsave(&chnl->free_list_lock, flags);
- while (!list_empty(&chnl->free_list)) {
- buf = list_first_entry(&chnl->free_list,
- struct sdio_buf_struct, list);
- list_del(&buf->list);
- kfree(buf);
- }
- num_free_bufs = 0;
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-
- spin_lock_irqsave(&chnl->write_list_lock, flags);
- while (!list_empty(&chnl->write_list)) {
- buf = list_first_entry(&chnl->write_list,
- struct sdio_buf_struct, list);
- list_del(&buf->list);
- kfree(buf);
- }
- num_tx_bufs = 0;
- spin_unlock_irqrestore(&chnl->write_list_lock, flags);
-
- spin_lock_irqsave(&chnl->read_list_lock, flags);
- while (!list_empty(&chnl->read_list)) {
- buf = list_first_entry(&chnl->read_list,
- struct sdio_buf_struct, list);
- list_del(&buf->list);
- kfree(buf);
- }
- num_rx_bufs = 0;
- spin_unlock_irqrestore(&chnl->read_list_lock, flags);
- wake_unlock(&chnl->read_wakelock);
-}
-
-static struct sdio_buf_struct *alloc_from_free_list(struct sdio_xprt *chnl)
-{
- struct sdio_buf_struct *buf;
- unsigned long flags;
-
- spin_lock_irqsave(&chnl->free_list_lock, flags);
- if (list_empty(&chnl->free_list)) {
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
- SDIO_XPRT_DBG("%s: Free list empty\n", __func__);
- return NULL;
- }
- buf = list_first_entry(&chnl->free_list, struct sdio_buf_struct, list);
- list_del(&buf->list);
- num_free_bufs--;
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-
- buf->size = 0;
- buf->read_index = 0;
- buf->write_index = 0;
-
- return buf;
-}
-
-static void return_to_free_list(struct sdio_xprt *chnl,
- struct sdio_buf_struct *buf)
-{
- unsigned long flags;
-
- if (!chnl || !buf) {
- pr_err("%s: Invalid chnl or buf\n", __func__);
- return;
- }
-
- buf->size = 0;
- buf->read_index = 0;
- buf->write_index = 0;
-
- spin_lock_irqsave(&chnl->free_list_lock, flags);
- list_add_tail(&buf->list, &chnl->free_list);
- num_free_bufs++;
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
-
-}
-
-static int rpcrouter_sdio_remote_read_avail(void)
-{
- int read_avail = 0;
- unsigned long flags;
- struct sdio_buf_struct *buf;
-
- spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags);
- list_for_each_entry(buf, &sdio_remote_xprt.channel->read_list, list) {
- read_avail += buf->size;
- }
- spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock,
- flags);
- return read_avail;
-}
-
-static int rpcrouter_sdio_remote_read(void *data, uint32_t len)
-{
- struct sdio_buf_struct *buf;
- unsigned char *buf_data;
- unsigned long flags;
-
- SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
- if (len < 0 || !data)
- return -EINVAL;
- else if (len == 0)
- return 0;
-
- spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags);
- if (list_empty(&sdio_remote_xprt.channel->read_list)) {
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->read_list_lock, flags);
- return -EINVAL;
- }
-
- buf = list_first_entry(&sdio_remote_xprt.channel->read_list,
- struct sdio_buf_struct, list);
- if (buf->size < len) {
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->read_list_lock, flags);
- return -EINVAL;
- }
-
- buf_data = buf->data + buf->read_index;
- memcpy(data, buf_data, len);
- buf->read_index += len;
- buf->size -= len;
- if (buf->size == 0) {
- list_del(&buf->list);
- num_rx_bufs--;
- return_to_free_list(sdio_remote_xprt.channel, buf);
- }
-
- if (list_empty(&sdio_remote_xprt.channel->read_list))
- wake_unlock(&sdio_remote_xprt.channel->read_wakelock);
- spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock,
- flags);
- return len;
-}
-
-static int rpcrouter_sdio_remote_write_avail(void)
-{
- uint32_t write_avail = 0;
- unsigned long flags;
-
- SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
- spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags);
- write_avail = (MAX_TX_BUFS - num_tx_bufs) * SDIO_BUF_SIZE;
- spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock,
- flags);
- return write_avail;
-}
-
-static int rpcrouter_sdio_remote_write(void *data, uint32_t len,
- enum write_data_type type)
-{
- unsigned long flags;
- static struct sdio_buf_struct *buf;
- unsigned char *buf_data;
-
- switch (type) {
- case HEADER:
- spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
- flags);
- if (num_tx_bufs == MAX_TX_BUFS) {
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->write_list_lock,
- flags);
- return -ENOMEM;
- }
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->write_list_lock, flags);
-
- SDIO_XPRT_DBG("sdio_xprt WRITE HEADER %s\n", __func__);
- buf = alloc_from_free_list(sdio_remote_xprt.channel);
- if (!buf) {
- pr_err("%s: alloc_from_free_list failed\n", __func__);
- return -ENOMEM;
- }
- buf_data = buf->data + buf->write_index;
- memcpy(buf_data, data, len);
- buf->write_index += len;
- buf->size += len;
- return len;
- case PACKMARK:
- SDIO_XPRT_DBG("sdio_xprt WRITE PACKMARK %s\n", __func__);
- if (!buf) {
- pr_err("%s: HEADER not written or alloc failed\n",
- __func__);
- return -ENOMEM;
- }
- buf_data = buf->data + buf->write_index;
- memcpy(buf_data, data, len);
- buf->write_index += len;
- buf->size += len;
- return len;
- case PAYLOAD:
- SDIO_XPRT_DBG("sdio_xprt WRITE PAYLOAD %s\n", __func__);
- if (!buf) {
- pr_err("%s: HEADER not written or alloc failed\n",
- __func__);
- return -ENOMEM;
- }
- buf_data = buf->data + buf->write_index;
- memcpy(buf_data, data, len);
- buf->write_index += len;
- buf->size += len;
-
- SDIO_XPRT_DBG("sdio_xprt flush %d bytes\n", buf->size);
- spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
- flags);
- list_add_tail(&buf->list,
- &sdio_remote_xprt.channel->write_list);
- num_tx_bufs++;
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->write_list_lock, flags);
- queue_work(sdio_xprt_read_workqueue, &work_write_data);
- buf = NULL;
- return len;
- default:
- return -EINVAL;
- }
-}
-
-static void sdio_xprt_write_data(struct work_struct *work)
-{
- int rc = 0, sdio_write_retry = 0;
- unsigned long flags;
- struct sdio_buf_struct *buf;
-
- mutex_lock(&modem_reset_lock);
- if (modem_reset) {
- mutex_unlock(&modem_reset_lock);
- return;
- }
-
- spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags);
- while (!list_empty(&sdio_remote_xprt.channel->write_list)) {
- buf = list_first_entry(&sdio_remote_xprt.channel->write_list,
- struct sdio_buf_struct, list);
- list_del(&buf->list);
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->write_list_lock, flags);
- mutex_unlock(&modem_reset_lock);
-
- wait_event(write_avail_wait_q,
- (!(modem_reset) && (sdio_write_avail(
- sdio_remote_xprt.channel->handle) >=
- buf->size)));
-
- mutex_lock(&modem_reset_lock);
- while (!(modem_reset) &&
- ((rc = sdio_write(sdio_remote_xprt.channel->handle,
- buf->data, buf->size)) < 0) &&
- (sdio_write_retry++ < MAX_SDIO_WRITE_RETRY)) {
- printk(KERN_ERR "sdio_write failed with RC %d\n", rc);
- mutex_unlock(&modem_reset_lock);
- msleep(250);
- mutex_lock(&modem_reset_lock);
- }
- if (modem_reset) {
- mutex_unlock(&modem_reset_lock);
- kfree(buf);
- return;
- } else {
- return_to_free_list(sdio_remote_xprt.channel, buf);
- }
-
- if (!rc)
- SDIO_XPRT_DBG("sdio_write %d bytes completed\n",
- buf->size);
-
- spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
- flags);
- num_tx_bufs--;
- }
- spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock,
- flags);
- mutex_unlock(&modem_reset_lock);
-}
-
-static int rpcrouter_sdio_remote_close(void)
-{
- SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
- flush_workqueue(sdio_xprt_read_workqueue);
- sdio_close(sdio_remote_xprt.channel->handle);
- free_sdio_xprt(sdio_remote_xprt.channel);
- return 0;
-}
-
-static void sdio_xprt_read_data(struct work_struct *work)
-{
- int size = 0, read_avail;
- unsigned long flags;
- struct sdio_buf_struct *buf;
- SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
-
- mutex_lock(&modem_reset_lock);
- while (!(modem_reset) &&
- ((read_avail =
- sdio_read_avail(sdio_remote_xprt.channel->handle)) > 0)) {
- spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock,
- flags);
- if (num_rx_bufs == MAX_RX_BUFS) {
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->read_list_lock,
- flags);
- queue_delayed_work(sdio_xprt_read_workqueue,
- &work_read_data,
- msecs_to_jiffies(100));
- break;
- }
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->read_list_lock, flags);
-
- buf = alloc_from_free_list(sdio_remote_xprt.channel);
- if (!buf) {
- SDIO_XPRT_DBG("%s: Failed to alloc_from_free_list"
- " Try again later\n", __func__);
- queue_delayed_work(sdio_xprt_read_workqueue,
- &work_read_data,
- msecs_to_jiffies(100));
- break;
- }
-
- size = sdio_read(sdio_remote_xprt.channel->handle,
- buf->data, read_avail);
- if (size < 0) {
- printk(KERN_ERR "sdio_read failed,"
- " read %d bytes, expected %d\n",
- size, read_avail);
- return_to_free_list(sdio_remote_xprt.channel, buf);
- queue_delayed_work(sdio_xprt_read_workqueue,
- &work_read_data,
- msecs_to_jiffies(100));
- break;
- }
-
- if (size == 0)
- size = read_avail;
-
- buf->size = size;
- buf->write_index = size;
- spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock,
- flags);
- list_add_tail(&buf->list,
- &sdio_remote_xprt.channel->read_list);
- num_rx_bufs++;
- spin_unlock_irqrestore(
- &sdio_remote_xprt.channel->read_list_lock, flags);
- wake_lock(&sdio_remote_xprt.channel->read_wakelock);
- }
-
- if (!modem_reset && !list_empty(&sdio_remote_xprt.channel->read_list))
- msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
- RPCROUTER_XPRT_EVENT_DATA);
- mutex_unlock(&modem_reset_lock);
-}
-
-static void rpcrouter_sdio_remote_notify(void *_dev, unsigned event)
-{
- if (event == SDIO_EVENT_DATA_READ_AVAIL) {
- SDIO_XPRT_DBG("%s Received Notify"
- "SDIO_EVENT_DATA_READ_AVAIL\n", __func__);
- queue_delayed_work(sdio_xprt_read_workqueue,
- &work_read_data, 0);
- }
- if (event == SDIO_EVENT_DATA_WRITE_AVAIL) {
- SDIO_XPRT_DBG("%s Received Notify"
- "SDIO_EVENT_DATA_WRITE_AVAIL\n", __func__);
- wake_up(&write_avail_wait_q);
- }
-}
-
-static int allocate_sdio_xprt(struct sdio_xprt **sdio_xprt_chnl)
-{
- struct sdio_buf_struct *buf;
- struct sdio_xprt *chnl;
- int i;
- unsigned long flags;
- int rc = -ENOMEM;
-
- if (!(*sdio_xprt_chnl)) {
- chnl = kmalloc(sizeof(struct sdio_xprt), GFP_KERNEL);
- if (!chnl) {
- printk(KERN_ERR "sdio_xprt channel"
- " allocation failed\n");
- return rc;
- }
-
- spin_lock_init(&chnl->write_list_lock);
- spin_lock_init(&chnl->read_list_lock);
- spin_lock_init(&chnl->free_list_lock);
-
- INIT_LIST_HEAD(&chnl->write_list);
- INIT_LIST_HEAD(&chnl->read_list);
- INIT_LIST_HEAD(&chnl->free_list);
- wake_lock_init(&chnl->read_wakelock,
- WAKE_LOCK_SUSPEND, "rpc_sdio_xprt_read");
- } else {
- chnl = *sdio_xprt_chnl;
- }
-
- for (i = 0; i < NUM_SDIO_BUFS; i++) {
- buf = kzalloc(sizeof(struct sdio_buf_struct), GFP_KERNEL);
- if (!buf) {
- printk(KERN_ERR "sdio_buf_struct alloc failed\n");
- goto alloc_failure;
- }
- spin_lock_irqsave(&chnl->free_list_lock, flags);
- list_add_tail(&buf->list, &chnl->free_list);
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
- }
- num_free_bufs = NUM_SDIO_BUFS;
-
- *sdio_xprt_chnl = chnl;
- return 0;
-
-alloc_failure:
- spin_lock_irqsave(&chnl->free_list_lock, flags);
- while (!list_empty(&chnl->free_list)) {
- buf = list_first_entry(&chnl->free_list,
- struct sdio_buf_struct,
- list);
- list_del(&buf->list);
- kfree(buf);
- }
- spin_unlock_irqrestore(&chnl->free_list_lock, flags);
- wake_lock_destroy(&chnl->read_wakelock);
-
- kfree(chnl);
- *sdio_xprt_chnl = NULL;
- return rc;
-}
-
-static int rpcrouter_sdio_remote_probe(struct platform_device *pdev)
-{
- int rc;
-
- SDIO_XPRT_INFO("%s Called\n", __func__);
-
- mutex_lock(&modem_reset_lock);
- if (!modem_reset) {
- sdio_xprt_read_workqueue =
- create_singlethread_workqueue("sdio_xprt");
- if (!sdio_xprt_read_workqueue) {
- mutex_unlock(&modem_reset_lock);
- return -ENOMEM;
- }
-
- sdio_remote_xprt.xprt.name = "rpcrotuer_sdio_xprt";
- sdio_remote_xprt.xprt.read_avail =
- rpcrouter_sdio_remote_read_avail;
- sdio_remote_xprt.xprt.read = rpcrouter_sdio_remote_read;
- sdio_remote_xprt.xprt.write_avail =
- rpcrouter_sdio_remote_write_avail;
- sdio_remote_xprt.xprt.write = rpcrouter_sdio_remote_write;
- sdio_remote_xprt.xprt.close = rpcrouter_sdio_remote_close;
- sdio_remote_xprt.xprt.priv = NULL;
-
- init_waitqueue_head(&write_avail_wait_q);
- }
- modem_reset = 0;
-
- rc = allocate_sdio_xprt(&sdio_remote_xprt.channel);
- if (rc) {
- destroy_workqueue(sdio_xprt_read_workqueue);
- mutex_unlock(&modem_reset_lock);
- return rc;
- }
-
- /* Open up SDIO channel */
- rc = sdio_open("SDIO_RPC", &sdio_remote_xprt.channel->handle, NULL,
- rpcrouter_sdio_remote_notify);
-
- if (rc < 0) {
- free_sdio_xprt(sdio_remote_xprt.channel);
- destroy_workqueue(sdio_xprt_read_workqueue);
- mutex_unlock(&modem_reset_lock);
- return rc;
- }
- mutex_unlock(&modem_reset_lock);
-
- msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
- RPCROUTER_XPRT_EVENT_OPEN);
-
- SDIO_XPRT_INFO("%s Completed\n", __func__);
-
- return 0;
-}
-
-static int rpcrouter_sdio_remote_remove(struct platform_device *pdev)
-{
- SDIO_XPRT_INFO("%s Called\n", __func__);
-
- mutex_lock(&modem_reset_lock);
- modem_reset = 1;
- wake_up(&write_avail_wait_q);
- free_sdio_xprt(sdio_remote_xprt.channel);
- mutex_unlock(&modem_reset_lock);
-
- msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
- RPCROUTER_XPRT_EVENT_CLOSE);
-
- SDIO_XPRT_INFO("%s Completed\n", __func__);
-
- return 0;
-}
-
-/*Remove this platform driver after mainline of SDIO_AL update*/
-static struct platform_driver rpcrouter_sdio_remote_driver = {
- .probe = rpcrouter_sdio_remote_probe,
- .driver = {
- .name = "SDIO_AL",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver rpcrouter_sdio_driver = {
- .probe = rpcrouter_sdio_remote_probe,
- .remove = rpcrouter_sdio_remote_remove,
- .driver = {
- .name = "SDIO_RPC",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init rpcrouter_sdio_init(void)
-{
- int rc;
- msm_sdio_xprt_debug_mask = 0x2;
- rc = platform_driver_register(&rpcrouter_sdio_remote_driver);
- if (rc < 0)
- return rc;
- return platform_driver_register(&rpcrouter_sdio_driver);
-}
-
-module_init(rpcrouter_sdio_init);
-MODULE_DESCRIPTION("RPC Router SDIO XPRT");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index c4c9566..654e526 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -1091,14 +1091,16 @@
{
struct device *dev = &pdev->dev;
struct rpm_regulator *reg;
+ struct rpm_vreg *rpm_vreg;
reg = platform_get_drvdata(pdev);
if (reg) {
- rpm_vreg_lock(reg->rpm_vreg);
+ rpm_vreg = reg->rpm_vreg;
+ rpm_vreg_lock(rpm_vreg);
regulator_unregister(reg->rdev);
list_del(®->list);
kfree(reg);
- rpm_vreg_unlock(reg->rpm_vreg);
+ rpm_vreg_unlock(rpm_vreg);
} else {
dev_err(dev, "%s: drvdata missing\n", __func__);
return -EINVAL;
diff --git a/arch/arm/mach-msm/sdio_al.c b/arch/arm/mach-msm/sdio_al.c
deleted file mode 100644
index bcfc556..0000000
--- a/arch/arm/mach-msm/sdio_al.c
+++ /dev/null
@@ -1,4365 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Abstraction-Layer Module.
- *
- * To be used with Qualcomm's SDIO-Client connected to this host.
- */
-#include "sdio_al_private.h"
-
-#include <linux/module.h>
-#include <linux/scatterlist.h>
-#include <linux/workqueue.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/wakelock.h>
-#include <linux/mmc/core.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/gpio.h>
-#include <linux/dma-mapping.h>
-#include <linux/earlysuspend.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/syscalls.h>
-#include <linux/time.h>
-#include <linux/spinlock.h>
-
-#include <mach/dma.h>
-#include <mach/gpio.h>
-#include <mach/subsystem_notif.h>
-
-#include "../../../drivers/mmc/host/msm_sdcc.h"
-
-/**
- * Func#0 has SDIO standard registers
- * Func#1 is for Mailbox.
- * Functions 2..7 are for channels.
- * Currently only functions 2..5 are active due to SDIO-Client
- * number of pipes.
- *
- */
-#define SDIO_AL_MAX_CHANNELS 6
-
-/** Func 1..5 */
-#define SDIO_AL_MAX_FUNCS (SDIO_AL_MAX_CHANNELS+1)
-#define SDIO_AL_WAKEUP_FUNC 6
-
-/** Number of SDIO-Client pipes */
-#define SDIO_AL_MAX_PIPES 16
-#define SDIO_AL_ACTIVE_PIPES 8
-
-/** CMD53/CMD54 Block size */
-#define SDIO_AL_BLOCK_SIZE 256
-
-/** Func#1 hardware Mailbox base address */
-#define HW_MAILBOX_ADDR 0x1000
-
-/** Func#1 peer sdioc software version.
- * The header is duplicated also to the mailbox of the other
- * functions. It can be used before other functions are enabled. */
-#define SDIOC_SW_HEADER_ADDR 0x0400
-
-/** Func#2..7 software Mailbox base address at 16K */
-#define SDIOC_SW_MAILBOX_ADDR 0x4000
-
-/** Some Mailbox registers address, written by host for
- control */
-#define PIPES_THRESHOLD_ADDR 0x01000
-
-#define PIPES_0_7_IRQ_MASK_ADDR 0x01048
-
-#define PIPES_8_15_IRQ_MASK_ADDR 0x0104C
-
-#define FUNC_1_4_MASK_IRQ_ADDR 0x01040
-#define FUNC_5_7_MASK_IRQ_ADDR 0x01044
-#define FUNC_1_4_USER_IRQ_ADDR 0x01050
-#define FUNC_5_7_USER_IRQ_ADDR 0x01054
-
-#define EOT_PIPES_ENABLE 0x00
-
-/** Maximum read/write data available is SDIO-Client limitation */
-#define MAX_DATA_AVAILABLE (16*1024)
-#define INVALID_DATA_AVAILABLE (0x8000)
-
-/** SDIO-Client HW threshold to generate interrupt to the
- * SDIO-Host on write available bytes.
- */
-#define DEFAULT_WRITE_THRESHOLD (1024)
-
-/** SDIO-Client HW threshold to generate interrupt to the
- * SDIO-Host on read available bytes, for streaming (non
- * packet) rx data.
- */
-#define DEFAULT_READ_THRESHOLD (1024)
-#define LOW_LATENCY_THRESHOLD (1)
-
-/* Extra bytes to ensure getting the rx threshold interrupt on stream channels
- when restoring the threshold after sleep */
-#define THRESHOLD_CHANGE_EXTRA_BYTES (100)
-
-/** SW threshold to trigger reading the mailbox. */
-#define DEFAULT_MIN_WRITE_THRESHOLD (1024)
-#define DEFAULT_MIN_WRITE_THRESHOLD_STREAMING (1600)
-
-#define THRESHOLD_DISABLE_VAL (0xFFFFFFFF)
-
-/** Mailbox polling time for packet channels */
-#define DEFAULT_POLL_DELAY_MSEC 10
-/** Mailbox polling time for streaming channels */
-#define DEFAULT_POLL_DELAY_NOPACKET_MSEC 30
-
-/** The SDIO-Client prepares N buffers of size X per Tx pipe.
- * Even when the transfer fills a partial buffer,
- * that buffer becomes unusable for the next transfer. */
-#define DEFAULT_PEER_TX_BUF_SIZE (128)
-
-#define ROUND_UP(x, n) (((x + n - 1) / n) * n)
-
-/** Func#2..7 FIFOs are r/w via
- sdio_readsb() & sdio_writesb(),when inc_addr=0 */
-#define PIPE_RX_FIFO_ADDR 0x00
-#define PIPE_TX_FIFO_ADDR 0x00
-
-/** Inactivity time to go to sleep in mseconds */
-#define INACTIVITY_TIME_MSEC 30
-#define INITIAL_INACTIVITY_TIME_MSEC 5000
-
-/** Context validity check */
-#define SDIO_AL_SIGNATURE 0xAABBCCDD
-
-/* Vendor Specific Command */
-#define SD_IO_RW_EXTENDED_QCOM 54
-
-#define TIME_TO_WAIT_US 500
-#define SDIO_CLOSE_FLUSH_TIMEOUT_MSEC (10000)
-#define RX_FLUSH_BUFFER_SIZE (16*1024)
-
-#define SDIO_TEST_POSTFIX "_TEST"
-
-#define DATA_DEBUG(x, y...) \
- do { \
- if (sdio_al->debug.debug_data_on) \
- pr_info(y); \
- sdio_al_log(x, y); \
- } while (0)
-
-#define LPM_DEBUG(x, y...) \
- do { \
- if (sdio_al->debug.debug_lpm_on) \
- pr_info(y); \
- sdio_al_log(x, y); \
- } while (0)
-
-#define sdio_al_loge(x, y...) \
- do { \
- pr_err(y); \
- sdio_al_log(x, y); \
- } while (0)
-
-#define sdio_al_logi(x, y...) \
- do { \
- pr_info(y); \
- sdio_al_log(x, y); \
- } while (0)
-
-#define CLOSE_DEBUG(x, y...) \
- do { \
- if (sdio_al->debug.debug_close_on) \
- pr_info(y); \
- sdio_al_log(x, y); \
- } while (0)
-
-/* The index of the SDIO card used for the sdio_al_dloader */
-#define SDIO_BOOTLOADER_CARD_INDEX 1
-
-
-/* SDIO card state machine */
-enum sdio_al_device_state {
- CARD_INSERTED,
- CARD_REMOVED,
- MODEM_RESTART
-};
-
-struct sdio_al_debug {
- u8 debug_lpm_on;
- u8 debug_data_on;
- u8 debug_close_on;
- struct dentry *sdio_al_debug_root;
- struct dentry *sdio_al_debug_lpm_on;
- struct dentry *sdio_al_debug_data_on;
- struct dentry *sdio_al_debug_close_on;
- struct dentry *sdio_al_debug_info;
- struct dentry *sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES + 1];
-};
-
-/* Polling time for the inactivity timer for devices that doesn't have
- * a streaming channel
- */
-#define SDIO_AL_POLL_TIME_NO_STREAMING 30
-
-#define CHAN_TO_FUNC(x) ((x) + 2 - 1)
-
-/**
- * Mailbox structure.
- * The Mailbox is located on the SDIO-Client Function#1.
- * The mailbox size is 128 bytes, which is one block.
- * The mailbox allows the host ton:
- * 1. Get the number of available bytes on the pipes.
- * 2. Enable/Disable SDIO-Client interrupt, related to pipes.
- * 3. Set the Threshold for generating interrupt.
- *
- */
-struct sdio_mailbox {
- u32 pipe_bytes_threshold[SDIO_AL_MAX_PIPES]; /* Addr 0x1000 */
-
- /* Mask USER interrupts generated towards host - Addr 0x1040 */
- u32 mask_irq_func_1:8; /* LSB */
- u32 mask_irq_func_2:8;
- u32 mask_irq_func_3:8;
- u32 mask_irq_func_4:8;
-
- u32 mask_irq_func_5:8;
- u32 mask_irq_func_6:8;
- u32 mask_irq_func_7:8;
- u32 mask_mutex_irq:8;
-
- /* Mask PIPE interrupts generated towards host - Addr 0x1048 */
- u32 mask_eot_pipe_0_7:8;
- u32 mask_thresh_above_limit_pipe_0_7:8;
- u32 mask_overflow_pipe_0_7:8;
- u32 mask_underflow_pipe_0_7:8;
-
- u32 mask_eot_pipe_8_15:8;
- u32 mask_thresh_above_limit_pipe_8_15:8;
- u32 mask_overflow_pipe_8_15:8;
- u32 mask_underflow_pipe_8_15:8;
-
- /* Status of User interrupts generated towards host - Addr 0x1050 */
- u32 user_irq_func_1:8;
- u32 user_irq_func_2:8;
- u32 user_irq_func_3:8;
- u32 user_irq_func_4:8;
-
- u32 user_irq_func_5:8;
- u32 user_irq_func_6:8;
- u32 user_irq_func_7:8;
- u32 user_mutex_irq:8;
-
- /* Status of PIPE interrupts generated towards host */
- /* Note: All sources are cleared once they read. - Addr 0x1058 */
- u32 eot_pipe_0_7:8;
- u32 thresh_above_limit_pipe_0_7:8;
- u32 overflow_pipe_0_7:8;
- u32 underflow_pipe_0_7:8;
-
- u32 eot_pipe_8_15:8;
- u32 thresh_above_limit_pipe_8_15:8;
- u32 overflow_pipe_8_15:8;
- u32 underflow_pipe_8_15:8;
-
- u16 pipe_bytes_avail[SDIO_AL_MAX_PIPES];
-};
-
-/** Track pending Rx Packet size */
-struct rx_packet_size {
- u32 size; /* in bytes */
- struct list_head list;
-};
-
-#define PEER_SDIOC_SW_MAILBOX_SIGNATURE 0xFACECAFE
-#define PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE 0x5D107E57
-#define PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE 0xDEADBEEF
-
-/* Allow support in old sdio version */
-#define PEER_SDIOC_OLD_VERSION_MAJOR 0x0002
-#define INVALID_SDIO_CHAN 0xFF
-
-/**
- * Peer SDIO-Client software header.
- */
-struct peer_sdioc_sw_header {
- u32 signature;
- u32 version;
- u32 max_channels;
- char channel_names[SDIO_AL_MAX_CHANNELS][PEER_CHANNEL_NAME_SIZE];
- u32 reserved[23];
-};
-
-struct peer_sdioc_boot_sw_header {
- u32 signature;
- u32 version;
- u32 boot_ch_num;
- u32 reserved[29]; /* 32 - previous fields */
-};
-
-/**
- * Peer SDIO-Client software mailbox.
- */
-struct peer_sdioc_sw_mailbox {
- struct peer_sdioc_sw_header sw_header;
- struct peer_sdioc_channel_config ch_config[SDIO_AL_MAX_CHANNELS];
-};
-
-#define SDIO_AL_DEBUG_LOG_SIZE 3000
-struct sdio_al_local_log {
- char buffer[SDIO_AL_DEBUG_LOG_SIZE];
- unsigned int buf_cur_pos;
- spinlock_t log_lock;
-};
-
-#define SDIO_AL_DEBUG_TMP_LOG_SIZE 250
-static int sdio_al_log(struct sdio_al_local_log *, const char *fmt, ...);
-
-/**
- * SDIO Abstraction Layer driver context.
- *
- * @pdata -
- * @debug -
- * @devices - an array of the the devices claimed by sdio_al
- * @unittest_mode - a flag to indicate if sdio_al is in
- * unittest mode
- * @bootloader_dev - the device which is used for the
- * bootloader
- * @subsys_notif_handle - handle for modem restart
- * notifications
- *
- */
-struct sdio_al {
- struct sdio_al_local_log gen_log;
- struct sdio_al_local_log device_log[MAX_NUM_OF_SDIO_DEVICES];
- struct sdio_al_platform_data *pdata;
- struct sdio_al_debug debug;
- struct sdio_al_device *devices[MAX_NUM_OF_SDIO_DEVICES];
- int unittest_mode;
- struct sdio_al_device *bootloader_dev;
- void *subsys_notif_handle;
- int sdioc_major;
- int skip_print_info;
-};
-
-struct sdio_al_work {
- struct work_struct work;
- struct sdio_al_device *sdio_al_dev;
-};
-
-
-/**
- * SDIO Abstraction Layer device context.
- *
- * @card - card claimed.
- *
- * @mailbox - A shadow of the SDIO-Client mailbox.
- *
- * @channel - Channels context.
- *
- * @workqueue - workqueue to read the mailbox and handle
- * pending requests. Reading the mailbox should not happen
- * in interrupt context.
- *
- * @work - work to submit to workqueue.
- *
- * @is_ready - driver is ready.
- *
- * @ask_mbox - Flag to request reading the mailbox,
- * for different reasons.
- *
- * @wake_lock - Lock when can't sleep.
- *
- * @lpm_chan - Channel to use for LPM (low power mode)
- * communication.
- *
- * @is_ok_to_sleep - Mark if driver is OK with going to sleep
- * (no pending transactions).
- *
- * @inactivity_time - time allowed to be in inactivity before
- * going to sleep
- *
- * @timer - timer to use for polling the mailbox.
- *
- * @poll_delay_msec - timer delay for polling the mailbox.
- *
- * @is_err - error detected.
- *
- * @signature - Context Validity Check.
- *
- * @flashless_boot_on - flag to indicate if sdio_al is in
- * flshless boot mode
- *
- */
-struct sdio_al_device {
- struct sdio_al_local_log *dev_log;
- struct mmc_card *card;
- struct mmc_host *host;
- struct sdio_mailbox *mailbox;
- struct sdio_channel channel[SDIO_AL_MAX_CHANNELS];
-
- struct peer_sdioc_sw_header *sdioc_sw_header;
- struct peer_sdioc_boot_sw_header *sdioc_boot_sw_header;
-
- struct workqueue_struct *workqueue;
- struct sdio_al_work sdio_al_work;
- struct sdio_al_work boot_work;
-
- int is_ready;
-
- wait_queue_head_t wait_mbox;
- int ask_mbox;
- int bootloader_done;
-
- struct wake_lock wake_lock;
- int lpm_chan;
- int is_ok_to_sleep;
- unsigned long inactivity_time;
-
- struct timer_list timer;
- u32 poll_delay_msec;
- int is_timer_initialized;
-
- int is_err;
-
- u32 signature;
-
- unsigned int is_suspended;
-
- int flashless_boot_on;
- int ch_close_supported;
- int state;
- int (*lpm_callback)(void *, int);
-
- int print_after_interrupt;
-
- u8 *rx_flush_buf;
-};
-
-/*
- * Host operation:
- * lower 16bits are operation code
- * upper 16bits are operation state
- */
-#define PEER_OPERATION(op_code , op_state) ((op_code) | ((op_state) << 16))
-#define GET_PEER_OPERATION_CODE(op) ((op) & 0xffff)
-#define GET_PEER_OPERATION_STATE(op) ((op) >> 16)
-
-enum peer_op_code {
- PEER_OP_CODE_CLOSE = 1
-};
-
-enum peer_op_state {
- PEER_OP_STATE_INIT = 0,
- PEER_OP_STATE_START = 1
-};
-
-
-/*
- * On the kernel command line specify
- * sdio_al.debug_lpm_on=1 to enable the LPM debug messages
- * By default the LPM debug messages are turned off
- */
-static int debug_lpm_on;
-module_param(debug_lpm_on, int, 0);
-
-/*
- * On the kernel command line specify
- * sdio_al.debug_data_on=1 to enable the DATA debug messages
- * By default the DATA debug messages are turned off
- */
-static int debug_data_on;
-module_param(debug_data_on, int, 0);
-
-/*
- * Enables / disables open close debug messages
- */
-static int debug_close_on = 1;
-module_param(debug_close_on, int, 0);
-
-/** The driver context */
-static struct sdio_al *sdio_al;
-
-/* Static functions declaration */
-static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int enable);
-static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int enable);
-static void sdio_func_irq(struct sdio_func *func);
-static void sdio_al_timer_handler(unsigned long data);
-static int get_min_poll_time_msec(struct sdio_al_device *sdio_al_dev);
-static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot);
-static u32 remove_handled_rx_packet(struct sdio_channel *ch);
-static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int threshold);
-static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
- u32 not_from_int, struct sdio_channel *ch);
-static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev);
-static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
- int func_num, int enable, u8 bit_offset);
-static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name);
-static void sdio_al_print_info(void);
-static int sdio_read_internal(struct sdio_channel *ch, void *data, int len);
-static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len);
-static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev);
-
-#define SDIO_AL_ERR(func) \
- do { \
- printk_once(KERN_ERR MODULE_NAME \
- ":In Error state, ignore %s\n", \
- func); \
- sdio_al_print_info(); \
- } while (0)
-
-#ifdef CONFIG_DEBUG_FS
-static int debug_info_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t debug_info_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- sdio_al_print_info();
- return 1;
-}
-
-const struct file_operations debug_info_ops = {
- .open = debug_info_open,
- .write = debug_info_write,
-};
-
-struct debugfs_blob_wrapper sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES + 1];
-
-/*
-*
-* Trigger on/off for debug messages
-* for trigger off the data messages debug level use:
-* echo 0 > /sys/kernel/debugfs/sdio_al/debug_data_on
-* for trigger on the data messages debug level use:
-* echo 1 > /sys/kernel/debugfs/sdio_al/debug_data_on
-* for trigger off the lpm messages debug level use:
-* echo 0 > /sys/kernel/debugfs/sdio_al/debug_lpm_on
-* for trigger on the lpm messages debug level use:
-* echo 1 > /sys/kernel/debugfs/sdio_al/debug_lpm_on
-*/
-static int sdio_al_debugfs_init(void)
-{
- int i, blob_errs = 0;
-
- sdio_al->debug.sdio_al_debug_root = debugfs_create_dir("sdio_al", NULL);
- if (!sdio_al->debug.sdio_al_debug_root)
- return -ENOENT;
-
- sdio_al->debug.sdio_al_debug_lpm_on = debugfs_create_u8("debug_lpm_on",
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- &sdio_al->debug.debug_lpm_on);
-
- sdio_al->debug.sdio_al_debug_data_on = debugfs_create_u8(
- "debug_data_on",
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- &sdio_al->debug.debug_data_on);
-
- sdio_al->debug.sdio_al_debug_close_on = debugfs_create_u8(
- "debug_close_on",
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- &sdio_al->debug.debug_close_on);
-
- sdio_al->debug.sdio_al_debug_info = debugfs_create_file(
- "sdio_debug_info",
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- NULL,
- &debug_info_ops);
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
- char temp[18];
-
- scnprintf(temp, 18, "sdio_al_log_dev_%d", i + 1);
- sdio_al->debug.sdio_al_debug_log_buffers[i] =
- debugfs_create_blob(temp,
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- &sdio_al_dbgfs_log[i]);
- }
-
- sdio_al->debug.sdio_al_debug_log_buffers[MAX_NUM_OF_SDIO_DEVICES] =
- debugfs_create_blob("sdio_al_gen_log",
- S_IRUGO | S_IWUGO,
- sdio_al->debug.sdio_al_debug_root,
- &sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES]);
-
- for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i) {
- if (!sdio_al->debug.sdio_al_debug_log_buffers[i]) {
- pr_err(MODULE_NAME ": Failed to create debugfs buffer"
- " entry for "
- "sdio_al->debug.sdio_al_debug_log_buffers[%d]",
- i);
- blob_errs = 1;
- }
- }
-
- if (blob_errs) {
- for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i)
- if (sdio_al->debug.sdio_al_debug_log_buffers[i])
- debugfs_remove(
- sdio_al->
- debug.sdio_al_debug_log_buffers[i]);
- }
-
-
- if ((!sdio_al->debug.sdio_al_debug_data_on) &&
- (!sdio_al->debug.sdio_al_debug_lpm_on) &&
- (!sdio_al->debug.sdio_al_debug_close_on) &&
- (!sdio_al->debug.sdio_al_debug_info) &&
- blob_errs) {
- debugfs_remove(sdio_al->debug.sdio_al_debug_root);
- sdio_al->debug.sdio_al_debug_root = NULL;
- return -ENOENT;
- }
-
- sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].data =
- sdio_al->gen_log.buffer;
- sdio_al_dbgfs_log[MAX_NUM_OF_SDIO_DEVICES].size =
- SDIO_AL_DEBUG_LOG_SIZE;
-
- return 0;
-}
-
-static void sdio_al_debugfs_cleanup(void)
-{
- int i;
-
- debugfs_remove(sdio_al->debug.sdio_al_debug_lpm_on);
- debugfs_remove(sdio_al->debug.sdio_al_debug_data_on);
- debugfs_remove(sdio_al->debug.sdio_al_debug_close_on);
- debugfs_remove(sdio_al->debug.sdio_al_debug_info);
-
- for (i = 0; i < (MAX_NUM_OF_SDIO_DEVICES + 1); ++i)
- debugfs_remove(sdio_al->debug.sdio_al_debug_log_buffers[i]);
-
- debugfs_remove(sdio_al->debug.sdio_al_debug_root);
-}
-#endif
-
-static int sdio_al_log(struct sdio_al_local_log *log, const char *fmt, ...)
-{
- va_list args;
- int r;
- char *tp, *log_buf;
- unsigned int *log_cur_pos;
- struct timeval kt;
- unsigned long flags;
- static char sdio_al_log_tmp[SDIO_AL_DEBUG_TMP_LOG_SIZE];
-
- spin_lock_irqsave(&log->log_lock, flags);
-
- kt = ktime_to_timeval(ktime_get());
- r = scnprintf(sdio_al_log_tmp, SDIO_AL_DEBUG_TMP_LOG_SIZE,
- "[%8ld.%6ld] ", kt.tv_sec, kt.tv_usec);
-
- va_start(args, fmt);
- r += vscnprintf(&sdio_al_log_tmp[r], (SDIO_AL_DEBUG_TMP_LOG_SIZE - r),
- fmt, args);
- va_end(args);
-
- log_buf = log->buffer;
- log_cur_pos = &(log->buf_cur_pos);
-
- for (tp = sdio_al_log_tmp; tp < (sdio_al_log_tmp + r); tp++) {
- log_buf[(*log_cur_pos)++] = *tp;
- if ((*log_cur_pos) == SDIO_AL_DEBUG_LOG_SIZE)
- *log_cur_pos = 0;
- }
-
- spin_unlock_irqrestore(&log->log_lock, flags);
-
- return r;
-}
-
-static int sdio_al_verify_func1(struct sdio_al_device *sdio_al_dev,
- char const *func)
-{
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "sdio_al_dev\n", func);
- return -ENODEV;
- }
-
- if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
- "signature\n", func);
- return -ENODEV;
- }
-
- if (!sdio_al_dev->card) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
- "card\n", func);
- return -ENODEV;
- }
- if (!sdio_al_dev->card->sdio_func[0]) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
- "func1\n", func);
- return -ENODEV;
- }
- return 0;
-}
-
-static int sdio_al_claim_mutex(struct sdio_al_device *sdio_al_dev,
- char const *func)
-{
- if (!sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "device\n", func);
- return -ENODEV;
- }
-
- if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
- "device signature\n", func);
- return -ENODEV;
- }
-
- if (!sdio_al_dev->host) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
- "host\n", func);
- return -ENODEV;
- }
-
- mmc_claim_host(sdio_al_dev->host);
-
- return 0;
-}
-
-static int sdio_al_release_mutex(struct sdio_al_device *sdio_al_dev,
- char const *func)
-{
- if (!sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "device\n", func);
- return -ENODEV;
- }
-
- if (sdio_al_dev->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
- "device signature\n", func);
- return -ENODEV;
- }
-
- if (!sdio_al_dev->host) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: NULL "
- "host\n", func);
- return -ENODEV;
- }
-
- mmc_release_host(sdio_al_dev->host);
-
- return 0;
-}
-
-static int sdio_al_claim_mutex_and_verify_dev(
- struct sdio_al_device *sdio_al_dev,
- char const *func)
-{
- if (sdio_al_claim_mutex(sdio_al_dev, __func__))
- return -ENODEV;
-
- if (sdio_al_dev->state != CARD_INSERTED) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": %s: Invalid "
- "device state %d\n", func, sdio_al_dev->state);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void sdio_al_get_into_err_state(struct sdio_al_device *sdio_al_dev)
-{
- if ((!sdio_al) || (!sdio_al_dev))
- return;
-
- sdio_al_dev->is_err = true;
- sdio_al->debug.debug_data_on = 0;
- sdio_al->debug.debug_lpm_on = 0;
- sdio_al_print_info();
-}
-
-void sdio_al_register_lpm_cb(void *device_handle,
- int(*lpm_callback)(void *, int))
-{
- struct sdio_al_device *sdio_al_dev =
- (struct sdio_al_device *) device_handle;
-
- if (!sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - "
- "device_handle is NULL\n", __func__);
- return;
- }
-
- if (lpm_callback) {
- sdio_al_dev->lpm_callback = lpm_callback;
- lpm_callback((void *)sdio_al_dev,
- sdio_al_dev->is_ok_to_sleep);
- }
-
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
- "registered for wakeup callback\n", __func__,
- sdio_al_dev->host->index);
-}
-
-void sdio_al_unregister_lpm_cb(void *device_handle)
-{
- struct sdio_al_device *sdio_al_dev =
- (struct sdio_al_device *) device_handle;
-
- if (!sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - "
- "device_handle is NULL\n", __func__);
- return;
- }
-
- sdio_al_dev->lpm_callback = NULL;
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - device %d "
- "unregister for wakeup callback\n", __func__,
- sdio_al_dev->host->index);
-}
-
-static void sdio_al_vote_for_sleep(struct sdio_al_device *sdio_al_dev,
- int is_vote_for_sleep)
-{
- pr_debug(MODULE_NAME ": %s()", __func__);
-
- if (!sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - sdio_al_dev"
- " is NULL\n", __func__);
- return;
- }
-
- if (is_vote_for_sleep) {
- pr_debug(MODULE_NAME ": %s - sdio vote for Sleep", __func__);
- wake_unlock(&sdio_al_dev->wake_lock);
- } else {
- pr_debug(MODULE_NAME ": %s - sdio vote against sleep",
- __func__);
- wake_lock(&sdio_al_dev->wake_lock);
- }
-
- if (sdio_al_dev->lpm_callback != NULL) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": %s - "
- "is_vote_for_sleep=%d for card#%d, "
- "calling callback...", __func__,
- is_vote_for_sleep,
- sdio_al_dev->host->index);
- sdio_al_dev->lpm_callback((void *)sdio_al_dev,
- is_vote_for_sleep);
- }
-}
-
-/**
- * Write SDIO-Client lpm information
- * Should only be called with host claimed.
- */
-static int write_lpm_info(struct sdio_al_device *sdio_al_dev)
-{
- struct sdio_func *lpm_func = NULL;
- int offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
- sizeof(struct peer_sdioc_channel_config) *
- sdio_al_dev->lpm_chan+
- offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
- int ret;
-
- if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
- "lpm_chan for card %d\n",
- sdio_al_dev->host->index);
- return -EINVAL;
- }
-
- if (!sdio_al_dev->card ||
- !sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1]) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": NULL card or lpm_func\n");
- return -ENODEV;
- }
- lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->lpm_chan+1];
-
- pr_debug(MODULE_NAME ":write_lpm_info is_ok_to_sleep=%d, device %d\n",
- sdio_al_dev->is_ok_to_sleep,
- sdio_al_dev->host->index);
-
- ret = sdio_memcpy_toio(lpm_func, SDIOC_SW_MAILBOX_ADDR+offset,
- &sdio_al_dev->is_ok_to_sleep, sizeof(u32));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
- "write lpm info for card %d\n",
- sdio_al_dev->host->index);
- return ret;
- }
-
- return 0;
-}
-
-/* Set inactivity counter to intial value to allow clients come up */
-static inline void start_inactive_time(struct sdio_al_device *sdio_al_dev)
-{
- sdio_al_dev->inactivity_time = jiffies +
- msecs_to_jiffies(INITIAL_INACTIVITY_TIME_MSEC);
-}
-
-static inline void restart_inactive_time(struct sdio_al_device *sdio_al_dev)
-{
- sdio_al_dev->inactivity_time = jiffies +
- msecs_to_jiffies(INACTIVITY_TIME_MSEC);
-}
-
-static inline int is_inactive_time_expired(struct sdio_al_device *sdio_al_dev)
-{
- return time_after(jiffies, sdio_al_dev->inactivity_time);
-}
-
-
-static int is_user_irq_enabled(struct sdio_al_device *sdio_al_dev,
- int func_num)
-{
- int ret = 0;
- struct sdio_func *func1;
- u32 user_irq = 0;
- u32 addr = 0;
- u32 offset = 0;
- u32 masked_user_irq = 0;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return 0;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- if (func_num < 4) {
- addr = FUNC_1_4_USER_IRQ_ADDR;
- offset = func_num * 8;
- } else {
- addr = FUNC_5_7_USER_IRQ_ADDR;
- offset = (func_num - 4) * 8;
- }
-
- user_irq = sdio_readl(func1, addr, &ret);
- if (ret) {
- pr_debug(MODULE_NAME ":read_user_irq fail\n");
- return 0;
- }
-
- masked_user_irq = (user_irq >> offset) && 0xFF;
- if (masked_user_irq == 0x1) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":user_irq "
- "enabled\n");
- return 1;
- }
-
- return 0;
-}
-
-static void sdio_al_sleep(struct sdio_al_device *sdio_al_dev,
- struct mmc_host *host)
-{
- int i;
-
- /* Go to sleep */
- pr_debug(MODULE_NAME ":Inactivity timer expired."
- " Going to sleep\n");
- /* Stop mailbox timer */
- stop_and_del_timer(sdio_al_dev);
- /* Make sure we get interrupt for non-packet-mode right away */
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
- if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
- (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
- pr_debug(MODULE_NAME ":continue for channel %s in"
- " state %d\n", ch->name, ch->state);
- continue;
- }
- if (ch->is_packet_mode == false) {
- ch->read_threshold = LOW_LATENCY_THRESHOLD;
- set_pipe_threshold(sdio_al_dev,
- ch->rx_pipe_index,
- ch->read_threshold);
- }
- }
- /* Prevent modem to go to sleep until we get the PROG_DONE on
- the dummy CMD52 */
- msmsdcc_set_pwrsave(sdio_al_dev->host, 0);
- /* Mark HOST_OK_TOSLEEP */
- sdio_al_dev->is_ok_to_sleep = 1;
- write_lpm_info(sdio_al_dev);
-
- msmsdcc_lpm_enable(host);
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Finished sleep sequence"
- " for card %d. Sleep now.\n",
- sdio_al_dev->host->index);
- /* Release wakelock */
- sdio_al_vote_for_sleep(sdio_al_dev, 1);
-}
-
-
-/**
- * Read SDIO-Client Mailbox from Function#1.thresh_pipe
- *
- * The mailbox contain the bytes available per pipe,
- * and the End-Of-Transfer indication per pipe (if available).
- *
- * WARNING: Each time the Mailbox is read from the client, the
- * read_bytes_avail is incremented with another pending
- * transfer. Therefore, a pending rx-packet should be added to a
- * list before the next read of the mailbox.
- *
- * This function should run from a workqueue context since it
- * notifies the clients.
- *
- * This function assumes that sdio_al_claim_mutex was called before
- * calling it.
- *
- */
-static int read_mailbox(struct sdio_al_device *sdio_al_dev, int from_isr)
-{
- int ret;
- struct sdio_func *func1 = NULL;
- struct sdio_mailbox *mailbox = sdio_al_dev->mailbox;
- struct mmc_host *host = sdio_al_dev->host;
- u32 new_write_avail = 0;
- u32 old_write_avail = 0;
- u32 any_read_avail = 0;
- u32 any_write_pending = 0;
- int i;
- u32 rx_notify_bitmask = 0;
- u32 tx_notify_bitmask = 0;
- u32 eot_pipe = 0;
- u32 thresh_pipe = 0;
- u32 overflow_pipe = 0;
- u32 underflow_pipe = 0;
- u32 thresh_intr_mask = 0;
- int is_closing = 0;
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- return 0;
- }
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- pr_debug(MODULE_NAME ":start %s from_isr = %d for card %d.\n"
- , __func__, from_isr, sdio_al_dev->host->index);
-
- pr_debug(MODULE_NAME ":before sdio_memcpy_fromio.\n");
- memset(mailbox, 0, sizeof(struct sdio_mailbox));
- ret = sdio_memcpy_fromio(func1, mailbox,
- HW_MAILBOX_ADDR, sizeof(*mailbox));
- pr_debug(MODULE_NAME ":after sdio_memcpy_fromio.\n");
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to read "
- "Mailbox for card %d, goto error state\n",
- sdio_al_dev->host->index);
- sdio_al_get_into_err_state(sdio_al_dev);
- goto exit_err;
- }
-
- eot_pipe = (mailbox->eot_pipe_0_7) |
- (mailbox->eot_pipe_8_15<<8);
- thresh_pipe = (mailbox->thresh_above_limit_pipe_0_7) |
- (mailbox->thresh_above_limit_pipe_8_15<<8);
-
- overflow_pipe = (mailbox->overflow_pipe_0_7) |
- (mailbox->overflow_pipe_8_15<<8);
- underflow_pipe = mailbox->underflow_pipe_0_7 |
- (mailbox->underflow_pipe_8_15<<8);
- thresh_intr_mask =
- (mailbox->mask_thresh_above_limit_pipe_0_7) |
- (mailbox->mask_thresh_above_limit_pipe_8_15<<8);
-
- if (overflow_pipe || underflow_pipe)
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Mailbox ERROR "
- "overflow=0x%x, underflow=0x%x\n",
- overflow_pipe, underflow_pipe);
-
- /* In case of modem reset we would like to read the daya from the modem
- to clear the interrupts but do not process it */
- if (sdio_al_dev->state != CARD_INSERTED) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_device"
- " (card %d) is in invalid state %d\n",
- sdio_al_dev->host->index,
- sdio_al_dev->state);
- return -ENODEV;
- }
-
- pr_debug(MODULE_NAME ":card %d: eot=0x%x, thresh=0x%x\n",
- sdio_al_dev->host->index,
- eot_pipe, thresh_pipe);
-
- /* Scan for Rx Packets available and update read available bytes */
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
- u32 old_read_avail;
- u32 read_avail;
- u32 new_packet_size = 0;
-
- if (ch->state == SDIO_CHANNEL_STATE_CLOSING)
- is_closing = true; /* used to prevent sleep */
-
- old_read_avail = ch->read_avail;
- read_avail = mailbox->pipe_bytes_avail[ch->rx_pipe_index];
-
- if ((ch->state == SDIO_CHANNEL_STATE_CLOSED) &&
- (read_avail > 0)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":%s: Invalid read_avail 0x%x, for CLOSED ch %s\n",
- __func__, read_avail, ch->name);
- sdio_read_from_closed_ch(ch, read_avail);
- }
- if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
- (ch->state != SDIO_CHANNEL_STATE_CLOSING))
- continue;
-
- if (read_avail > INVALID_DATA_AVAILABLE) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":Invalid read_avail 0x%x for pipe %d\n",
- read_avail, ch->rx_pipe_index);
- continue;
- }
- any_read_avail |= read_avail | old_read_avail;
- ch->statistics.last_any_read_avail = any_read_avail;
- ch->statistics.last_read_avail = read_avail;
- ch->statistics.last_old_read_avail = old_read_avail;
-
- if (ch->is_packet_mode) {
- if ((eot_pipe & (1<<ch->rx_pipe_index)) &&
- sdio_al_dev->print_after_interrupt) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
- ":Interrupt on ch %s, "
- "card %d", ch->name,
- sdio_al_dev->host->index);
- }
- new_packet_size = check_pending_rx_packet(ch, eot_pipe);
- } else {
- if ((thresh_pipe & (1<<ch->rx_pipe_index)) &&
- sdio_al_dev->print_after_interrupt) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME
- ":Interrupt on ch %s, "
- "card %d", ch->name,
- sdio_al_dev->host->index);
- }
- ch->read_avail = read_avail;
-
- /*
- * Restore default thresh for non packet channels.
- * in case it IS low latency channel then read_threshold
- * and def_read_threshold are both
- * LOW_LATENCY_THRESHOLD
- */
- if ((ch->read_threshold != ch->def_read_threshold) &&
- (read_avail >= ch->threshold_change_cnt)) {
- if (!ch->is_low_latency_ch) {
- ch->read_threshold =
- ch->def_read_threshold;
- set_pipe_threshold(sdio_al_dev,
- ch->rx_pipe_index,
- ch->read_threshold);
- }
- }
- }
-
- if ((ch->is_packet_mode) && (new_packet_size > 0)) {
- rx_notify_bitmask |= (1<<ch->num);
- ch->statistics.total_notifs++;
- }
-
- if ((!ch->is_packet_mode) && (ch->read_avail > 0) &&
- (old_read_avail == 0)) {
- rx_notify_bitmask |= (1<<ch->num);
- ch->statistics.total_notifs++;
- }
- }
- sdio_al_dev->print_after_interrupt = 0;
-
- /* Update Write available */
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
- if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
- (ch->state != SDIO_CHANNEL_STATE_CLOSING))
- continue;
-
- new_write_avail = mailbox->pipe_bytes_avail[ch->tx_pipe_index];
-
- if (new_write_avail > INVALID_DATA_AVAILABLE) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":Invalid write_avail 0x%x for pipe %d\n",
- new_write_avail, ch->tx_pipe_index);
- continue;
- }
-
- old_write_avail = ch->write_avail;
- ch->write_avail = new_write_avail;
-
- if ((old_write_avail <= ch->min_write_avail) &&
- (new_write_avail >= ch->min_write_avail))
- tx_notify_bitmask |= (1<<ch->num);
-
- /* There is not enough write avail for this channel.
- We need to keep reading mailbox to wait for the appropriate
- write avail and cannot sleep. Ignore SMEM channel that has
- only one direction. */
- if (strncmp(ch->name, "SDIO_SMEM", CHANNEL_NAME_SIZE))
- any_write_pending |=
- (new_write_avail < ch->ch_config.max_tx_threshold);
- }
- /* notify clients */
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
- if ((ch->state != SDIO_CHANNEL_STATE_OPEN) ||
- (ch->notify == NULL))
- continue;
-
- if (rx_notify_bitmask & (1<<ch->num))
- ch->notify(ch->priv,
- SDIO_EVENT_DATA_READ_AVAIL);
-
- if (tx_notify_bitmask & (1<<ch->num))
- ch->notify(ch->priv,
- SDIO_EVENT_DATA_WRITE_AVAIL);
- }
-
-
- if ((rx_notify_bitmask == 0) && (tx_notify_bitmask == 0) &&
- !any_read_avail && !any_write_pending) {
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Nothing to "
- "Notify for card %d, is_closing=%d\n",
- sdio_al_dev->host->index, is_closing);
- if (is_closing)
- restart_inactive_time(sdio_al_dev);
- else if (is_inactive_time_expired(sdio_al_dev))
- sdio_al_sleep(sdio_al_dev, host);
- } else {
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":Notify bitmask"
- " for card %d rx=0x%x, tx=0x%x.\n",
- sdio_al_dev->host->index,
- rx_notify_bitmask, tx_notify_bitmask);
- /* Restart inactivity timer if any activity on the channel */
- restart_inactive_time(sdio_al_dev);
- }
-
- pr_debug(MODULE_NAME ":end %s.\n", __func__);
-
-exit_err:
- return ret;
-}
-
-/**
- * Check pending rx packet when reading the mailbox.
- */
-static u32 check_pending_rx_packet(struct sdio_channel *ch, u32 eot)
-{
- u32 rx_pending;
- u32 rx_avail;
- u32 new_packet_size = 0;
- struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
-
-
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
- " for channel %s\n", ch->name);
- return -EINVAL;
- }
-
- mutex_lock(&ch->ch_lock);
-
- rx_pending = ch->rx_pending_bytes;
- rx_avail = sdio_al_dev->mailbox->pipe_bytes_avail[ch->rx_pipe_index];
-
- pr_debug(MODULE_NAME ":pipe %d of card %d rx_avail=0x%x, "
- "rx_pending=0x%x\n",
- ch->rx_pipe_index, sdio_al_dev->host->index, rx_avail,
- rx_pending);
-
-
- /* new packet detected */
- if (eot & (1<<ch->rx_pipe_index)) {
- struct rx_packet_size *p = NULL;
- new_packet_size = rx_avail - rx_pending;
-
- if ((rx_avail <= rx_pending)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Invalid new packet size."
- " rx_avail=%d.\n", rx_avail);
- new_packet_size = 0;
- goto exit_err;
- }
-
- p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (p == NULL) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": failed to allocate item for "
- "rx_pending list. rx_avail=%d, "
- "rx_pending=%d.\n",
- rx_avail, rx_pending);
- new_packet_size = 0;
- goto exit_err;
- }
- p->size = new_packet_size;
- /* Add new packet as last */
- list_add_tail(&p->list, &ch->rx_size_list_head);
- ch->rx_pending_bytes += new_packet_size;
-
- if (ch->read_avail == 0)
- ch->read_avail = new_packet_size;
- }
-
-exit_err:
- mutex_unlock(&ch->ch_lock);
-
- return new_packet_size;
-}
-
-
-
-/**
- * Remove first pending packet from the list.
- */
-static u32 remove_handled_rx_packet(struct sdio_channel *ch)
-{
- struct rx_packet_size *p = NULL;
-
- mutex_lock(&ch->ch_lock);
-
- ch->rx_pending_bytes -= ch->read_avail;
-
- if (!list_empty(&ch->rx_size_list_head)) {
- p = list_first_entry(&ch->rx_size_list_head,
- struct rx_packet_size, list);
- list_del(&p->list);
- kfree(p);
- } else {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: ch "
- "%s: unexpected empty list!!\n",
- __func__, ch->name);
- }
-
- if (list_empty(&ch->rx_size_list_head)) {
- ch->read_avail = 0;
- } else {
- p = list_first_entry(&ch->rx_size_list_head,
- struct rx_packet_size, list);
- ch->read_avail = p->size;
- }
-
- mutex_unlock(&ch->ch_lock);
-
- return ch->read_avail;
-}
-
-
-/**
- * Bootloader worker function.
- *
- * @note: clear the bootloader_done flag only after reading the
- * mailbox, to ignore more requests while reading the mailbox.
- */
-static void boot_worker(struct work_struct *work)
-{
- int ret = 0;
- int func_num = 0;
- int i;
- struct sdio_al_device *sdio_al_dev = NULL;
- struct sdio_al_work *sdio_al_work = container_of(work,
- struct sdio_al_work,
- work);
-
- if (sdio_al_work == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "sdio_al_work\n", __func__);
- return;
- }
-
- sdio_al_dev = sdio_al_work->sdio_al_dev;
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "sdio_al_dev\n", __func__);
- return;
- }
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Bootloader Worker Started"
- ", wait for bootloader_done event..\n");
- wait_event(sdio_al_dev->wait_mbox,
- sdio_al_dev->bootloader_done);
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":Got bootloader_done "
- "event..\n");
- /* Do polling until MDM is up */
- for (i = 0; i < 5000; ++i) {
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return;
- if (is_user_irq_enabled(sdio_al_dev, func_num)) {
- sdio_al_release_mutex(sdio_al_dev, __func__);
- sdio_al_dev->bootloader_done = 0;
- ret = sdio_al_client_setup(sdio_al_dev);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": sdio_al_client_setup failed, "
- "for card %d ret=%d\n",
- sdio_al_dev->host->index, ret);
- sdio_al_get_into_err_state(sdio_al_dev);
- }
- goto done;
- }
- sdio_al_release_mutex(sdio_al_dev, __func__);
- msleep(100);
- }
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Timeout waiting for "
- "user_irq for card %d\n",
- sdio_al_dev->host->index);
- sdio_al_get_into_err_state(sdio_al_dev);
-
-done:
- pr_debug(MODULE_NAME ":Boot Worker for card %d Exit!\n",
- sdio_al_dev->host->index);
-}
-
-/**
- * Worker function.
- *
- * @note: clear the ask_mbox flag only after
- * reading the mailbox, to ignore more requests while
- * reading the mailbox.
- */
-static void worker(struct work_struct *work)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = NULL;
- struct sdio_al_work *sdio_al_work = container_of(work,
- struct sdio_al_work,
- work);
- if (sdio_al_work == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
- "sdio_al_work\n");
- return;
- }
-
- sdio_al_dev = sdio_al_work->sdio_al_dev;
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": worker: NULL "
- "sdio_al_dev\n");
- return;
- }
- pr_debug(MODULE_NAME ":Worker Started..\n");
- while ((sdio_al_dev->is_ready) && (ret == 0)) {
- pr_debug(MODULE_NAME ":Wait for read mailbox request..\n");
- wait_event(sdio_al_dev->wait_mbox, sdio_al_dev->ask_mbox);
- if (!sdio_al_dev->is_ready)
- break;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- break;
- if (sdio_al_dev->is_ok_to_sleep) {
- ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
- if (ret) {
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return;
- }
- }
- ret = read_mailbox(sdio_al_dev, false);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- sdio_al_dev->ask_mbox = false;
- }
-
- pr_debug(MODULE_NAME ":Worker Exit!\n");
-}
-
-/**
- * Write command using CMD54 rather than CMD53.
- * Writing with CMD54 generate EOT interrupt at the
- * SDIO-Client.
- * Based on mmc_io_rw_extended()
- */
-static int sdio_write_cmd54(struct mmc_card *card, unsigned fn,
- unsigned addr, const u8 *buf,
- unsigned blocks, unsigned blksz)
-{
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
- struct scatterlist sg;
- int incr_addr = 1; /* MUST */
- int write = 1;
-
- BUG_ON(!card);
- BUG_ON(fn > 7);
- BUG_ON(blocks == 1 && blksz > 512);
- WARN_ON(blocks == 0);
- WARN_ON(blksz == 0);
-
- write = true;
- pr_debug(MODULE_NAME ":sdio_write_cmd54()"
- "fn=%d,buf=0x%x,blocks=%d,blksz=%d\n",
- fn, (u32) buf, blocks, blksz);
-
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- cmd.opcode = SD_IO_RW_EXTENDED_QCOM;
-
- cmd.arg = write ? 0x80000000 : 0x00000000;
- cmd.arg |= fn << 28;
- cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
- cmd.arg |= addr << 9;
- if (blocks == 1 && blksz <= 512)
- cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
- else
- cmd.arg |= 0x08000000 | blocks; /* block mode */
- cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
-
- data.blksz = blksz;
- data.blocks = blocks;
- data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, buf, blksz * blocks);
-
- mmc_set_data_timeout(&data, card);
-
- mmc_wait_for_req(card->host, &mrq);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- if (mmc_host_is_spi(card->host)) {
- /* host driver already reported errors */
- } else {
- if (cmd.resp[0] & R5_ERROR) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
- ":%s: R5_ERROR for card %d",
- __func__, card->host->index);
- return -EIO;
- }
- if (cmd.resp[0] & R5_FUNCTION_NUMBER) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
- ":%s: R5_FUNCTION_NUMBER for card %d",
- __func__, card->host->index);
- return -EINVAL;
- }
- if (cmd.resp[0] & R5_OUT_OF_RANGE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME
- ":%s: R5_OUT_OF_RANGE for card %d",
- __func__, card->host->index);
- return -ERANGE;
- }
- }
-
- return 0;
-}
-
-
-/**
- * Write data to channel.
- * Handle different data size types.
- *
- */
-static int sdio_ch_write(struct sdio_channel *ch, const u8 *buf, u32 len)
-{
- int ret = 0;
- unsigned blksz = ch->func->cur_blksize;
- int blocks = len / blksz;
- int remain_bytes = len % blksz;
- struct mmc_card *card = NULL;
- u32 fn = ch->func->num;
-
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
-
- if (!ch->sdio_al_dev) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "sdio_al_dev\n", __func__);
- return -ENODEV;
- }
-
- if (len == 0) {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":channel "
- "%s trying to write 0 bytes\n", ch->name);
- return -EINVAL;
- }
-
- card = ch->func->card;
-
- if (remain_bytes) {
- /* CMD53 */
- if (blocks) {
- ret = sdio_memcpy_toio(ch->func, PIPE_TX_FIFO_ADDR,
- (void *) buf, blocks*blksz);
- if (ret != 0) {
- sdio_al_loge(ch->sdio_al_dev->dev_log,
- MODULE_NAME ":%s: sdio_memcpy_toio "
- "failed for channel %s\n",
- __func__, ch->name);
- sdio_al_get_into_err_state(ch->sdio_al_dev);
- return ret;
- }
- }
-
- buf += (blocks*blksz);
-
- ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
- buf, 1, remain_bytes);
- } else {
- ret = sdio_write_cmd54(card, fn, PIPE_TX_FIFO_ADDR,
- buf, blocks, blksz);
- }
-
- if (ret != 0) {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "sdio_write_cmd54 failed for channel %s\n",
- __func__, ch->name);
- ch->sdio_al_dev->is_err = true;
- return ret;
- }
-
- return ret;
-}
-
-static int sdio_al_bootloader_completed(void)
-{
- int i;
-
- pr_debug(MODULE_NAME ":sdio_al_bootloader_completed was called\n");
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
- struct sdio_al_device *dev = NULL;
- if (sdio_al->devices[i] == NULL)
- continue;
- dev = sdio_al->devices[i];
- dev->bootloader_done = 1;
- wake_up(&dev->wait_mbox);
- }
-
- return 0;
-}
-
-static int sdio_al_wait_for_bootloader_comp(struct sdio_al_device *sdio_al_dev)
-{
- int ret = 0;
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- /*
- * Enable function 0 interrupt mask to allow 9k to raise this interrupt
- * in power-up. When sdio_downloader will notify its completion
- * we will poll on this interrupt to wait for 9k power-up
- */
- ret = enable_mask_irq(sdio_al_dev, 0, 1, 0);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Enable_mask_irq for card %d failed, "
- "ret=%d\n",
- sdio_al_dev->host->index, ret);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return ret;
- }
-
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- /*
- * Start bootloader worker that will wait for the bootloader
- * completion
- */
- sdio_al_dev->boot_work.sdio_al_dev = sdio_al_dev;
- INIT_WORK(&sdio_al_dev->boot_work.work, boot_worker);
- sdio_al_dev->bootloader_done = 0;
- queue_work(sdio_al_dev->workqueue, &sdio_al_dev->boot_work.work);
-
- return 0;
-}
-
-static int sdio_al_bootloader_setup(void)
-{
- int ret = 0;
- struct sdio_al_device *bootloader_dev = sdio_al->bootloader_dev;
- struct sdio_func *func1 = NULL;
-
- if (sdio_al_claim_mutex_and_verify_dev(bootloader_dev, __func__))
- return -ENODEV;
-
- if (bootloader_dev->flashless_boot_on) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":Already "
- "in boot process.\n");
- sdio_al_release_mutex(bootloader_dev, __func__);
- return 0;
- }
-
- bootloader_dev->sdioc_boot_sw_header
- = kzalloc(sizeof(*bootloader_dev->sdioc_boot_sw_header),
- GFP_KERNEL);
- if (bootloader_dev->sdioc_boot_sw_header == NULL) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
- "allocate sdioc boot sw header.\n");
- sdio_al_release_mutex(bootloader_dev, __func__);
- return -ENOMEM;
- }
-
- if (sdio_al_verify_func1(bootloader_dev, __func__)) {
- sdio_al_release_mutex(bootloader_dev, __func__);
- goto exit_err;
- }
- func1 = bootloader_dev->card->sdio_func[0];
-
- ret = sdio_memcpy_fromio(func1,
- bootloader_dev->sdioc_boot_sw_header,
- SDIOC_SW_HEADER_ADDR,
- sizeof(struct peer_sdioc_boot_sw_header));
- if (ret) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":fail to "
- "read sdioc boot sw header.\n");
- sdio_al_release_mutex(bootloader_dev, __func__);
- goto exit_err;
- }
-
- if (bootloader_dev->sdioc_boot_sw_header->signature !=
- (u32) PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ":invalid "
- "mailbox signature 0x%x.\n",
- bootloader_dev->sdioc_boot_sw_header->signature);
- sdio_al_release_mutex(bootloader_dev, __func__);
- ret = -EINVAL;
- goto exit_err;
- }
-
- /* Upper byte has to be equal - no backward compatibility for unequal */
- if ((bootloader_dev->sdioc_boot_sw_header->version >> 16) !=
- (sdio_al->pdata->peer_sdioc_boot_version_major)) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME ": HOST(0x%x)"
- " and CLIENT(0x%x) SDIO_AL BOOT VERSION don't match\n",
- ((sdio_al->pdata->peer_sdioc_boot_version_major<<16)+
- sdio_al->pdata->peer_sdioc_boot_version_minor),
- bootloader_dev->sdioc_boot_sw_header->version);
- sdio_al_release_mutex(bootloader_dev, __func__);
- ret = -EIO;
- goto exit_err;
- }
-
- sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ": SDIOC BOOT SW "
- "version 0x%x\n",
- bootloader_dev->sdioc_boot_sw_header->version);
-
- bootloader_dev->flashless_boot_on = true;
-
- sdio_al_release_mutex(bootloader_dev, __func__);
-
- ret = sdio_al_wait_for_bootloader_comp(bootloader_dev);
- if (ret) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
- ": sdio_al_wait_for_bootloader_comp failed, "
- "err=%d\n", ret);
- goto exit_err;
- }
-
- ret = sdio_downloader_setup(bootloader_dev->card, 1,
- bootloader_dev->sdioc_boot_sw_header->boot_ch_num,
- sdio_al_bootloader_completed);
-
- if (ret) {
- sdio_al_loge(bootloader_dev->dev_log, MODULE_NAME
- ": sdio_downloader_setup failed, err=%d\n", ret);
- goto exit_err;
- }
-
- sdio_al_logi(bootloader_dev->dev_log, MODULE_NAME ":In Flashless boot,"
- " waiting for its completion\n");
-
-
-exit_err:
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":free "
- "sdioc_boot_sw_header.\n");
- kfree(bootloader_dev->sdioc_boot_sw_header);
- bootloader_dev->sdioc_boot_sw_header = NULL;
- bootloader_dev = NULL;
-
- return ret;
-}
-
-
-/**
- * Read SDIO-Client software header
- *
- */
-static int read_sdioc_software_header(struct sdio_al_device *sdio_al_dev,
- struct peer_sdioc_sw_header *header)
-{
- int ret;
- int i;
- int test_version = 0;
- int sdioc_test_version = 0;
- struct sdio_func *func1 = NULL;
-
- pr_debug(MODULE_NAME ":reading sdioc sw header.\n");
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
-
- func1 = sdio_al_dev->card->sdio_func[0];
-
- ret = sdio_memcpy_fromio(func1, header,
- SDIOC_SW_HEADER_ADDR, sizeof(*header));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
- "sdioc sw header.\n");
- goto exit_err;
- }
-
- if (header->signature == (u32)PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
- "unittest signature. 0x%x\n",
- header->signature);
- sdio_al->unittest_mode = true;
- /* Verify test code compatibility with the modem */
- sdioc_test_version = (header->version & 0xFF00) >> 8;
- test_version = sdio_al->pdata->peer_sdioc_version_minor >> 8;
- if (test_version != sdioc_test_version) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": HOST(0x%x) and CLIENT(0x%x) "
- "testing VERSION don't match\n",
- test_version,
- sdioc_test_version);
- msleep(500);
- BUG();
- }
- }
-
- if ((header->signature != (u32) PEER_SDIOC_SW_MAILBOX_SIGNATURE) &&
- (header->signature != (u32) PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW "
- "invalid signature. 0x%x\n", header->signature);
- goto exit_err;
- }
- /* Upper byte has to be equal - no backward compatibility for unequal */
- sdio_al->sdioc_major = header->version >> 16;
- if (sdio_al->pdata->allow_sdioc_version_major_2) {
- if ((sdio_al->sdioc_major !=
- sdio_al->pdata->peer_sdioc_version_major) &&
- (sdio_al->sdioc_major != PEER_SDIOC_OLD_VERSION_MAJOR)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": HOST(0x%x) and CLIENT(0x%x) "
- "SDIO_AL VERSION don't match\n",
- ((sdio_al->pdata->peer_sdioc_version_major<<16)+
- sdio_al->pdata->peer_sdioc_version_minor),
- header->version);
- goto exit_err;
- }
- } else {
- if (sdio_al->sdioc_major !=
- sdio_al->pdata->peer_sdioc_version_major) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": HOST(0x%x) and CLIENT(0x%x) "
- "SDIO_AL VERSION don't match\n",
- ((sdio_al->pdata->peer_sdioc_version_major<<16)+
- sdio_al->pdata->peer_sdioc_version_minor),
- header->version);
- goto exit_err;
- }
- }
- sdio_al_dev->ch_close_supported = (header->version & 0x000F) >=
- (sdio_al->pdata->peer_sdioc_version_minor & 0xF);
-
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":SDIOC SW version 0x%x,"
- " sdio_al major 0x%x minor 0x%x\n", header->version,
- sdio_al->sdioc_major,
- sdio_al->pdata->peer_sdioc_version_minor);
-
- sdio_al_dev->flashless_boot_on = false;
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
- /* Set default values */
- ch->read_threshold = DEFAULT_READ_THRESHOLD;
- ch->write_threshold = DEFAULT_WRITE_THRESHOLD;
- ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD;
- ch->is_packet_mode = true;
- ch->peer_tx_buf_size = DEFAULT_PEER_TX_BUF_SIZE;
- ch->poll_delay_msec = 0;
-
- ch->num = i;
- ch->func = NULL;
- ch->rx_pipe_index = ch->num*2;
- ch->tx_pipe_index = ch->num*2+1;
-
- memset(ch->name, 0, sizeof(ch->name));
-
- if (header->channel_names[i][0]) {
- memcpy(ch->name, SDIO_PREFIX,
- strlen(SDIO_PREFIX));
- memcpy(ch->name + strlen(SDIO_PREFIX),
- header->channel_names[i],
- PEER_CHANNEL_NAME_SIZE);
-
- ch->state = SDIO_CHANNEL_STATE_IDLE;
- ch->sdio_al_dev = sdio_al_dev;
- if (sdio_al_dev->card->sdio_func[ch->num+1]) {
- ch->func =
- sdio_al_dev->card->sdio_func[ch->num+1];
- } else {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": NULL func for channel %s\n",
- ch->name);
- goto exit_err;
- }
- } else {
- ch->state = SDIO_CHANNEL_STATE_INVALID;
- }
-
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Channel=%s, "
- "state=%d\n", ch->name, ch->state);
- }
-
- return 0;
-
-exit_err:
- sdio_al_get_into_err_state(sdio_al_dev);
- memset(header, 0, sizeof(*header));
-
- return -EIO;
-}
-
-/**
- * Read SDIO-Client channel configuration
- *
- */
-static int read_sdioc_channel_config(struct sdio_channel *ch)
-{
- int ret;
- struct peer_sdioc_sw_mailbox *sw_mailbox = NULL;
- struct peer_sdioc_channel_config *ch_config = NULL;
- struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
-
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL sdio_al_dev"
- " for channel %s\n", ch->name);
- return -EINVAL;
- }
-
- if (sdio_al_dev->sdioc_sw_header->version == 0)
- return -1;
-
- pr_debug(MODULE_NAME ":reading sw mailbox %s channel.\n", ch->name);
-
- sw_mailbox = kzalloc(sizeof(*sw_mailbox), GFP_KERNEL);
- if (sw_mailbox == NULL)
- return -ENOMEM;
-
- ret = sdio_memcpy_fromio(ch->func, sw_mailbox,
- SDIOC_SW_MAILBOX_ADDR, sizeof(*sw_mailbox));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
- "sw mailbox.\n");
- goto exit_err;
- }
-
- ch_config = &sw_mailbox->ch_config[ch->num];
- memcpy(&ch->ch_config, ch_config,
- sizeof(struct peer_sdioc_channel_config));
-
- if (!ch_config->is_ready) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sw mailbox "
- "channel not ready.\n");
- goto exit_err;
- }
-
- ch->read_threshold = LOW_LATENCY_THRESHOLD;
- ch->is_low_latency_ch = ch_config->is_low_latency_ch;
- /* Threshold on 50% of the maximum size , sdioc uses double-buffer */
- ch->write_threshold = (ch_config->max_tx_threshold * 5) / 10;
- ch->threshold_change_cnt = ch->ch_config.max_rx_threshold -
- ch->read_threshold + THRESHOLD_CHANGE_EXTRA_BYTES;
-
- if (ch->is_low_latency_ch)
- ch->def_read_threshold = LOW_LATENCY_THRESHOLD;
- else /* Aggregation up to 90% of the maximum size */
- ch->def_read_threshold = (ch_config->max_rx_threshold * 9) / 10;
-
- ch->is_packet_mode = ch_config->is_packet_mode;
- if (!ch->is_packet_mode) {
- ch->poll_delay_msec = DEFAULT_POLL_DELAY_NOPACKET_MSEC;
- ch->min_write_avail = DEFAULT_MIN_WRITE_THRESHOLD_STREAMING;
- }
- /* The max_packet_size is set by the modem in version 3 and on */
- if (sdio_al->sdioc_major > PEER_SDIOC_OLD_VERSION_MAJOR)
- ch->min_write_avail = ch_config->max_packet_size;
-
- if (ch->min_write_avail > ch->write_threshold)
- ch->min_write_avail = ch->write_threshold;
-
- CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":ch %s "
- "read_threshold=%d, write_threshold=%d,"
- " min_write_avail=%d, max_rx_threshold=%d,"
- " max_tx_threshold=%d\n", ch->name, ch->read_threshold,
- ch->write_threshold, ch->min_write_avail,
- ch_config->max_rx_threshold,
- ch_config->max_tx_threshold);
-
- ch->peer_tx_buf_size = ch_config->tx_buf_size;
-
- kfree(sw_mailbox);
-
- return 0;
-
-exit_err:
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":Reading SW Mailbox "
- "error.\n");
- kfree(sw_mailbox);
-
- return -1;
-}
-
-
-/**
- * Enable/Disable EOT interrupt of a pipe.
- *
- */
-static int enable_eot_interrupt(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int enable)
-{
- int ret = 0;
- struct sdio_func *func1;
- u32 mask;
- u32 pipe_mask;
- u32 addr;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- if (pipe_index < 8) {
- addr = PIPES_0_7_IRQ_MASK_ADDR;
- pipe_mask = (1<<pipe_index);
- } else {
- addr = PIPES_8_15_IRQ_MASK_ADDR;
- pipe_mask = (1<<(pipe_index-8));
- }
-
- mask = sdio_readl(func1, addr, &ret);
- if (ret) {
- pr_debug(MODULE_NAME ":enable_eot_interrupt fail\n");
- goto exit_err;
- }
-
- if (enable)
- mask &= (~pipe_mask); /* 0 = enable */
- else
- mask |= (pipe_mask); /* 1 = disable */
-
- sdio_writel(func1, mask, addr, &ret);
-
-exit_err:
- return ret;
-}
-
-
-/**
- * Enable/Disable mask interrupt of a function.
- *
- */
-static int enable_mask_irq(struct sdio_al_device *sdio_al_dev,
- int func_num, int enable, u8 bit_offset)
-{
- int ret = 0;
- struct sdio_func *func1 = NULL;
- u32 mask = 0;
- u32 func_mask = 0;
- u32 addr = 0;
- u32 offset = 0;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- if (func_num < 4) {
- addr = FUNC_1_4_MASK_IRQ_ADDR;
- offset = func_num * 8 + bit_offset;
- } else {
- addr = FUNC_5_7_MASK_IRQ_ADDR;
- offset = (func_num - 4) * 8 + bit_offset;
- }
-
- func_mask = 1<<offset;
-
- mask = sdio_readl(func1, addr, &ret);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "enable_mask_irq fail\n");
- goto exit_err;
- }
-
- if (enable)
- mask &= (~func_mask); /* 0 = enable */
- else
- mask |= (func_mask); /* 1 = disable */
-
- pr_debug(MODULE_NAME ":enable_mask_irq, writing mask = 0x%x\n", mask);
-
- sdio_writel(func1, mask, addr, &ret);
-
-exit_err:
- return ret;
-}
-
-/**
- * Enable/Disable Threshold interrupt of a pipe.
- *
- */
-static int enable_threshold_interrupt(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int enable)
-{
- int ret = 0;
- struct sdio_func *func1;
- u32 mask;
- u32 pipe_mask;
- u32 addr;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- if (pipe_index < 8) {
- addr = PIPES_0_7_IRQ_MASK_ADDR;
- pipe_mask = (1<<pipe_index);
- } else {
- addr = PIPES_8_15_IRQ_MASK_ADDR;
- pipe_mask = (1<<(pipe_index-8));
- }
-
- mask = sdio_readl(func1, addr, &ret);
- if (ret) {
- pr_debug(MODULE_NAME ":enable_threshold_interrupt fail\n");
- goto exit_err;
- }
-
- pipe_mask = pipe_mask<<8; /* Threshold bits 8..15 */
- if (enable)
- mask &= (~pipe_mask); /* 0 = enable */
- else
- mask |= (pipe_mask); /* 1 = disable */
-
- sdio_writel(func1, mask, addr, &ret);
-
-exit_err:
- return ret;
-}
-
-/**
- * Set the threshold to trigger interrupt from SDIO-Card on
- * pipe available bytes.
- *
- */
-static int set_pipe_threshold(struct sdio_al_device *sdio_al_dev,
- int pipe_index, int threshold)
-{
- int ret = 0;
- struct sdio_func *func1;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = sdio_al_dev->card->sdio_func[0];
-
- sdio_writel(func1, threshold,
- PIPES_THRESHOLD_ADDR+pipe_index*4, &ret);
- if (ret)
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "set_pipe_threshold err=%d\n", -ret);
-
- return ret;
-}
-
-/**
- * Enable func w/ retries
- *
- */
-static int sdio_al_enable_func_retry(struct sdio_func *func, const char *name)
-{
- int ret, i;
- for (i = 0; i < 200; i++) {
- ret = sdio_enable_func(func);
- if (ret) {
- pr_debug(MODULE_NAME ":retry enable %s func#%d "
- "ret=%d\n",
- name, func->num, ret);
- msleep(10);
- } else
- break;
- }
-
- return ret;
-}
-
-/**
- * Open Channel
- *
- * 1. Init Channel Context.
- * 2. Init the Channel SDIO-Function.
- * 3. Init the Channel Pipes on Mailbox.
- */
-static int open_channel(struct sdio_channel *ch)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = ch->sdio_al_dev;
-
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL "
- "sdio_al_dev for channel %s\n", ch->name);
- return -EINVAL;
- }
-
- /* Init channel Context */
- /** Func#1 is reserved for mailbox */
- ch->func = sdio_al_dev->card->sdio_func[ch->num+1];
- ch->rx_pipe_index = ch->num*2;
- ch->tx_pipe_index = ch->num*2+1;
- ch->signature = SDIO_AL_SIGNATURE;
-
- ch->total_rx_bytes = 0;
- ch->total_tx_bytes = 0;
-
- ch->write_avail = 0;
- ch->read_avail = 0;
- ch->rx_pending_bytes = 0;
-
- mutex_init(&ch->ch_lock);
-
- pr_debug(MODULE_NAME ":open_channel %s func#%d\n",
- ch->name, ch->func->num);
-
- INIT_LIST_HEAD(&(ch->rx_size_list_head));
-
- /* Init SDIO Function */
- ret = sdio_al_enable_func_retry(ch->func, ch->name);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "sdio_enable_func() err=%d\n", -ret);
- goto exit_err;
- }
-
- /* Note: Patch Func CIS tuple issue */
- ret = sdio_set_block_size(ch->func, SDIO_AL_BLOCK_SIZE);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "sdio_set_block_size()failed, err=%d\n", -ret);
- goto exit_err;
- }
-
- ch->func->max_blksize = SDIO_AL_BLOCK_SIZE;
-
- sdio_set_drvdata(ch->func, ch);
-
- /* Get channel parameters from the peer SDIO-Client */
- read_sdioc_channel_config(ch);
-
- /* Set Pipes Threshold on Mailbox */
- ret = set_pipe_threshold(sdio_al_dev,
- ch->rx_pipe_index, ch->read_threshold);
- if (ret)
- goto exit_err;
- ret = set_pipe_threshold(sdio_al_dev,
- ch->tx_pipe_index, ch->write_threshold);
- if (ret)
- goto exit_err;
-
- /* Set flag before interrupts are enabled to allow notify */
- ch->state = SDIO_CHANNEL_STATE_OPEN;
- pr_debug(MODULE_NAME ":channel %s is in OPEN state now\n", ch->name);
-
- sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
-
- /* lpm mechanism lives under the assumption there is always a timer */
- /* Check if need to start the timer */
- if ((sdio_al_dev->poll_delay_msec) &&
- (sdio_al_dev->is_timer_initialized == false)) {
-
- init_timer(&sdio_al_dev->timer);
- sdio_al_dev->timer.data = (unsigned long) sdio_al_dev;
- sdio_al_dev->timer.function = sdio_al_timer_handler;
- sdio_al_dev->timer.expires = jiffies +
- msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
- add_timer(&sdio_al_dev->timer);
- sdio_al_dev->is_timer_initialized = true;
- }
-
- /* Enable Pipes Interrupts */
- enable_eot_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
- enable_eot_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
-
- enable_threshold_interrupt(sdio_al_dev, ch->rx_pipe_index, true);
- enable_threshold_interrupt(sdio_al_dev, ch->tx_pipe_index, true);
-
-exit_err:
-
- return ret;
-}
-
-/**
- * Ask the worker to read the mailbox.
- */
-static void ask_reading_mailbox(struct sdio_al_device *sdio_al_dev)
-{
- if (!sdio_al_dev->ask_mbox) {
- pr_debug(MODULE_NAME ":ask_reading_mailbox for card %d\n",
- sdio_al_dev->host->index);
- sdio_al_dev->ask_mbox = true;
- wake_up(&sdio_al_dev->wait_mbox);
- }
-}
-
-/**
- * Start the timer
- */
-static void start_timer(struct sdio_al_device *sdio_al_dev)
-{
- if ((sdio_al_dev->poll_delay_msec) &&
- (sdio_al_dev->state == CARD_INSERTED)) {
- sdio_al_dev->timer.expires = jiffies +
- msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
- add_timer(&sdio_al_dev->timer);
- }
-}
-
-/**
- * Restart(postpone) the already working timer
- */
-static void restart_timer(struct sdio_al_device *sdio_al_dev)
-{
- if ((sdio_al_dev->poll_delay_msec) &&
- (sdio_al_dev->state == CARD_INSERTED)) {
- ulong expires = jiffies +
- msecs_to_jiffies(sdio_al_dev->poll_delay_msec);
- mod_timer(&sdio_al_dev->timer, expires);
- }
-}
-
-/**
- * Stop and delete the timer
- */
-static void stop_and_del_timer(struct sdio_al_device *sdio_al_dev)
-{
- if (sdio_al_dev->is_timer_initialized) {
- sdio_al_dev->poll_delay_msec = 0;
- del_timer_sync(&sdio_al_dev->timer);
- }
-}
-
-/**
- * Do the wakup sequence.
- * This function should be called after claiming the host!
- * The caller is responsible for releasing the host.
- *
- * Wake up sequence
- * 1. Get lock
- * 2. Enable wake up function if needed
- * 3. Mark NOT OK to sleep and write it
- * 4. Restore default thresholds
- * 5. Start the mailbox and inactivity timer again
- */
-static int sdio_al_wake_up(struct sdio_al_device *sdio_al_dev,
- u32 not_from_int, struct sdio_channel *ch)
-{
- int ret = 0;
- struct sdio_func *wk_func = NULL;
- unsigned long time_to_wait;
- struct mmc_host *host = sdio_al_dev->host;
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- return -ENODEV;
- }
-
- if (!sdio_al_dev->is_ok_to_sleep) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":card %d "
- "already awake, no need to wake up\n",
- sdio_al_dev->host->index);
- return 0;
- }
-
- /* Wake up sequence */
- if (not_from_int) {
- if (ch) {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
- " card %d (not by interrupt), ch %s",
- sdio_al_dev->host->index,
- ch->name);
- } else {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up"
- " card %d (not by interrupt)",
- sdio_al_dev->host->index);
- }
- } else {
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": Wake up card "
- "%d by interrupt",
- sdio_al_dev->host->index);
- sdio_al_dev->print_after_interrupt = 1;
- }
-
- sdio_al_vote_for_sleep(sdio_al_dev, 0);
-
- msmsdcc_lpm_disable(host);
- msmsdcc_set_pwrsave(host, 0);
- /* Poll the GPIO */
- time_to_wait = jiffies + msecs_to_jiffies(1000);
- while (time_before(jiffies, time_to_wait)) {
- if (sdio_al->pdata->get_mdm2ap_status())
- break;
- udelay(TIME_TO_WAIT_US);
- }
-
- pr_debug(MODULE_NAME ":GPIO mdm2ap_status=%d\n",
- sdio_al->pdata->get_mdm2ap_status());
-
- /* Here get_mdm2ap_status() returning 0 is not an error condition */
- if (sdio_al->pdata->get_mdm2ap_status() == 0)
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ": "
- "get_mdm2ap_status() is 0\n");
-
- /* Enable Wake up Function */
- if (!sdio_al_dev->card ||
- !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": NULL card or wk_func\n");
- return -ENODEV;
- }
- wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
- ret = sdio_al_enable_func_retry(wk_func, "wakeup func");
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "sdio_enable_func() err=%d\n", -ret);
- goto error_exit;
- }
- /* Mark NOT OK_TOSLEEP */
- sdio_al_dev->is_ok_to_sleep = 0;
- ret = write_lpm_info(sdio_al_dev);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": "
- "write_lpm_info() failed, err=%d\n", -ret);
- sdio_al_dev->is_ok_to_sleep = 1;
- sdio_disable_func(wk_func);
- goto error_exit;
- }
- sdio_disable_func(wk_func);
-
- /* Start the timer again*/
- restart_inactive_time(sdio_al_dev);
- sdio_al_dev->poll_delay_msec = get_min_poll_time_msec(sdio_al_dev);
- start_timer(sdio_al_dev);
-
- LPM_DEBUG(sdio_al_dev->dev_log, MODULE_NAME "Finished Wake up sequence"
- " for card %d", sdio_al_dev->host->index);
-
- msmsdcc_set_pwrsave(host, 1);
- pr_debug(MODULE_NAME ":Turn clock off\n");
-
- return ret;
-error_exit:
- sdio_al_vote_for_sleep(sdio_al_dev, 1);
- msmsdcc_set_pwrsave(host, 1);
- WARN_ON(ret);
- sdio_al_get_into_err_state(sdio_al_dev);
- return ret;
-}
-
-
-/**
- * SDIO Function Interrupt handler.
- *
- * Interrupt shall be triggered by SDIO-Client when:
- * 1. End-Of-Transfer (EOT) detected in packet mode.
- * 2. Bytes-available reached the threshold.
- *
- * Reading the mailbox clears the EOT/Threshold interrupt
- * source.
- * The interrupt source should be cleared before this ISR
- * returns. This ISR is called from IRQ Thread and not
- * interrupt, so it may sleep.
- *
- */
-static void sdio_func_irq(struct sdio_func *func)
-{
- struct sdio_al_device *sdio_al_dev = sdio_get_drvdata(func);
-
- pr_debug(MODULE_NAME ":start %s.\n", __func__);
-
- if (sdio_al_dev == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": NULL device");
- return;
- }
-
- if (sdio_al_dev->is_ok_to_sleep)
- sdio_al_wake_up(sdio_al_dev, 0, NULL);
- else
- restart_timer(sdio_al_dev);
-
- read_mailbox(sdio_al_dev, true);
-
- pr_debug(MODULE_NAME ":end %s.\n", __func__);
-}
-
-/**
- * Timer Expire Handler
- *
- */
-static void sdio_al_timer_handler(unsigned long data)
-{
- struct sdio_al_device *sdio_al_dev = (struct sdio_al_device *)data;
- if (sdio_al_dev == NULL) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": NULL "
- "sdio_al_dev for data %lu\n", data);
- return;
- }
- if (sdio_al_dev->state != CARD_INSERTED) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": sdio_al_dev "
- "is in invalid state %d\n", sdio_al_dev->state);
- return;
- }
- pr_debug(MODULE_NAME " Timer Expired\n");
-
- ask_reading_mailbox(sdio_al_dev);
-
- restart_timer(sdio_al_dev);
-}
-
-/**
- * Driver Setup.
- *
- */
-static int sdio_al_setup(struct sdio_al_device *sdio_al_dev)
-{
- int ret = 0;
- struct mmc_card *card = sdio_al_dev->card;
- struct sdio_func *func1 = NULL;
- int i = 0;
- int fn = 0;
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- return -ENODEV;
- func1 = card->sdio_func[0];
-
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":sdio_al_setup for "
- "card %d\n", sdio_al_dev->host->index);
-
- ret = sdio_al->pdata->config_mdm2ap_status(1);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME "Could not "
- "request GPIO\n");
- return ret;
- }
-
- INIT_WORK(&sdio_al_dev->sdio_al_work.work, worker);
- /* disable all pipes interrupts before claim irq.
- since all are enabled by default. */
- for (i = 0 ; i < SDIO_AL_MAX_PIPES; i++) {
- enable_eot_interrupt(sdio_al_dev, i, false);
- enable_threshold_interrupt(sdio_al_dev, i, false);
- }
-
- /* Disable all SDIO Functions before claim irq. */
- for (fn = 1 ; fn <= card->sdio_funcs; fn++)
- sdio_disable_func(card->sdio_func[fn-1]);
-
- sdio_set_drvdata(func1, sdio_al_dev);
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":claim IRQ for card "
- "%d\n", sdio_al_dev->host->index);
-
- ret = sdio_claim_irq(func1, sdio_func_irq);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to claim"
- " IRQ for card %d\n",
- sdio_al_dev->host->index);
- return ret;
- }
-
- sdio_al_dev->is_ready = true;
-
- /* Start worker before interrupt might happen */
- queue_work(sdio_al_dev->workqueue, &sdio_al_dev->sdio_al_work.work);
-
- start_inactive_time(sdio_al_dev);
-
- pr_debug(MODULE_NAME ":Ready.\n");
-
- return 0;
-}
-
-/**
- * Driver Tear-Down.
- *
- */
-static void sdio_al_tear_down(void)
-{
- int i, j;
- struct sdio_al_device *sdio_al_dev = NULL;
- struct sdio_func *func1;
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
- if (sdio_al->devices[i] == NULL)
- continue;
- sdio_al_dev = sdio_al->devices[i];
-
- if (sdio_al_dev->is_ready) {
- sdio_al_dev->is_ready = false; /* Flag worker to exit */
- sdio_al_dev->ask_mbox = false;
- ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
- /* allow gracefully exit of the worker thread */
- msleep(100);
-
- flush_workqueue(sdio_al_dev->workqueue);
- destroy_workqueue(sdio_al_dev->workqueue);
-
- sdio_al_vote_for_sleep(sdio_al_dev, 1);
-
- if (!sdio_al_claim_mutex_and_verify_dev(sdio_al_dev,
- __func__)) {
- if (!sdio_al_dev->card ||
- !sdio_al_dev->card->sdio_func[0]) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME
- ": %s: Invalid func1",
- __func__);
- return;
- }
- func1 = sdio_al_dev->card->sdio_func[0];
- sdio_release_irq(func1);
- sdio_disable_func(func1);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- }
- }
-
- for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++)
- sdio_al_dev->channel[j].signature = 0x0;
- sdio_al_dev->signature = 0;
-
- kfree(sdio_al_dev->sdioc_sw_header);
- kfree(sdio_al_dev->mailbox);
- kfree(sdio_al_dev->rx_flush_buf);
- kfree(sdio_al_dev);
- }
-
- sdio_al->pdata->config_mdm2ap_status(0);
-}
-
-/**
- * Find channel by name.
- *
- */
-static struct sdio_channel *find_channel_by_name(const char *name)
-{
- struct sdio_channel *ch = NULL;
- int i, j;
- struct sdio_al_device *sdio_al_dev = NULL;
-
- for (j = 0; j < MAX_NUM_OF_SDIO_DEVICES; ++j) {
- if (sdio_al->devices[j] == NULL)
- continue;
- sdio_al_dev = sdio_al->devices[j];
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- if (sdio_al_dev->channel[i].state ==
- SDIO_CHANNEL_STATE_INVALID)
- continue;
- if (strncmp(sdio_al_dev->channel[i].name, name,
- CHANNEL_NAME_SIZE) == 0) {
- ch = &sdio_al_dev->channel[i];
- break;
- }
- }
- if (ch != NULL)
- break;
- }
-
- return ch;
-}
-
-/**
- * Find the minimal poll time.
- *
- */
-static int get_min_poll_time_msec(struct sdio_al_device *sdio_sl_dev)
-{
- int i;
- int poll_delay_msec = 0x0FFFFFFF;
-
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++)
- if ((sdio_sl_dev->channel[i].state ==
- SDIO_CHANNEL_STATE_OPEN) &&
- (sdio_sl_dev->channel[i].poll_delay_msec > 0) &&
- (sdio_sl_dev->channel[i].poll_delay_msec < poll_delay_msec))
- poll_delay_msec =
- sdio_sl_dev->channel[i].poll_delay_msec;
-
- if (poll_delay_msec == 0x0FFFFFFF)
- poll_delay_msec = SDIO_AL_POLL_TIME_NO_STREAMING;
-
- pr_debug(MODULE_NAME ":poll delay time is %d msec\n", poll_delay_msec);
-
- return poll_delay_msec;
-}
-
-/**
- * Open SDIO Channel.
- *
- * Enable the channel.
- * Set the channel context.
- * Trigger reading the mailbox to check available bytes.
- *
- */
-int sdio_open(const char *name, struct sdio_channel **ret_ch, void *priv,
- void (*notify)(void *priv, unsigned ch_event))
-{
- int ret = 0;
- struct sdio_channel *ch = NULL;
- struct sdio_al_device *sdio_al_dev = NULL;
-
- *ret_ch = NULL; /* default */
-
- ch = find_channel_by_name(name);
- if (ch == NULL) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":Can't find "
- "channel name %s\n", name);
- return -EINVAL;
- }
-
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- if ((ch->state != SDIO_CHANNEL_STATE_IDLE) &&
- (ch->state != SDIO_CHANNEL_STATE_CLOSED)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Wrong ch %s "
- "state %d\n", name, ch->state);
- ret = -EPERM;
- goto exit_err;
- }
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- ret = -ENODEV;
- goto exit_err;
- }
-
- ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
- if (ret)
- goto exit_err;
-
- ch->notify = notify;
- ch->priv = priv;
-
- /* Note: Set caller returned context before interrupts are enabled */
- *ret_ch = ch;
-
- ret = open_channel(ch);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
- "err=%d\n", name, -ret);
- goto exit_err;
- }
-
- CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":sdio_open %s "
- "completed OK\n", name);
- if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
- if (sdio_al->sdioc_major == PEER_SDIOC_OLD_VERSION_MAJOR) {
- if (!ch->is_packet_mode) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
- ":setting channel %s as "
- "lpm_chan\n", name);
- sdio_al_dev->lpm_chan = ch->num;
- }
- } else {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": "
- "setting channel %s as lpm_chan\n",
- name);
- sdio_al_dev->lpm_chan = ch->num;
- }
- }
-
-exit_err:
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return ret;
-}
-EXPORT_SYMBOL(sdio_open);
-
-/**
- * Request peer operation
- * note: sanity checks of parameters done by caller
- * called under bus locked
- */
-static int peer_set_operation(u32 opcode,
- struct sdio_al_device *sdio_al_dev,
- struct sdio_channel *ch)
-{
- int ret;
- int offset;
- struct sdio_func *wk_func = NULL;
- u32 peer_operation;
- int loop_count = 0;
-
- if (!sdio_al_dev->card ||
- !sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1]) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": NULL card or wk_func\n");
- ret = -ENODEV;
- goto exit;
- }
- wk_func = sdio_al_dev->card->sdio_func[SDIO_AL_WAKEUP_FUNC-1];
-
- /* calculate offset of peer_operation field in sw mailbox struct */
- offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config) +
- sizeof(struct peer_sdioc_channel_config) * ch->num +
- offsetof(struct peer_sdioc_channel_config, peer_operation);
-
- ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
- "wake up\n");
- goto exit;
- }
- /* request operation from MDM peer */
- peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_INIT);
- ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
- &peer_operation, sizeof(u32));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
- "request close operation\n");
- goto exit;
- }
- ret = sdio_al_enable_func_retry(wk_func, "wk_func");
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to enable"
- " Func#%d\n", wk_func->num);
- goto exit;
- }
- pr_debug(MODULE_NAME ":%s: wk_func enabled on ch %s\n",
- __func__, ch->name);
- /* send "start" operation to MDM */
- peer_operation = PEER_OPERATION(opcode, PEER_OP_STATE_START);
- ret = sdio_memcpy_toio(ch->func, SDIOC_SW_MAILBOX_ADDR+offset,
- &peer_operation, sizeof(u32));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":failed to "
- "send start close operation\n");
- goto exit;
- }
- ret = sdio_disable_func(wk_func);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
- "disable Func#%d\n", wk_func->num);
- goto exit;
- }
- /* poll for peer operation ack */
- while (peer_operation != 0) {
- ret = sdio_memcpy_fromio(ch->func,
- &peer_operation,
- SDIOC_SW_MAILBOX_ADDR+offset,
- sizeof(u32));
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":failed to request ack on close"
- " operation, loop_count = %d\n",
- loop_count);
- goto exit;
- }
- loop_count++;
- if (loop_count > 10) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "peer_operation=0x%x wait loop"
- " %d on ch %s\n", __func__,
- peer_operation, loop_count, ch->name);
- }
- }
-exit:
- return ret;
-}
-
-static int channel_close(struct sdio_channel *ch, int flush_flag)
-{
- int ret;
- struct sdio_al_device *sdio_al_dev = NULL;
- int flush_len;
- ulong flush_expires;
-
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
-
- if (!ch->func) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: NULL func"
- " on channel:%d\n", __func__, ch->num);
- return -ENODEV;
- }
-
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- if (!sdio_al_dev->ch_close_supported) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: Not "
- "supported by mdm, ch %s\n",
- __func__, ch->name);
- ret = -ENOTSUPP;
- goto error_exit;
- }
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- ret = -ENODEV;
- goto error_exit;
- }
- if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME ":%s: ch %s is not in "
- "open state (%d)\n",
- __func__, ch->name, ch->state);
- ret = -ENODEV;
- goto error_exit;
- }
- ch->state = SDIO_CHANNEL_STATE_CLOSING;
- ret = peer_set_operation(PEER_OP_CODE_CLOSE, sdio_al_dev, ch);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "peer_set_operation() failed: %d\n",
- __func__, ret);
- ret = -ENODEV;
- goto error_exit;
- }
- /* udate poll time for opened channels */
- if (ch->poll_delay_msec > 0) {
- sdio_al_dev->poll_delay_msec =
- get_min_poll_time_msec(sdio_al_dev);
- }
- sdio_al_release_mutex(ch->sdio_al_dev, __func__);
-
- flush_expires = jiffies +
- msecs_to_jiffies(SDIO_CLOSE_FLUSH_TIMEOUT_MSEC);
- /* flush rx packets of the channel */
- if (flush_flag) {
- do {
- while (ch->read_avail > 0) {
- flush_len = ch->read_avail;
- ret = sdio_read_internal(ch,
- sdio_al_dev->rx_flush_buf,
- flush_len);
- if (ret) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":%s sdio_read"
- " failed: %d, ch %s\n",
- __func__, ret,
- ch->name);
- return ret;
- }
-
- if (time_after(jiffies, flush_expires) != 0) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":%s flush rx "
- "packets timeout: ch %s\n",
- __func__, ch->name);
- sdio_al_get_into_err_state(sdio_al_dev);
- return -EBUSY;
- }
- }
- msleep(100);
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":%s: after sleep,"
- " invalid signature"
- " 0x%x\n", __func__,
- ch->signature);
- return -ENODEV;
- }
- if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
- __func__))
- return -ENODEV;
-
- ret = read_mailbox(sdio_al_dev, false);
- if (ret) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":%s: failed to"
- " read mailbox", __func__);
- goto error_exit;
- }
- sdio_al_release_mutex(ch->sdio_al_dev, __func__);
- } while (ch->read_avail > 0);
- }
- if (sdio_al_claim_mutex_and_verify_dev(ch->sdio_al_dev,
- __func__))
- return -ENODEV;
- /* disable function to be able to open the channel again */
- ret = sdio_disable_func(ch->func);
- if (ret) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":Fail to disable Func#%d\n",
- ch->func->num);
- goto error_exit;
- }
- ch->state = SDIO_CHANNEL_STATE_CLOSED;
- CLOSE_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":%s: Ch %s closed "
- "successfully\n", __func__, ch->name);
-
-error_exit:
- sdio_al_release_mutex(ch->sdio_al_dev, __func__);
-
- return ret;
-}
-
-/**
- * Close SDIO Channel.
- *
- */
-int sdio_close(struct sdio_channel *ch)
-{
- return channel_close(ch, true);
-}
-EXPORT_SYMBOL(sdio_close);
-
-/**
- * Get the number of available bytes to write.
- *
- */
-int sdio_write_avail(struct sdio_channel *ch)
-{
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
- "Invalid signature 0x%x\n", __func__,
- ch->signature);
- return -ENODEV;
- }
- if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "channel %s state is not open (%d)\n",
- __func__, ch->name, ch->state);
- return -ENODEV;
- }
- pr_debug(MODULE_NAME ":sdio_write_avail %s 0x%x\n",
- ch->name, ch->write_avail);
-
- return ch->write_avail;
-}
-EXPORT_SYMBOL(sdio_write_avail);
-
-/**
- * Get the number of available bytes to read.
- *
- */
-int sdio_read_avail(struct sdio_channel *ch)
-{
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
- "Invalid signature 0x%x\n", __func__,
- ch->signature);
- return -ENODEV;
- }
- if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME ":%s: "
- "channel %s state is not open (%d)\n",
- __func__, ch->name, ch->state);
- return -ENODEV;
- }
- pr_debug(MODULE_NAME ":sdio_read_avail %s 0x%x\n",
- ch->name, ch->read_avail);
-
- return ch->read_avail;
-}
-EXPORT_SYMBOL(sdio_read_avail);
-
-static int sdio_read_from_closed_ch(struct sdio_channel *ch, int len)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = NULL;
-
- if (!ch) {
- sdio_al_loge(ch->sdio_al_dev->dev_log,
- MODULE_NAME ":%s: NULL channel\n", __func__);
- return -ENODEV;
- }
-
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- ret = sdio_memcpy_fromio(ch->func, sdio_al_dev->rx_flush_buf,
- PIPE_RX_FIFO_ADDR, len);
-
- if (ret) {
- sdio_al_loge(ch->sdio_al_dev->dev_log,
- MODULE_NAME ":ch %s: %s err=%d, len=%d\n",
- ch->name, __func__, -ret, len);
- sdio_al_dev->is_err = true;
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return ret;
- }
-
- restart_inactive_time(sdio_al_dev);
-
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- return 0;
-}
-
-/**
- * Internal read from SDIO Channel.
- *
- * Reading from the pipe will trigger interrupt if there are
- * other pending packets on the SDIO-Client.
- *
- */
-static int sdio_read_internal(struct sdio_channel *ch, void *data, int len)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = NULL;
-
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
- if (!data) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
- __func__);
- return -ENODEV;
- }
- if (len == 0) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
- " to read 0 bytes\n", ch->name);
- return -EINVAL;
- }
-
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
- "signature 0x%x\n", __func__, ch->signature);
- return -ENODEV;
- }
-
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- ret = -ENODEV;
- goto exit;
- }
-
- /* lpm policy says we can't go to sleep when we have pending rx data,
- so either we had rx interrupt and woken up, or we never went to
- sleep */
- if (sdio_al_dev->is_ok_to_sleep) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s: called "
- "when is_ok_to_sleep is set for ch %s, len=%d,"
- " last_any_read_avail=%d, last_read_avail=%d, "
- "last_old_read_avail=%d", __func__, ch->name,
- len, ch->statistics.last_any_read_avail,
- ch->statistics.last_read_avail,
- ch->statistics.last_old_read_avail);
- }
- BUG_ON(sdio_al_dev->is_ok_to_sleep);
-
- if ((ch->state != SDIO_CHANNEL_STATE_OPEN) &&
- (ch->state != SDIO_CHANNEL_STATE_CLOSING)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":%s wrong "
- "channel %s state %d\n",
- __func__, ch->name, ch->state);
- ret = -EINVAL;
- goto exit;
- }
-
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s read %d "
- "avail %d.\n", ch->name, len, ch->read_avail);
-
- restart_inactive_time(sdio_al_dev);
-
- if ((ch->is_packet_mode) && (len != ch->read_avail)) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_read ch "
- "%s len != read_avail\n", ch->name);
- ret = -EINVAL;
- goto exit;
- }
-
- if (len > ch->read_avail) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
- "reading more bytes (%d) than the avail(%d).\n",
- ch->name, len, ch->read_avail);
- ret = -ENOMEM;
- goto exit;
- }
-
- ret = sdio_memcpy_fromio(ch->func, data, PIPE_RX_FIFO_ADDR, len);
-
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ch %s: "
- "sdio_read err=%d, len=%d, read_avail=%d, "
- "last_read_avail=%d, last_old_read_avail=%d\n",
- ch->name, -ret, len, ch->read_avail,
- ch->statistics.last_read_avail,
- ch->statistics.last_old_read_avail);
- sdio_al_get_into_err_state(sdio_al_dev);
- goto exit;
- }
-
- ch->statistics.total_read_times++;
-
- /* Remove handled packet from the list regardless if ret is ok */
- if (ch->is_packet_mode)
- remove_handled_rx_packet(ch);
- else
- ch->read_avail -= len;
-
- ch->total_rx_bytes += len;
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s read %d "
- "avail %d total %d.\n", ch->name, len,
- ch->read_avail, ch->total_rx_bytes);
-
- if ((ch->read_avail == 0) && !(ch->is_packet_mode))
- ask_reading_mailbox(sdio_al_dev);
-
-exit:
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- return ret;
-}
-
-/**
- * Read from SDIO Channel.
- *
- * Reading from the pipe will trigger interrupt if there are
- * other pending packets on the SDIO-Client.
- *
- */
-int sdio_read(struct sdio_channel *ch, void *data, int len)
-{
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: "
- "Invalid signature 0x%x\n", __func__, ch->signature);
- return -ENODEV;
- }
- if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
- return sdio_read_internal(ch, data, len);
- } else {
- sdio_al_loge(ch->sdio_al_dev->dev_log, MODULE_NAME
- ":%s: Invalid channel %s state %d\n",
- __func__, ch->name, ch->state);
- }
- return -ENODEV;
-}
-EXPORT_SYMBOL(sdio_read);
-
-/**
- * Write to SDIO Channel.
- *
- */
-int sdio_write(struct sdio_channel *ch, const void *data, int len)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = NULL;
-
- if (!ch) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL "
- "channel\n", __func__);
- return -ENODEV;
- }
- if (!data) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: NULL data\n",
- __func__);
- return -ENODEV;
- }
- if (len == 0) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":channel %s trying"
- " to write 0 bytes\n", ch->name);
- return -EINVAL;
- }
-
- if (ch->signature != SDIO_AL_SIGNATURE) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":%s: Invalid "
- "signature 0x%x\n", __func__, ch->signature);
- return -ENODEV;
- }
-
- sdio_al_dev = ch->sdio_al_dev;
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- WARN_ON(len > ch->write_avail);
-
- if (sdio_al_dev->is_err) {
- SDIO_AL_ERR(__func__);
- ret = -ENODEV;
- goto exit;
- }
-
- if (ch->state != SDIO_CHANNEL_STATE_OPEN) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":writing to "
- "closed channel %s\n", ch->name);
- ret = -EINVAL;
- goto exit;
- }
-
- if (sdio_al_dev->is_ok_to_sleep) {
- ret = sdio_al_wake_up(sdio_al_dev, 1, ch);
- if (ret)
- goto exit;
- } else {
- restart_inactive_time(sdio_al_dev);
- }
-
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":start ch %s write %d "
- "avail %d.\n", ch->name, len, ch->write_avail);
-
- if (len > ch->write_avail) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":ERR ch %s: "
- "write more bytes (%d) than available %d.\n",
- ch->name, len, ch->write_avail);
- ret = -ENOMEM;
- goto exit;
- }
-
- ret = sdio_ch_write(ch, data, len);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":sdio_write "
- "on channel %s err=%d\n", ch->name, -ret);
- goto exit;
- }
-
- ch->total_tx_bytes += len;
- DATA_DEBUG(sdio_al_dev->dev_log, MODULE_NAME ":end ch %s write %d "
- "avail %d total %d.\n", ch->name, len,
- ch->write_avail, ch->total_tx_bytes);
-
- /* Round up to whole buffer size */
- len = ROUND_UP(len, ch->peer_tx_buf_size);
- /* Protect from wraparound */
- len = min(len, (int) ch->write_avail);
- ch->write_avail -= len;
-
- if (ch->write_avail < ch->min_write_avail)
- ask_reading_mailbox(sdio_al_dev);
-
-exit:
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- return ret;
-}
-EXPORT_SYMBOL(sdio_write);
-
-static int __devinit msm_sdio_al_probe(struct platform_device *pdev)
-{
- if (!sdio_al) {
- pr_err(MODULE_NAME ": %s: NULL sdio_al\n", __func__);
- return -ENODEV;
- }
-
- sdio_al->pdata = pdev->dev.platform_data;
- return 0;
-}
-
-static int __devexit msm_sdio_al_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
-static void sdio_al_close_all_channels(struct sdio_al_device *sdio_al_dev)
-{
- int j;
- int ret;
- struct sdio_channel *ch = NULL;
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
-
- if (!sdio_al_dev) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: NULL device", __func__);
- return;
- }
- for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
- ch = &sdio_al_dev->channel[j];
-
- if (ch->state == SDIO_CHANNEL_STATE_OPEN) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: Call to sdio_close() for"
- " ch %s\n", __func__, ch->name);
- ret = channel_close(ch, false);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log,
- MODULE_NAME ": %s: failed sdio_close()"
- " for ch %s (%d)\n",
- __func__, ch->name, ret);
- }
- } else {
- pr_debug(MODULE_NAME ": %s: skip sdio_close() ch %s"
- " (state=%d)\n", __func__,
- ch->name, ch->state);
- }
- }
-}
-
-static void sdio_al_invalidate_sdio_clients(struct sdio_al_device *sdio_al_dev,
- struct platform_device **pdev_arr)
-{
- int j;
-
- pr_debug(MODULE_NAME ": %s: Notifying SDIO clients for card %d",
- __func__, sdio_al_dev->host->index);
- for (j = 0; j < SDIO_AL_MAX_CHANNELS; ++j) {
- if (sdio_al_dev->channel[j].state ==
- SDIO_CHANNEL_STATE_INVALID)
- continue;
- pdev_arr[j] = sdio_al_dev->channel[j].pdev;
- sdio_al_dev->channel[j].signature = 0x0;
- sdio_al_dev->channel[j].state =
- SDIO_CHANNEL_STATE_INVALID;
- }
-}
-
-static void sdio_al_modem_reset_operations(struct sdio_al_device
- *sdio_al_dev)
-{
- int ret = 0;
- struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
- int j;
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return;
-
- if (sdio_al_dev->state == CARD_REMOVED) {
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
- "card %d is already removed", __func__,
- sdio_al_dev->host->index);
- goto exit_err;
- }
-
- if (sdio_al_dev->state == MODEM_RESTART) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: "
- "card %d was already notified for modem reset",
- __func__, sdio_al_dev->host->index);
- goto exit_err;
- }
-
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ": %s: Set the "
- "state to MODEM_RESTART for card %d",
- __func__, sdio_al_dev->host->index);
- sdio_al_dev->state = MODEM_RESTART;
- sdio_al_dev->is_ready = false;
-
- /* Stop mailbox timer */
- stop_and_del_timer(sdio_al_dev);
-
- if ((sdio_al_dev->is_ok_to_sleep) &&
- (!sdio_al_dev->is_err)) {
- pr_debug(MODULE_NAME ": %s: wakeup modem for "
- "card %d", __func__,
- sdio_al_dev->host->index);
- ret = sdio_al_wake_up(sdio_al_dev, 1, NULL);
- }
-
- if (!ret && (!sdio_al_dev->is_err) && sdio_al_dev->card &&
- sdio_al_dev->card->sdio_func[0]) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME
- ": %s: sdio_release_irq for card %d",
- __func__,
- sdio_al_dev->host->index);
- sdio_release_irq(sdio_al_dev->card->sdio_func[0]);
- }
-
- memset(pdev_arr, 0, sizeof(pdev_arr));
- sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
-
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
- "clients for card %d",
- __func__, sdio_al_dev->host->index);
- for (j = 0; j < SDIO_AL_MAX_CHANNELS; j++) {
- if (!pdev_arr[j])
- continue;
- platform_device_unregister(pdev_arr[j]);
- }
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
- "SDIO clients for card %d",
- __func__, sdio_al_dev->host->index);
-
- return;
-
-exit_err:
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return;
-}
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
-static void sdio_al_reset(void)
-{
- int i;
- struct sdio_al_device *sdio_al_dev;
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s", __func__);
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
- if (sdio_al->devices[i] == NULL) {
- pr_debug(MODULE_NAME ": %s: NULL device in index %d",
- __func__, i);
- continue;
- }
- sdio_al_dev = sdio_al->devices[i];
- sdio_al_modem_reset_operations(sdio_al->devices[i]);
- }
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s completed", __func__);
-}
-#endif
-
-static void msm_sdio_al_shutdown(struct platform_device *pdev)
-{
- int i;
- struct sdio_al_device *sdio_al_dev;
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME
- "Initiating msm_sdio_al_shutdown...");
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; i++) {
- if (sdio_al->devices[i] == NULL) {
- pr_debug(MODULE_NAME ": %s: NULL device in index %d",
- __func__, i);
- continue;
- }
- sdio_al_dev = sdio_al->devices[i];
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return;
-
- if (sdio_al_dev->ch_close_supported)
- sdio_al_close_all_channels(sdio_al_dev);
-
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- sdio_al_modem_reset_operations(sdio_al_dev);
- }
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: "
- "msm_sdio_al_shutdown complete.", __func__);
-}
-
-static struct platform_driver msm_sdio_al_driver = {
- .probe = msm_sdio_al_probe,
- .remove = __exit_p(msm_sdio_al_remove),
- .shutdown = msm_sdio_al_shutdown,
- .driver = {
- .name = "msm_sdio_al",
- },
-};
-
-/**
- * Initialize SDIO_AL channels.
- *
- */
-static int init_channels(struct sdio_al_device *sdio_al_dev)
-{
- int ret = 0;
- int i;
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- ret = read_sdioc_software_header(sdio_al_dev,
- sdio_al_dev->sdioc_sw_header);
- if (ret)
- goto exit;
-
- ret = sdio_al_setup(sdio_al_dev);
- if (ret)
- goto exit;
-
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- int ch_name_size;
- if (sdio_al_dev->channel[i].state == SDIO_CHANNEL_STATE_INVALID)
- continue;
- if (sdio_al->unittest_mode) {
- memset(sdio_al_dev->channel[i].ch_test_name, 0,
- sizeof(sdio_al_dev->channel[i].ch_test_name));
- ch_name_size = strnlen(sdio_al_dev->channel[i].name,
- CHANNEL_NAME_SIZE);
- strncpy(sdio_al_dev->channel[i].ch_test_name,
- sdio_al_dev->channel[i].name,
- ch_name_size);
- strncat(sdio_al_dev->channel[i].ch_test_name +
- ch_name_size,
- SDIO_TEST_POSTFIX,
- SDIO_TEST_POSTFIX_SIZE);
- pr_debug(MODULE_NAME ":pdev.name = %s\n",
- sdio_al_dev->channel[i].ch_test_name);
- sdio_al_dev->channel[i].pdev = platform_device_alloc(
- sdio_al_dev->channel[i].ch_test_name, -1);
- } else {
- pr_debug(MODULE_NAME ":pdev.name = %s\n",
- sdio_al_dev->channel[i].name);
- sdio_al_dev->channel[i].pdev = platform_device_alloc(
- sdio_al_dev->channel[i].name, -1);
- }
- if (!sdio_al_dev->channel[i].pdev) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":NULL platform device for ch %s",
- sdio_al_dev->channel[i].name);
- sdio_al_dev->channel[i].state =
- SDIO_CHANNEL_STATE_INVALID;
- continue;
- }
- ret = platform_device_add(sdio_al_dev->channel[i].pdev);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ":platform_device_add failed, "
- "ret=%d\n", ret);
- sdio_al_dev->channel[i].state =
- SDIO_CHANNEL_STATE_INVALID;
- }
- }
-
-exit:
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return ret;
-}
-
-/**
- * Initialize SDIO_AL channels according to the client setup.
- * This function also check if the client is in boot mode and
- * flashless boot is required to be activated or the client is
- * up and running.
- *
- */
-static int sdio_al_client_setup(struct sdio_al_device *sdio_al_dev)
-{
- int ret = 0;
- struct sdio_func *func1;
- int signature = 0;
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":NULL card or "
- "func1\n");
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return -ENODEV;
- }
- func1 = sdio_al_dev->card->sdio_func[0];
-
- /* Read the header signature to determine the status of the MDM
- * SDIO Client
- */
- signature = sdio_readl(func1, SDIOC_SW_HEADER_ADDR, &ret);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":fail to read "
- "signature from sw header.\n");
- return ret;
- }
-
- switch (signature) {
- case PEER_SDIOC_SW_MAILBOX_BOOT_SIGNATURE:
- if (sdio_al_dev == sdio_al->bootloader_dev) {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":setup "
- "bootloader on card %d\n",
- sdio_al_dev->host->index);
- return sdio_al_bootloader_setup();
- } else {
- sdio_al_logi(sdio_al_dev->dev_log, MODULE_NAME ":wait "
- "for bootloader completion "
- "on card %d\n",
- sdio_al_dev->host->index);
- return sdio_al_wait_for_bootloader_comp(sdio_al_dev);
- }
- case PEER_SDIOC_SW_MAILBOX_SIGNATURE:
- case PEER_SDIOC_SW_MAILBOX_UT_SIGNATURE:
- return init_channels(sdio_al_dev);
- default:
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Invalid "
- "signature 0x%x\n", signature);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void clean_sdio_al_device_data(struct sdio_al_device *sdio_al_dev)
-{
- sdio_al_dev->is_ready = 0;
- sdio_al_dev->bootloader_done = 0;
- sdio_al_dev->lpm_chan = 0;
- sdio_al_dev->is_ok_to_sleep = 0;
- sdio_al_dev->inactivity_time = 0;
- sdio_al_dev->poll_delay_msec = 0;
- sdio_al_dev->is_timer_initialized = 0;
- sdio_al_dev->is_err = 0;
- sdio_al_dev->is_suspended = 0;
- sdio_al_dev->flashless_boot_on = 0;
- sdio_al_dev->ch_close_supported = 0;
- sdio_al_dev->print_after_interrupt = 0;
- memset(sdio_al_dev->sdioc_sw_header, 0,
- sizeof(*sdio_al_dev->sdioc_sw_header));
- memset(sdio_al_dev->mailbox, 0, sizeof(*sdio_al_dev->mailbox));
- memset(sdio_al_dev->rx_flush_buf, 0,
- sizeof(*sdio_al_dev->rx_flush_buf));
-}
-
-/*
- * SDIO driver functions
- */
-static int sdio_al_sdio_probe(struct sdio_func *func,
- const struct sdio_device_id *sdio_dev_id)
-{
- int ret = 0;
- struct sdio_al_device *sdio_al_dev = NULL;
- int i;
- struct mmc_card *card = NULL;
-
- if (!func) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
- __func__);
- return -ENODEV;
- }
- card = func->card;
-
- if (!card) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
- __func__);
- return -ENODEV;
- }
-
- if (!card->sdio_func[0]) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "func1\n",
- __func__);
- return -ENODEV;
- }
-
- if (card->sdio_funcs < SDIO_AL_MAX_FUNCS) {
- dev_info(&card->dev,
- "SDIO-functions# %d less than expected.\n",
- card->sdio_funcs);
- return -ENODEV;
- }
-
- /* Check if there is already a device for this card */
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
- if (sdio_al->devices[i] == NULL)
- continue;
- if (sdio_al->devices[i]->host == card->host) {
- sdio_al_dev = sdio_al->devices[i];
- if (sdio_al_dev->state == CARD_INSERTED)
- return 0;
- clean_sdio_al_device_data(sdio_al_dev);
- break;
- }
- }
-
- if (!sdio_al_dev) {
- sdio_al_dev = kzalloc(sizeof(struct sdio_al_device),
- GFP_KERNEL);
- if (sdio_al_dev == NULL)
- return -ENOMEM;
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
- if (sdio_al->devices[i] == NULL) {
- sdio_al->devices[i] = sdio_al_dev;
- sdio_al_dev->dev_log = &sdio_al->device_log[i];
- spin_lock_init(&sdio_al_dev->dev_log->log_lock);
- #ifdef CONFIG_DEBUG_FS
- sdio_al_dbgfs_log[i].data =
- sdio_al_dev->dev_log->buffer;
- sdio_al_dbgfs_log[i].size =
- SDIO_AL_DEBUG_LOG_SIZE;
- #endif
- break;
- }
- if (i == MAX_NUM_OF_SDIO_DEVICES) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ":No space "
- "in devices array for the device\n");
- return -ENOMEM;
- }
- }
-
- dev_info(&card->dev, "SDIO Card claimed.\n");
- sdio_al->skip_print_info = 0;
-
- sdio_al_dev->state = CARD_INSERTED;
-
- if (card->host->index == SDIO_BOOTLOADER_CARD_INDEX)
- sdio_al->bootloader_dev = sdio_al_dev;
-
- sdio_al_dev->is_ready = false;
-
- sdio_al_dev->signature = SDIO_AL_SIGNATURE;
-
- sdio_al_dev->is_suspended = 0;
- sdio_al_dev->is_timer_initialized = false;
-
- sdio_al_dev->lpm_chan = INVALID_SDIO_CHAN;
-
- sdio_al_dev->card = card;
- sdio_al_dev->host = card->host;
-
- if (!sdio_al_dev->mailbox) {
- sdio_al_dev->mailbox = kzalloc(sizeof(struct sdio_mailbox),
- GFP_KERNEL);
- if (sdio_al_dev->mailbox == NULL)
- return -ENOMEM;
- }
-
- if (!sdio_al_dev->sdioc_sw_header) {
- sdio_al_dev->sdioc_sw_header
- = kzalloc(sizeof(*sdio_al_dev->sdioc_sw_header),
- GFP_KERNEL);
- if (sdio_al_dev->sdioc_sw_header == NULL)
- return -ENOMEM;
- }
-
- if (!sdio_al_dev->rx_flush_buf) {
- sdio_al_dev->rx_flush_buf = kzalloc(RX_FLUSH_BUFFER_SIZE,
- GFP_KERNEL);
- if (sdio_al_dev->rx_flush_buf == NULL) {
- sdio_al_loge(&sdio_al->gen_log,
- MODULE_NAME ":Fail to allocate "
- "rx_flush_buf for card %d\n",
- card->host->index);
- return -ENOMEM;
- }
- }
-
- sdio_al_dev->timer.data = (unsigned long)sdio_al_dev;
-
- wake_lock_init(&sdio_al_dev->wake_lock, WAKE_LOCK_SUSPEND, MODULE_NAME);
- /* Don't allow sleep until all required clients register */
- sdio_al_vote_for_sleep(sdio_al_dev, 0);
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return -ENODEV;
-
- /* Init Func#1 */
- ret = sdio_al_enable_func_retry(card->sdio_func[0], "Init Func#1");
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to "
- "enable Func#%d\n", card->sdio_func[0]->num);
- goto exit;
- }
-
- /* Patch Func CIS tuple issue */
- ret = sdio_set_block_size(card->sdio_func[0], SDIO_AL_BLOCK_SIZE);
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ":Fail to set "
- "block size, Func#%d\n", card->sdio_func[0]->num);
- goto exit;
- }
- sdio_al_dev->card->sdio_func[0]->max_blksize = SDIO_AL_BLOCK_SIZE;
-
- sdio_al_dev->workqueue = create_singlethread_workqueue("sdio_al_wq");
- sdio_al_dev->sdio_al_work.sdio_al_dev = sdio_al_dev;
- init_waitqueue_head(&sdio_al_dev->wait_mbox);
-
- ret = sdio_al_client_setup(sdio_al_dev);
-
-exit:
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return ret;
-}
-
-static void sdio_al_sdio_remove(struct sdio_func *func)
-{
- struct sdio_al_device *sdio_al_dev = NULL;
- int i;
- struct mmc_card *card = NULL;
- struct platform_device *pdev_arr[SDIO_AL_MAX_CHANNELS];
-
- if (!func) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL func\n",
- __func__);
- return;
- }
- card = func->card;
-
- if (!card) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL card\n",
- __func__);
- return;
- }
-
- /* Find the sdio_al_device of this card */
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES; ++i) {
- if (sdio_al->devices[i] == NULL)
- continue;
- if (sdio_al->devices[i]->card == card) {
- sdio_al_dev = sdio_al->devices[i];
- break;
- }
- }
- if (sdio_al_dev == NULL) {
- pr_debug(MODULE_NAME ":%s :NULL sdio_al_dev for card %d\n",
- __func__, card->host->index);
- return;
- }
-
- if (sdio_al_claim_mutex(sdio_al_dev, __func__))
- return;
-
- if (sdio_al_dev->state == CARD_REMOVED) {
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return;
- }
-
- if (!card->sdio_func[0]) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: NULL "
- "func1\n", __func__);
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return;
- }
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s for card %d\n",
- __func__, card->host->index);
-
- sdio_al_dev->state = CARD_REMOVED;
-
- memset(pdev_arr, 0, sizeof(pdev_arr));
- sdio_al_invalidate_sdio_clients(sdio_al_dev, pdev_arr);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: ask_reading_mailbox "
- "for card %d\n", __func__, card->host->index);
- sdio_al_dev->is_ready = false; /* Flag worker to exit */
- sdio_al_dev->ask_mbox = false;
- ask_reading_mailbox(sdio_al_dev); /* Wakeup worker */
-
- stop_and_del_timer(sdio_al_dev);
-
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Notifying SDIO "
- "clients for card %d",
- __func__, sdio_al_dev->host->index);
- for (i = 0; i < SDIO_AL_MAX_CHANNELS; i++) {
- if (!pdev_arr[i])
- continue;
- platform_device_unregister(pdev_arr[i]);
- }
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: Finished Notifying "
- "SDIO clients for card %d",
- __func__, sdio_al_dev->host->index);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: vote for sleep for "
- "card %d\n", __func__, card->host->index);
- sdio_al_vote_for_sleep(sdio_al_dev, 1);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: flush_workqueue for "
- "card %d\n", __func__, card->host->index);
- flush_workqueue(sdio_al_dev->workqueue);
- destroy_workqueue(sdio_al_dev->workqueue);
- wake_lock_destroy(&sdio_al_dev->wake_lock);
-
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ":%s: sdio card %d removed."
- "\n", __func__, card->host->index);
-}
-
-static void sdio_print_mailbox(char *prefix_str, struct sdio_mailbox *mailbox)
-{
- int k = 0;
- char buf[256];
- char buf1[10];
-
- if (!mailbox) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": mailbox is "
- "NULL\n");
- return;
- }
-
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s: pipes 0_7: eot=0x%x,"
- " thresh=0x%x, overflow=0x%x, "
- "underflow=0x%x, mask_thresh=0x%x\n",
- prefix_str, mailbox->eot_pipe_0_7,
- mailbox->thresh_above_limit_pipe_0_7,
- mailbox->overflow_pipe_0_7,
- mailbox->underflow_pipe_0_7,
- mailbox->mask_thresh_above_limit_pipe_0_7);
-
- memset(buf, 0, sizeof(buf));
- strncat(buf, ": bytes_avail:", sizeof(buf));
-
- for (k = 0 ; k < SDIO_AL_ACTIVE_PIPES ; ++k) {
- snprintf(buf1, sizeof(buf1), "%d, ",
- mailbox->pipe_bytes_avail[k]);
- strncat(buf, buf1, sizeof(buf));
- }
-
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME "%s", buf);
-}
-
-static void sdio_al_print_info(void)
-{
- int i = 0;
- int j = 0;
- int ret = 0;
- struct sdio_mailbox *mailbox = NULL;
- struct sdio_mailbox *hw_mailbox = NULL;
- struct peer_sdioc_channel_config *ch_config = NULL;
- struct sdio_func *func1 = NULL;
- struct sdio_func *lpm_func = NULL;
- int offset = 0;
- int is_ok_to_sleep = 0;
- char buf[50];
-
- if (sdio_al->skip_print_info == 1)
- return;
-
- sdio_al->skip_print_info = 1;
-
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - SDIO DEBUG INFO\n",
- __func__);
-
- if (!sdio_al) {
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": %s - ERROR - "
- "sdio_al is NULL\n", __func__);
- return;
- }
-
- sdio_al_loge(&sdio_al->gen_log, MODULE_NAME ": GPIO mdm2ap_status=%d\n",
- sdio_al->pdata->get_mdm2ap_status());
-
- for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
- struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
-
- if (sdio_al_dev == NULL) {
- continue;
- }
-
- if (!sdio_al_dev->host) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Host"
- " is NULL\n);");
- continue;
- }
-
- snprintf(buf, sizeof(buf), "Card#%d: Shadow HW MB",
- sdio_al_dev->host->index);
-
- /* printing Shadowing HW Mailbox*/
- mailbox = sdio_al_dev->mailbox;
- sdio_print_mailbox(buf, mailbox);
-
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
- "is_ok_to_sleep=%d\n",
- sdio_al_dev->host->index,
- sdio_al_dev->is_ok_to_sleep);
-
-
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME ": Card#%d: "
- "Shadow channels SW MB:",
- sdio_al_dev->host->index);
-
- /* printing Shadowing SW Mailbox per channel*/
- for (i = 0 ; i < SDIO_AL_MAX_CHANNELS ; ++i) {
- struct sdio_channel *ch = &sdio_al_dev->channel[i];
-
- if (ch == NULL) {
- continue;
- }
-
- if (ch->state == SDIO_CHANNEL_STATE_INVALID)
- continue;
-
- ch_config = &sdio_al_dev->channel[i].ch_config;
-
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Ch %s: max_rx_thres=0x%x, "
- "max_tx_thres=0x%x, tx_buf=0x%x, "
- "is_packet_mode=%d, "
- "max_packet=0x%x, min_write=0x%x",
- ch->name, ch_config->max_rx_threshold,
- ch_config->max_tx_threshold,
- ch_config->tx_buf_size,
- ch_config->is_packet_mode,
- ch_config->max_packet_size,
- ch->min_write_avail);
-
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": total_rx=0x%x, total_tx=0x%x, "
- "read_avail=0x%x, write_avail=0x%x, "
- "rx_pending=0x%x, num_reads=0x%x, "
- "num_notifs=0x%x", ch->total_rx_bytes,
- ch->total_tx_bytes, ch->read_avail,
- ch->write_avail, ch->rx_pending_bytes,
- ch->statistics.total_read_times,
- ch->statistics.total_notifs);
- } /* end loop over all channels */
-
- } /* end loop over all devices */
-
- /* reading from client and printing is_host_ok_to_sleep per device */
- for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
- struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
-
- if (sdio_al_verify_func1(sdio_al_dev, __func__))
- continue;
-
- if (!sdio_al_dev->host) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Host is NULL");
- continue;
- }
-
- if (sdio_al_dev->lpm_chan == INVALID_SDIO_CHAN) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": %s - for Card#%d, is lpm_chan=="
- "INVALID_SDIO_CHAN. continuing...",
- __func__, sdio_al_dev->host->index);
- continue;
- }
-
- offset = offsetof(struct peer_sdioc_sw_mailbox, ch_config)+
- sizeof(struct peer_sdioc_channel_config) *
- sdio_al_dev->lpm_chan+
- offsetof(struct peer_sdioc_channel_config, is_host_ok_to_sleep);
-
- lpm_func = sdio_al_dev->card->sdio_func[sdio_al_dev->
- lpm_chan+1];
- if (!lpm_func) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": %s - lpm_func is NULL for card#%d"
- " continuing...\n", __func__,
- sdio_al_dev->host->index);
- continue;
- }
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return;
- ret = sdio_memcpy_fromio(lpm_func,
- &is_ok_to_sleep,
- SDIOC_SW_MAILBOX_ADDR+offset,
- sizeof(int));
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- if (ret)
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": %s - fail to read "
- "is_HOST_ok_to_sleep from mailbox for card %d",
- __func__, sdio_al_dev->host->index);
- else
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": Card#%d: "
- "is_HOST_ok_to_sleep=%d\n",
- sdio_al_dev->host->index,
- is_ok_to_sleep);
- }
-
- for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES ; ++j) {
- struct sdio_al_device *sdio_al_dev = sdio_al->devices[j];
-
- if (!sdio_al_dev)
- continue;
-
- /* Reading HW Mailbox */
- hw_mailbox = sdio_al_dev->mailbox;
-
- if (sdio_al_claim_mutex_and_verify_dev(sdio_al_dev, __func__))
- return;
-
- if (!sdio_al_dev->card || !sdio_al_dev->card->sdio_func[0]) {
- sdio_al_release_mutex(sdio_al_dev, __func__);
- return;
- }
- func1 = sdio_al_dev->card->sdio_func[0];
- ret = sdio_memcpy_fromio(func1, hw_mailbox,
- HW_MAILBOX_ADDR, sizeof(*hw_mailbox));
- sdio_al_release_mutex(sdio_al_dev, __func__);
-
- if (ret) {
- sdio_al_loge(sdio_al_dev->dev_log, MODULE_NAME
- ": fail to read "
- "mailbox for card#%d. "
- "continuing...\n",
- sdio_al_dev->host->index);
- continue;
- }
-
- snprintf(buf, sizeof(buf), "Card#%d: Current HW MB",
- sdio_al_dev->host->index);
-
- /* Printing HW Mailbox */
- sdio_print_mailbox(buf, hw_mailbox);
- }
-}
-
-static struct sdio_device_id sdio_al_sdioid[] = {
- {.class = 0, .vendor = 0x70, .device = 0x2460},
- {.class = 0, .vendor = 0x70, .device = 0x0460},
- {.class = 0, .vendor = 0x70, .device = 0x23F1},
- {.class = 0, .vendor = 0x70, .device = 0x23F0},
- {}
-};
-
-static struct sdio_driver sdio_al_sdiofn_driver = {
- .name = "sdio_al_sdiofn",
- .id_table = sdio_al_sdioid,
- .probe = sdio_al_sdio_probe,
- .remove = sdio_al_sdio_remove,
-};
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
-/*
- * Callback for notifications from restart mudule.
- * This function handles only the BEFORE_RESTART notification.
- * Stop all the activity on the card and notify our clients.
- */
-static int sdio_al_subsys_notifier_cb(struct notifier_block *this,
- unsigned long notif_type,
- void *data)
-{
- if (notif_type != SUBSYS_BEFORE_SHUTDOWN) {
- sdio_al_logi(&sdio_al->gen_log, MODULE_NAME ": %s: got "
- "notification %ld", __func__, notif_type);
- return NOTIFY_DONE;
- }
-
- sdio_al_reset();
- return NOTIFY_OK;
-}
-
-static struct notifier_block sdio_al_nb = {
- .notifier_call = sdio_al_subsys_notifier_cb,
-};
-#endif
-
-/**
- * Module Init.
- *
- * @warn: allocate sdio_al context before registering driver.
- *
- */
-static int __init sdio_al_init(void)
-{
- int ret = 0;
- int i;
-
- pr_debug(MODULE_NAME ":sdio_al_init\n");
-
- pr_info(MODULE_NAME ":SDIO-AL SW version %s\n",
- DRV_VERSION);
-
- sdio_al = kzalloc(sizeof(struct sdio_al), GFP_KERNEL);
- if (sdio_al == NULL)
- return -ENOMEM;
-
- for (i = 0; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
- sdio_al->devices[i] = NULL;
-
- sdio_al->unittest_mode = false;
-
- sdio_al->debug.debug_lpm_on = debug_lpm_on;
- sdio_al->debug.debug_data_on = debug_data_on;
- sdio_al->debug.debug_close_on = debug_close_on;
-
-#ifdef CONFIG_DEBUG_FS
- sdio_al_debugfs_init();
-#endif
-
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
- sdio_al->subsys_notif_handle = subsys_notif_register_notifier(
- "external_modem", &sdio_al_nb);
-#endif
-
- ret = platform_driver_register(&msm_sdio_al_driver);
- if (ret) {
- pr_err(MODULE_NAME ": platform_driver_register failed: %d\n",
- ret);
- goto exit;
- }
-
- sdio_register_driver(&sdio_al_sdiofn_driver);
-
- spin_lock_init(&sdio_al->gen_log.log_lock);
-
-exit:
- if (ret)
- kfree(sdio_al);
- return ret;
-}
-
-/**
- * Module Exit.
- *
- * Free allocated memory.
- * Disable SDIO-Card.
- * Unregister driver.
- *
- */
-static void __exit sdio_al_exit(void)
-{
- if (sdio_al == NULL)
- return;
-
- pr_debug(MODULE_NAME ":sdio_al_exit\n");
-
-#ifdef CONFIG_MSM_SUBSYSTEM_RESTART
- subsys_notif_unregister_notifier(
- sdio_al->subsys_notif_handle, &sdio_al_nb);
-#endif
-
- sdio_al_tear_down();
-
- sdio_unregister_driver(&sdio_al_sdiofn_driver);
-
- kfree(sdio_al);
-
-#ifdef CONFIG_DEBUG_FS
- sdio_al_debugfs_cleanup();
-#endif
-
- platform_driver_unregister(&msm_sdio_al_driver);
-
- pr_debug(MODULE_NAME ":sdio_al_exit complete\n");
-}
-
-module_init(sdio_al_init);
-module_exit(sdio_al_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SDIO Abstraction Layer");
-MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/arch/arm/mach-msm/sdio_al_dloader.c b/arch/arm/mach-msm/sdio_al_dloader.c
deleted file mode 100644
index 167c163..0000000
--- a/arch/arm/mach-msm/sdio_al_dloader.c
+++ /dev/null
@@ -1,2541 +0,0 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Downloader
- *
- * To be used with Qualcomm's SDIO-Client connected to this host.
- */
-
-/* INCLUDES */
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/wakelock.h>
-#include <linux/mmc/card.h>
-#include <linux/dma-mapping.h>
-#include <mach/dma.h>
-#include <linux/mmc/sdio_func.h>
-#include "sdio_al_private.h"
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kthread.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-#include <linux/debugfs.h>
-
-/* DEFINES AND MACROS */
-#define MAX_NUM_DEVICES 1
-#define TTY_SDIO_DEV "tty_sdio_0"
-#define TTY_SDIO_DEV_TEST "tty_sdio_test_0"
-#define SDIOC_MAILBOX_ADDRESS 0
-#define SDIO_DL_BLOCK_SIZE 512
-#define SDIO_DL_MAIN_THREAD_NAME "sdio_tty_main_thread"
-#define SDIOC_DL_BUFF_ADDRESS 0
-#define SDIOC_UP_BUFF_ADDRESS 0x4
-#define SDIOC_DL_BUFF_SIZE_OFFSET 0x8
-#define SDIOC_UP_BUFF_SIZE_OFFSET 0xC
-#define SDIOC_DL_WR_PTR 0x10
-#define SDIOC_DL_RD_PTR 0x14
-#define SDIOC_UL_WR_PTR 0x18
-#define SDIOC_UL_RD_PTR 0x1C
-#define SDIOC_EXIT_PTR 0x20
-#define SDIOC_OP_MODE_PTR 0x24
-#define SDIOC_PTRS_OFFSET 0x10
-#define SDIOC_PTR_REGS_SIZE 0x10
-#define SDIOC_CFG_REGS_SIZE 0x10
-#define WRITE_RETRIES 0xFFFFFFFF
-#define INPUT_SPEED 4800
-#define OUTPUT_SPEED 4800
-#define SDIOC_EXIT_CODE 0xDEADDEAD
-#define SLEEP_MS 10
-#define PRINTING_GAP 200
-#define TIMER_DURATION 10
-#define PUSH_TIMER_DURATION 5000
-#define MULTIPLE_RATIO 1
-#define MS_IN_SEC 1000
-#define BITS_IN_BYTE 8
-#define BYTES_IN_KB 1024
-#define WRITE_TILL_END_RETRIES 5
-#define SDIO_DLD_NORMAL_MODE_NAME "SDIO DLD NORMAL MODE"
-#define SDIO_DLD_BOOT_TEST_MODE_NAME "SDIO DLD BOOT TEST MODE"
-#define SDIO_DLD_AMSS_TEST_MODE_NAME "SDIO DLD AMSS TEST MODE"
-#define TEST_NAME_MAX_SIZE 30
-#define PUSH_STRING
-#define SDIO_DLD_OUTGOING_BUFFER_SIZE (48*1024*MULTIPLE_RATIO)
-
-/* FORWARD DECLARATIONS */
-static int sdio_dld_open(struct tty_struct *tty, struct file *file);
-static void sdio_dld_close(struct tty_struct *tty, struct file *file);
-static int sdio_dld_write_callback(struct tty_struct *tty,
- const unsigned char *buf, int count);
-static int sdio_dld_write_room(struct tty_struct *tty);
-static int sdio_dld_main_task(void *card);
-static void sdio_dld_print_info(void);
-#ifdef CONFIG_DEBUG_FS
-static int sdio_dld_debug_info_open(struct inode *inode, struct file *file);
-static ssize_t sdio_dld_debug_info_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos);
-#endif
-
-
-/* STRUCTURES AND TYPES */
-enum sdio_dld_op_mode {
- SDIO_DLD_NO_MODE = 0,
- SDIO_DLD_NORMAL_MODE = 1,
- SDIO_DLD_BOOT_TEST_MODE = 2,
- SDIO_DLD_AMSS_TEST_MODE = 3,
- SDIO_DLD_NUM_OF_MODES,
-};
-
-struct sdioc_reg_sequential_chunk_ptrs {
- unsigned int dl_wr_ptr;
- unsigned int dl_rd_ptr;
- unsigned int up_wr_ptr;
- unsigned int up_rd_ptr;
-};
-
-struct sdioc_reg_sequential_chunk_cfg {
- unsigned int dl_buff_address;
- unsigned int up_buff_address;
- unsigned int dl_buff_size;
- unsigned int ul_buff_size;
-};
-
-struct sdioc_reg {
- unsigned int reg_val;
- unsigned int reg_offset;
-};
-
-struct sdioc_reg_chunk {
- struct sdioc_reg dl_buff_address;
- struct sdioc_reg up_buff_address;
- struct sdioc_reg dl_buff_size;
- struct sdioc_reg ul_buff_size;
- struct sdioc_reg dl_wr_ptr;
- struct sdioc_reg dl_rd_ptr;
- struct sdioc_reg up_wr_ptr;
- struct sdioc_reg up_rd_ptr;
- struct sdioc_reg good_to_exit_ptr;
-};
-
-struct sdio_data {
- char *data;
- int offset_read_p;
- int offset_write_p;
- int buffer_size;
- int num_of_bytes_in_use;
-};
-
-struct sdio_dld_data {
- struct sdioc_reg_chunk sdioc_reg;
- struct sdio_data incoming_data;
- struct sdio_data outgoing_data;
-};
-
-struct sdio_dld_wait_event {
- wait_queue_head_t wait_event;
- int wake_up_signal;
-};
-
-struct sdio_dld_task {
- struct task_struct *dld_task;
- const char *task_name;
- struct sdio_dld_wait_event exit_wait;
- atomic_t please_close;
-};
-
-#ifdef CONFIG_DEBUG_FS
-struct sdio_dloader_debug {
- struct dentry *sdio_dld_debug_root;
- struct dentry *sdio_al_dloader;
-};
-
-const struct file_operations sdio_dld_debug_info_ops = {
- .open = sdio_dld_debug_info_open,
- .write = sdio_dld_debug_info_write,
-};
-#endif
-
-struct sdio_downloader {
- int sdioc_boot_func;
- struct sdio_dld_wait_event write_callback_event;
- struct sdio_dld_task dld_main_thread;
- struct tty_driver *tty_drv;
- struct tty_struct *tty_str;
- struct sdio_dld_data sdio_dloader_data;
- struct mmc_card *card;
- int(*done_callback)(void);
- struct sdio_dld_wait_event main_loop_event;
- struct timer_list timer;
- unsigned int poll_ms;
- struct timer_list push_timer;
- unsigned int push_timer_ms;
- enum sdio_dld_op_mode op_mode;
- char op_mode_name[TEST_NAME_MAX_SIZE];
-};
-
-struct sdio_dld_global_info {
- int global_bytes_write_toio;
- int global_bytes_write_tty;
- int global_bytes_read_fromio;
- int global_bytes_push_tty;
- u64 start_time;
- u64 end_time;
- u64 delta_jiffies;
- unsigned int time_msec;
- unsigned int throughput;
- int cl_dl_wr_ptr;
- int cl_dl_rd_ptr;
- int cl_up_wr_ptr;
- int cl_up_rd_ptr;
- int host_read_ptr;
- int host_write_ptr;
- int cl_dl_buffer_size;
- int cl_up_buffer_size;
- int host_outgoing_buffer_size;
- int cl_dl_buffer_address;
- int cl_up_buffer_address;
-};
-
-static const struct tty_operations sdio_dloader_tty_ops = {
- .open = sdio_dld_open,
- .close = sdio_dld_close,
- .write = sdio_dld_write_callback,
- .write_room = sdio_dld_write_room,
-};
-
-/* GLOBAL VARIABLES */
-struct sdio_downloader *sdio_dld;
-struct sdio_dld_global_info sdio_dld_info;
-static char outgoing_data_buffer[SDIO_DLD_OUTGOING_BUFFER_SIZE];
-
-static DEFINE_SPINLOCK(lock1);
-static unsigned long lock_flags1;
-static DEFINE_SPINLOCK(lock2);
-static unsigned long lock_flags2;
-
-/*
- * sdio_op_mode sets the operation mode of the sdio_dloader -
- * it may be in NORMAL_MODE, BOOT_TEST_MODE or AMSS_TEST_MODE
- */
-static int sdio_op_mode = (int)SDIO_DLD_NORMAL_MODE;
-module_param(sdio_op_mode, int, 0);
-
-#ifdef CONFIG_DEBUG_FS
-
-struct sdio_dloader_debug sdio_dld_debug;
-
-#define ARR_SIZE 30000
-#define SDIO_DLD_DEBUGFS_INIT_VALUE 87654321
-#define SDIO_DLD_DEBUGFS_CASE_1_CODE 11111111
-#define SDIO_DLD_DEBUGFS_CASE_2_CODE 22222222
-#define SDIO_DLD_DEBUGFS_CASE_3_CODE 33333333
-#define SDIO_DLD_DEBUGFS_CASE_4_CODE 44444444
-#define SDIO_DLD_DEBUGFS_CASE_5_CODE 55555555
-#define SDIO_DLD_DEBUGFS_CASE_6_CODE 66666666
-#define SDIO_DLD_DEBUGFS_CASE_7_CODE 77777777
-#define SDIO_DLD_DEBUGFS_CASE_8_CODE 88888888
-#define SDIO_DLD_DEBUGFS_CASE_9_CODE 99999999
-#define SDIO_DLD_DEBUGFS_CASE_10_CODE 10101010
-#define SDIO_DLD_DEBUGFS_CASE_11_CODE 11001100
-#define SDIO_DLD_DEBUGFS_CASE_12_CODE 12001200
-#define SDIO_DLD_DEBUGFS_LOOP_WAIT 7
-#define SDIO_DLD_DEBUGFS_LOOP_WAKEUP 8
-#define SDIO_DLD_DEBUGFS_CB_WAIT 3
-#define SDIO_DLD_DEBUGFS_CB_WAKEUP 4
-
-static int curr_index;
-struct ptrs {
- int h_w_ptr;
- int h_r_ptr;
- int c_u_w_ptr;
- int c_u_r_ptr;
- int code;
- int h_has_to_send;
- int c_has_to_receive;
- int min_of;
- int reserve2;
- int tty_count;
- int write_tty;
- int write_toio;
- int loop_wait_wake;
- int cb_wait_wake;
- int c_d_w_ptr;
- int c_d_r_ptr;
- int to_read;
- int push_to_tty;
- int global_tty_send;
- int global_sdio_send;
- int global_tty_received;
- int global_sdio_received;
- int reserve22;
- int reserve23;
- int reserve24;
- int reserve25;
- int reserve26;
- int reserve27;
- int reserve28;
- int reserve29;
- int reserve30;
- int reserve31;
-};
-
-struct global_data {
- int curr_i;
- int duration_ms;
- int global_bytes_sent;
- int throughput_Mbs;
- int host_outgoing_buffer_size_KB;
- int client_up_buffer_size_KB;
- int client_dl_buffer_size_KB;
- int client_dl_buffer_address;
- int client_up_buffer_address;
- int global_bytes_received;
- int global_bytes_pushed;
- int reserve11;
- int reserve12;
- int reserve13;
- int reserve14;
- int reserve15;
- int reserve16;
- int reserve17;
- int reserve18;
- int reserve19;
- int reserve20;
- int reserve21;
- int reserve22;
- int reserve23;
- int reserve24;
- int reserve25;
- int reserve26;
- int reserve27;
- int reserve28;
- int reserve29;
- int reserve30;
- int reserve31;
- struct ptrs ptr_array[ARR_SIZE];
-};
-
-static struct global_data gd;
-static struct debugfs_blob_wrapper blob;
-static struct dentry *root;
-static struct dentry *dld;
-
-struct debugfs_global {
- int global_8k_has;
- int global_9k_has;
- int global_min;
- int global_count;
- int global_write_tty;
- int global_write_toio;
- int global_bytes_cb_tty;
- int global_to_read;
- int global_push_to_tty;
- int global_tty_send;
- int global_sdio_send;
- int global_sdio_received;
- int global_tty_push;
-};
-
-static struct debugfs_global debugfs_glob;
-
-static void update_standard_fields(int index)
-{
-
- gd.ptr_array[index].global_tty_send =
- sdio_dld_info.global_bytes_write_tty;
- gd.ptr_array[index].global_sdio_send =
- sdio_dld_info.global_bytes_write_toio;
- gd.ptr_array[index].global_tty_received =
- sdio_dld_info.global_bytes_push_tty;
- gd.ptr_array[index].global_sdio_received =
- sdio_dld_info.global_bytes_read_fromio;
-}
-
-static void update_gd(int code)
-{
- struct sdioc_reg_chunk *reg_str =
- &sdio_dld->sdio_dloader_data.sdioc_reg;
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
- int index = curr_index%ARR_SIZE;
-
- gd.curr_i = curr_index;
- gd.duration_ms = 0;
- gd.global_bytes_sent = 0;
- gd.throughput_Mbs = 0;
- gd.host_outgoing_buffer_size_KB = 0;
- gd.client_up_buffer_size_KB = 0;
- gd.client_dl_buffer_size_KB = 0;
- gd.client_dl_buffer_address = 0;
- gd.client_up_buffer_address = 0;
- gd.global_bytes_received = 0;
- gd.global_bytes_pushed = 0;
- gd.reserve11 = 0;
- gd.reserve12 = 0;
- gd.reserve13 = 0;
- gd.reserve14 = 0;
- gd.reserve15 = 0;
- gd.reserve16 = 0;
- gd.reserve17 = 0;
- gd.reserve18 = 0;
- gd.reserve19 = 0;
- gd.reserve20 = 0;
- gd.reserve21 = 0;
- gd.reserve22 = 0;
- gd.reserve23 = 0;
- gd.reserve24 = 0;
- gd.reserve25 = 0;
- gd.reserve26 = 0;
- gd.reserve27 = 0;
- gd.reserve28 = 0;
- gd.reserve29 = 0;
- gd.reserve30 = 0;
- gd.reserve31 = 0;
-
- gd.ptr_array[index].h_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*0*/
- gd.ptr_array[index].h_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*1*/
- gd.ptr_array[index].c_u_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*2*/
- gd.ptr_array[index].c_u_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*3*/
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_INIT_VALUE; /*4*/
- gd.ptr_array[index].h_has_to_send = SDIO_DLD_DEBUGFS_INIT_VALUE;/*5*/
- gd.ptr_array[index].c_has_to_receive =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*6*/
- gd.ptr_array[index].min_of = SDIO_DLD_DEBUGFS_INIT_VALUE; /*7*/
- gd.ptr_array[index].reserve2 = SDIO_DLD_DEBUGFS_INIT_VALUE; /*8*/
- gd.ptr_array[index].tty_count = SDIO_DLD_DEBUGFS_INIT_VALUE; /*9*/
- gd.ptr_array[index].write_tty = SDIO_DLD_DEBUGFS_INIT_VALUE; /*A*/
- gd.ptr_array[index].write_toio = SDIO_DLD_DEBUGFS_INIT_VALUE; /*B*/
- gd.ptr_array[index].loop_wait_wake =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*C*/
- gd.ptr_array[index].cb_wait_wake = SDIO_DLD_DEBUGFS_INIT_VALUE; /*D*/
- gd.ptr_array[index].c_d_w_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*E*/
- gd.ptr_array[index].c_d_r_ptr = SDIO_DLD_DEBUGFS_INIT_VALUE; /*F*/
- gd.ptr_array[index].to_read =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x10*/
- gd.ptr_array[index].push_to_tty =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x11*/
- gd.ptr_array[index].global_tty_send =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x12*/
- gd.ptr_array[index].global_sdio_send =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x13*/
- gd.ptr_array[index].global_tty_received =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x14*/
- gd.ptr_array[index].global_sdio_received =
- SDIO_DLD_DEBUGFS_INIT_VALUE; /*0x15*/
- gd.ptr_array[index].reserve22 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve23 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve24 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve25 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve26 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve27 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve28 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve29 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve30 = SDIO_DLD_DEBUGFS_INIT_VALUE;
- gd.ptr_array[index].reserve31 = SDIO_DLD_DEBUGFS_INIT_VALUE;
-
- switch (code) {
- case SDIO_DLD_DEBUGFS_CASE_1_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_1_CODE;
- gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
- gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
- gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val;
- gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val;
- gd.ptr_array[index].c_d_w_ptr = reg_str->dl_wr_ptr.reg_val;
- gd.ptr_array[index].c_d_r_ptr = reg_str->dl_rd_ptr.reg_val;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_2_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_2_CODE;
- gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val;
- gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val;
- gd.ptr_array[index].h_has_to_send = debugfs_glob.global_8k_has;
- gd.ptr_array[index].c_has_to_receive =
- debugfs_glob.global_9k_has;
- gd.ptr_array[index].min_of = debugfs_glob.global_min;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_3_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_3_CODE;
- gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
- gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
- gd.ptr_array[index].write_tty = debugfs_glob.global_write_tty;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_4_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_4_CODE;
- gd.ptr_array[index].h_w_ptr = outgoing->offset_write_p;
- gd.ptr_array[index].h_r_ptr = outgoing->offset_read_p;
- gd.ptr_array[index].c_u_r_ptr = reg_str->up_rd_ptr.reg_val;
- gd.ptr_array[index].c_u_w_ptr = reg_str->up_wr_ptr.reg_val;
- gd.ptr_array[index].write_toio =
- debugfs_glob.global_write_toio;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_5_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_5_CODE;
- gd.ptr_array[index].tty_count = debugfs_glob.global_count;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_6_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_6_CODE;
- gd.ptr_array[index].loop_wait_wake = 7;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_7_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_7_CODE;
- gd.ptr_array[index].loop_wait_wake = 8;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_8_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_8_CODE;
- gd.ptr_array[index].cb_wait_wake = 3;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_9_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_9_CODE;
- gd.ptr_array[index].cb_wait_wake = 4;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_10_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_10_CODE;
- gd.ptr_array[index].cb_wait_wake =
- debugfs_glob.global_bytes_cb_tty;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_11_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_11_CODE;
- gd.ptr_array[index].to_read = debugfs_glob.global_to_read;
- break;
-
- case SDIO_DLD_DEBUGFS_CASE_12_CODE:
- gd.ptr_array[index].code = SDIO_DLD_DEBUGFS_CASE_12_CODE;
- gd.ptr_array[index].push_to_tty =
- debugfs_glob.global_push_to_tty;
- break;
-
- default:
- break;
- }
- update_standard_fields(index);
- curr_index++;
-}
-
-static int bootloader_debugfs_init(void)
-{
- /* /sys/kernel/debug/bootloader there will be dld_arr file */
- root = debugfs_create_dir("bootloader", NULL);
- if (!root) {
- pr_info(MODULE_NAME ": %s - creating root dir "
- "failed\n", __func__);
- return -ENODEV;
- }
-
- blob.data = &gd;
- blob.size = sizeof(struct global_data);
- dld = debugfs_create_blob("dld_arr", S_IRUGO, root, &blob);
- if (!dld) {
- debugfs_remove_recursive(root);
- pr_err(MODULE_NAME ": %s, failed to create debugfs entry\n",
- __func__);
- return -ENODEV;
- }
-
- return 0;
-}
-
-/*
-* for triggering the sdio_dld info use:
-* echo 1 > /sys/kernel/debug/sdio_al_dld/sdio_al_dloader_info
-*/
-static int sdio_dld_debug_init(void)
-{
- sdio_dld_debug.sdio_dld_debug_root =
- debugfs_create_dir("sdio_al_dld", NULL);
- if (!sdio_dld_debug.sdio_dld_debug_root) {
- pr_err(MODULE_NAME ": %s - Failed to create folder. "
- "sdio_dld_debug_root is NULL",
- __func__);
- return -ENOENT;
- }
-
- sdio_dld_debug.sdio_al_dloader = debugfs_create_file(
- "sdio_al_dloader_info",
- S_IRUGO | S_IWUGO,
- sdio_dld_debug.sdio_dld_debug_root,
- NULL,
- &sdio_dld_debug_info_ops);
-
- if (!sdio_dld_debug.sdio_al_dloader) {
- pr_err(MODULE_NAME ": %s - Failed to create a file. "
- "sdio_al_dloader is NULL",
- __func__);
- debugfs_remove(sdio_dld_debug.sdio_dld_debug_root);
- sdio_dld_debug.sdio_dld_debug_root = NULL;
- return -ENOENT;
- }
-
- return 0;
-}
-
-static int sdio_dld_debug_info_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t sdio_dld_debug_info_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- sdio_dld_print_info();
- return count;
-}
-#endif /* CONFIG_DEBUG_FS */
-
-static void sdio_dld_print_info(void)
-{
-
- sdio_dld_info.end_time = get_jiffies_64(); /* read the current time */
- sdio_dld_info.delta_jiffies =
- sdio_dld_info.end_time - sdio_dld_info.start_time;
- sdio_dld_info.time_msec = jiffies_to_msecs(sdio_dld_info.delta_jiffies);
-
- sdio_dld_info.throughput = sdio_dld_info.global_bytes_write_toio *
- BITS_IN_BYTE / sdio_dld_info.time_msec;
- sdio_dld_info.throughput /= MS_IN_SEC;
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - DURATION IN MSEC = %d\n",
- __func__,
- sdio_dld_info.time_msec);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - BYTES WRITTEN ON SDIO BUS "
- "= %d...BYTES SENT BY TTY = %d",
- __func__,
- sdio_dld_info.global_bytes_write_toio,
- sdio_dld_info.global_bytes_write_tty);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - BYTES RECEIVED ON SDIO BUS "
- "= %d...BYTES SENT TO TTY = %d",
- __func__,
- sdio_dld_info.global_bytes_read_fromio,
- sdio_dld_info.global_bytes_push_tty);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - THROUGHPUT=%d Mbit/Sec",
- __func__, sdio_dld_info.throughput);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT DL_BUFFER_SIZE=%d"
- " KB..CLIENT UL_BUFFER=%d KB\n",
- __func__,
- sdio_dld_info.cl_dl_buffer_size/BYTES_IN_KB,
- sdio_dld_info.cl_up_buffer_size/BYTES_IN_KB);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST OUTGOING BUFFER_SIZE"
- "=%d KB",
- __func__,
- sdio_dld_info.host_outgoing_buffer_size/BYTES_IN_KB);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT DL BUFFER "
- "ADDRESS = 0x%x", __func__,
- sdio_dld_info.cl_dl_buffer_address);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT UP BUFFER "
- "ADDRESS = 0x%x",
- __func__,
- sdio_dld_info.cl_up_buffer_address);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - UPLINK BUFFER - "
- "READ POINTER = %d", __func__,
- sdio_dld_info.cl_up_rd_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - UPLINK BUFFER - "
- "WRITE POINTER = %d", __func__,
- sdio_dld_info.cl_up_wr_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - DOWNLINK BUFFER - "
- "READ POINTER = %d", __func__,
- sdio_dld_info.cl_dl_rd_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - CLIENT - DOWNLINK BUFFER - "
- "WRITE POINTER = %d", __func__,
- sdio_dld_info.cl_dl_wr_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST - OUTGOING BUFFER - "
- "READ POINTER = %d", __func__,
- sdio_dld_info.host_read_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - HOST - OUTGOING BUFFER - "
- "WRITE POINTER = %d", __func__,
- sdio_dld_info.host_write_ptr);
-
- pr_info(MODULE_NAME ": %s, FLASHLESS BOOT - END DEBUG INFO", __func__);
-}
-
-/**
- * sdio_dld_set_op_mode
- * sets the op_mode and the name of the op_mode. Also, in case
- * it's invalid mode sets op_mode to SDIO_DLD_NORMAL_MODE
- *
- * @op_mode: the operation mode to be set
- * @return NONE
- */
-static void sdio_dld_set_op_mode(enum sdio_dld_op_mode op_mode)
-{
- sdio_dld->op_mode = op_mode;
-
- switch (op_mode) {
- case SDIO_DLD_NORMAL_MODE:
- memcpy(sdio_dld->op_mode_name,
- SDIO_DLD_NORMAL_MODE_NAME, TEST_NAME_MAX_SIZE);
- break;
- case SDIO_DLD_BOOT_TEST_MODE:
- memcpy(sdio_dld->op_mode_name,
- SDIO_DLD_BOOT_TEST_MODE_NAME, TEST_NAME_MAX_SIZE);
- break;
- case SDIO_DLD_AMSS_TEST_MODE:
- memcpy(sdio_dld->op_mode_name,
- SDIO_DLD_AMSS_TEST_MODE_NAME, TEST_NAME_MAX_SIZE);
- break;
- default:
- sdio_dld->op_mode = SDIO_DLD_NORMAL_MODE;
- pr_err(MODULE_NAME ": %s - Invalid Op_Mode = %d. Settings "
- "Op_Mode to default - NORMAL_MODE\n",
- __func__, op_mode);
- memcpy(sdio_dld->op_mode_name,
- SDIO_DLD_NORMAL_MODE_NAME, TEST_NAME_MAX_SIZE);
- break;
- }
-
- if (sdio_dld->op_mode_name != NULL) {
- pr_info(MODULE_NAME ": %s - FLASHLESS BOOT - Op_Mode is set to "
- "%s\n", __func__, sdio_dld->op_mode_name);
- } else {
- pr_info(MODULE_NAME ": %s - FLASHLESS BOOT - op_mode_name is "
- "NULL\n", __func__);
- }
-}
-
-/**
- * sdio_dld_allocate_local_buffers
- * allocates local outgoing and incoming buffers and also sets
- * threshold for outgoing data.
- *
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_allocate_local_buffers(void)
-{
- struct sdioc_reg_chunk *reg_str = &sdio_dld->sdio_dloader_data.
- sdioc_reg;
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
- struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
-
- incoming->data =
- kzalloc(reg_str->dl_buff_size.reg_val, GFP_KERNEL);
-
- if (!incoming->data) {
- pr_err(MODULE_NAME ": %s - param ""incoming->data"" is NULL. "
- "Couldn't allocate incoming_data local buffer\n",
- __func__);
- return -ENOMEM;
- }
-
- incoming->buffer_size = reg_str->dl_buff_size.reg_val;
-
- outgoing->data = outgoing_data_buffer;
-
- outgoing->buffer_size = SDIO_DLD_OUTGOING_BUFFER_SIZE;
-
- if (outgoing->buffer_size !=
- reg_str->ul_buff_size.reg_val*MULTIPLE_RATIO) {
- pr_err(MODULE_NAME ": %s - HOST outgoing buffer size (%d bytes)"
- "must be a multiple of ClIENT uplink buffer size (%d "
- "bytes). HOST_SIZE == n*CLIENT_SIZE.(n=1,2,3...)\n",
- __func__,
- SDIO_DLD_OUTGOING_BUFFER_SIZE,
- reg_str->ul_buff_size.reg_val);
- kfree(incoming->data);
- return -EINVAL;
- }
-
- /* keep sdio_dld_info up to date */
- sdio_dld_info.host_outgoing_buffer_size = outgoing->buffer_size;
-
- return 0;
-}
-
-/**
- * sdio_dld_dealloc_local_buffers frees incoming and outgoing
- * buffers.
- *
- * @return None.
- */
-static void sdio_dld_dealloc_local_buffers(void)
-{
- kfree((void *)sdio_dld->sdio_dloader_data.incoming_data.data);
-}
-
-/**
- * mailbox_to_seq_chunk_read_cfg
- * reads 4 configuration registers of mailbox from str_func, as
- * a sequentail chunk in memory, and updates global struct
- * accordingly.
- *
- * @str_func: a pointer to func struct.
- * @return 0 on success or negative value on error.
- */
-static int mailbox_to_seq_chunk_read_cfg(struct sdio_func *str_func)
-{
- struct sdioc_reg_sequential_chunk_cfg seq_chunk;
- struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
- int status = 0;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_claim_host(str_func);
-
- /* reading SDIOC_MAILBOX_SIZE bytes from SDIOC_MAILBOX_ADDRESS */
- status = sdio_memcpy_fromio(str_func,
- (void *)&seq_chunk,
- SDIOC_MAILBOX_ADDRESS,
- SDIOC_CFG_REGS_SIZE);
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
- " READING CFG MAILBOX failed. status=%d.\n",
- __func__, status);
- }
-
- sdio_release_host(str_func);
-
- reg->dl_buff_address.reg_val = seq_chunk.dl_buff_address;
- reg->up_buff_address.reg_val = seq_chunk.up_buff_address;
- reg->dl_buff_size.reg_val = seq_chunk.dl_buff_size;
- reg->ul_buff_size.reg_val = seq_chunk.ul_buff_size;
-
- /* keep sdio_dld_info up to date */
- sdio_dld_info.cl_dl_buffer_size = seq_chunk.dl_buff_size;
- sdio_dld_info.cl_up_buffer_size = seq_chunk.ul_buff_size;
- sdio_dld_info.cl_dl_buffer_address = seq_chunk.dl_buff_address;
- sdio_dld_info.cl_up_buffer_address = seq_chunk.up_buff_address;
-
- return status;
-}
-
-/**
- * mailbox_to_seq_chunk_read_ptrs
- * reads 4 pointers registers of mailbox from str_func, as a
- * sequentail chunk in memory, and updates global struct
- * accordingly.
- *
- * @str_func: a pointer to func struct.
- * @return 0 on success or negative value on error.
- */
-static int mailbox_to_seq_chunk_read_ptrs(struct sdio_func *str_func)
-{
- struct sdioc_reg_sequential_chunk_ptrs seq_chunk;
- struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
- int status = 0;
-
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
- static int counter = 1;
- static int offset_write_p;
- static int offset_read_p;
- static int up_wr_ptr;
- static int up_rd_ptr;
- static int dl_wr_ptr;
- static int dl_rd_ptr;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_claim_host(str_func);
-
- /* reading SDIOC_MAILBOX_SIZE bytes from SDIOC_MAILBOX_ADDRESS */
- status = sdio_memcpy_fromio(str_func,
- (void *)&seq_chunk,
- SDIOC_PTRS_OFFSET,
- SDIOC_PTR_REGS_SIZE);
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
- " READING PTRS MAILBOX failed. status=%d.\n",
- __func__, status);
- }
-
- sdio_release_host(str_func);
-
- reg->dl_rd_ptr.reg_val = seq_chunk.dl_rd_ptr;
- reg->dl_wr_ptr.reg_val = seq_chunk.dl_wr_ptr;
- reg->up_rd_ptr.reg_val = seq_chunk.up_rd_ptr;
- reg->up_wr_ptr.reg_val = seq_chunk.up_wr_ptr;
-
- /* keeping sdio_dld_info up to date */
- sdio_dld_info.cl_dl_rd_ptr = seq_chunk.dl_rd_ptr;
- sdio_dld_info.cl_dl_wr_ptr = seq_chunk.dl_wr_ptr;
- sdio_dld_info.cl_up_rd_ptr = seq_chunk.up_rd_ptr;
- sdio_dld_info.cl_up_wr_ptr = seq_chunk.up_wr_ptr;
-
-
- /* DEBUG - if there was a change in value */
- if ((offset_write_p != outgoing->offset_write_p) ||
- (offset_read_p != outgoing->offset_read_p) ||
- (up_wr_ptr != reg->up_wr_ptr.reg_val) ||
- (up_rd_ptr != reg->up_rd_ptr.reg_val) ||
- (dl_wr_ptr != reg->dl_wr_ptr.reg_val) ||
- (dl_rd_ptr != reg->dl_rd_ptr.reg_val) ||
- (counter % PRINTING_GAP == 0)) {
- counter = 1;
- pr_debug(MODULE_NAME ": %s MailBox pointers: BLOCK_SIZE=%d, "
- "hw=%d, hr=%d, cuw=%d, cur=%d, cdw=%d, cdr=%d\n",
- __func__,
- SDIO_DL_BLOCK_SIZE,
- outgoing->offset_write_p,
- outgoing->offset_read_p,
- reg->up_wr_ptr.reg_val,
- reg->up_rd_ptr.reg_val,
- reg->dl_wr_ptr.reg_val,
- reg->dl_rd_ptr.reg_val);
-
-#ifdef CONFIG_DEBUG_FS
- update_gd(SDIO_DLD_DEBUGFS_CASE_1_CODE);
-#endif
- /* update static variables */
- offset_write_p = outgoing->offset_write_p;
- offset_read_p = outgoing->offset_read_p;
- up_wr_ptr = reg->up_wr_ptr.reg_val;
- up_rd_ptr = reg->up_rd_ptr.reg_val;
- dl_wr_ptr = reg->dl_wr_ptr.reg_val;
- dl_rd_ptr = reg->dl_rd_ptr.reg_val;
- } else {
- counter++;
- }
- return status;
-}
-
-/**
- * sdio_dld_init_func
- * enables the sdio func, and sets the func block size.
- *
- * @str_func: a pointer to func struct.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_init_func(struct sdio_func *str_func)
-{
- int status1 = 0;
- int status2 = 0;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_claim_host(str_func);
-
- status1 = sdio_enable_func(str_func);
- if (status1) {
- sdio_release_host(str_func);
- pr_err(MODULE_NAME ": %s - sdio_enable_func() failed. "
- "status=%d\n", __func__, status1);
- return status1;
- }
-
- status2 = sdio_set_block_size(str_func, SDIO_DL_BLOCK_SIZE);
- if (status2) {
- pr_err(MODULE_NAME ": %s - sdio_set_block_size() failed. "
- "status=%d\n", __func__, status2);
- status1 = sdio_disable_func(str_func);
- if (status1) {
- pr_err(MODULE_NAME ": %s - sdio_disable_func() "
- "failed. status=%d\n", __func__, status1);
- }
- sdio_release_host(str_func);
- return status2;
- }
-
- sdio_release_host(str_func);
- str_func->max_blksize = SDIO_DL_BLOCK_SIZE;
- return 0;
-}
-
-/**
- * sdio_dld_allocate_buffers
- * initializes the sdio func, and then reads the mailbox, in
- * order to allocate incoming and outgoing buffers according to
- * the size that was read from the mailbox.
- *
- * @str_func: a pointer to func struct.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_allocate_buffers(struct sdio_func *str_func)
-{
- int status = 0;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- status = mailbox_to_seq_chunk_read_cfg(str_func);
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "mailbox_to_seq_chunk_read_cfg(). status=%d\n",
- __func__, status);
- return status;
- }
-
- status = sdio_dld_allocate_local_buffers();
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_dld_allocate_local_buffers(). status=%d\n",
- __func__, status);
- return status;
- }
- return 0;
-}
-
-/**
- * sdio_dld_create_thread
- * creates thread and wakes it up.
- *
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_create_thread(void)
-{
- sdio_dld->dld_main_thread.task_name = SDIO_DL_MAIN_THREAD_NAME;
-
- sdio_dld->dld_main_thread.dld_task =
- kthread_create(sdio_dld_main_task,
- (void *)(sdio_dld->card),
- sdio_dld->dld_main_thread.task_name);
-
- if (IS_ERR(sdio_dld->dld_main_thread.dld_task)) {
- pr_err(MODULE_NAME ": %s - kthread_create() failed\n",
- __func__);
- return -ENOMEM;
- }
- wake_up_process(sdio_dld->dld_main_thread.dld_task);
- return 0;
-}
-
-/**
- * start_timer
- * sets the timer and starts.
- *
- * @timer: the timer to configure and add
- * @ms: the ms until it expires
- * @return None.
- */
-static void start_timer(struct timer_list *timer, unsigned int ms)
-{
- if ((ms == 0) || (timer == NULL)) {
- pr_err(MODULE_NAME ": %s - invalid parameter", __func__);
- } else {
- timer->expires = jiffies +
- msecs_to_jiffies(ms);
- add_timer(timer);
- }
-}
-
-/**
- * sdio_dld_timer_handler
- * this is the timer handler. whenever it is invoked, it wakes
- * up the main loop task, and the write callback, and starts
- * the timer again.
- *
- * @data: a pointer to the tty device driver structure.
- * @return None.
- */
-
-static void sdio_dld_timer_handler(unsigned long data)
-{
- pr_debug(MODULE_NAME " Timer Expired\n");
- spin_lock_irqsave(&lock2, lock_flags2);
- if (sdio_dld->main_loop_event.wake_up_signal == 0) {
- sdio_dld->main_loop_event.wake_up_signal = 1;
- wake_up(&sdio_dld->main_loop_event.wait_event);
- }
- spin_unlock_irqrestore(&lock2, lock_flags2);
-
- sdio_dld->write_callback_event.wake_up_signal = 1;
- wake_up(&sdio_dld->write_callback_event.wait_event);
-
- start_timer(&sdio_dld->timer, sdio_dld->poll_ms);
-}
-
-/**
- * sdio_dld_push_timer_handler
- * this is a timer handler of the push_timer.
- *
- * @data: a pointer to the tty device driver structure.
- * @return None.
- */
-static void sdio_dld_push_timer_handler(unsigned long data)
-{
- pr_err(MODULE_NAME " %s - Push Timer Expired... Trying to "
- "push data to TTY Core for over then %d ms.\n",
- __func__, sdio_dld->push_timer_ms);
-}
-
-/**
- * sdio_dld_open
- * this is the open callback of the tty driver.
- * it initializes the sdio func, allocates the buffers, and
- * creates the main thread.
- *
- * @tty: a pointer to the tty struct.
- * @file: file descriptor.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_open(struct tty_struct *tty, struct file *file)
-{
- int status = 0;
- int func_in_array =
- REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func);
- struct sdio_func *str_func = sdio_dld->card->sdio_func[func_in_array];
-
- sdio_dld->tty_str = tty;
- sdio_dld->tty_str->low_latency = 1;
- sdio_dld->tty_str->icanon = 0;
- set_bit(TTY_NO_WRITE_SPLIT, &sdio_dld->tty_str->flags);
-
- pr_info(MODULE_NAME ": %s, TTY DEVICE FOR FLASHLESS BOOT OPENED\n",
- __func__);
- sdio_dld_info.start_time = get_jiffies_64(); /* read the current time */
-
- if (!tty) {
- pr_err(MODULE_NAME ": %s - param ""tty"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- atomic_set(&sdio_dld->dld_main_thread.please_close, 0);
- sdio_dld->dld_main_thread.exit_wait.wake_up_signal = 0;
-
- status = sdio_dld_allocate_buffers(str_func);
- if (status) {
- pr_err(MODULE_NAME ": %s, failed in "
- "sdio_dld_allocate_buffers(). status=%d\n",
- __func__, status);
- return status;
- }
-
- /* init waiting event of the write callback */
- init_waitqueue_head(&sdio_dld->write_callback_event.wait_event);
-
- /* init waiting event of the main loop */
- init_waitqueue_head(&sdio_dld->main_loop_event.wait_event);
-
- /* configure and init the timer */
- sdio_dld->poll_ms = TIMER_DURATION;
- init_timer(&sdio_dld->timer);
- sdio_dld->timer.data = (unsigned long) sdio_dld;
- sdio_dld->timer.function = sdio_dld_timer_handler;
- sdio_dld->timer.expires = jiffies +
- msecs_to_jiffies(sdio_dld->poll_ms);
- add_timer(&sdio_dld->timer);
-
- sdio_dld->push_timer_ms = PUSH_TIMER_DURATION;
- init_timer(&sdio_dld->push_timer);
- sdio_dld->push_timer.data = (unsigned long) sdio_dld;
- sdio_dld->push_timer.function = sdio_dld_push_timer_handler;
-
- status = sdio_dld_create_thread();
- if (status) {
- del_timer_sync(&sdio_dld->timer);
- del_timer_sync(&sdio_dld->push_timer);
- sdio_dld_dealloc_local_buffers();
- pr_err(MODULE_NAME ": %s, failed in sdio_dld_create_thread()."
- "status=%d\n", __func__, status);
- return status;
- }
- return 0;
-}
-
-/**
- * sdio_dld_close
- * this is the close callback of the tty driver. it requests
- * the main thread to exit, and waits for notification of it.
- * it also de-allocates the buffers, and unregisters the tty
- * driver and device.
- *
- * @tty: a pointer to the tty struct.
- * @file: file descriptor.
- * @return None.
- */
-static void sdio_dld_close(struct tty_struct *tty, struct file *file)
-{
- int status = 0;
- struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
-
- /* informing the SDIOC that it can exit boot phase */
- sdio_dld->sdio_dloader_data.sdioc_reg.good_to_exit_ptr.reg_val =
- SDIOC_EXIT_CODE;
-
- atomic_set(&sdio_dld->dld_main_thread.please_close, 1);
-
- pr_debug(MODULE_NAME ": %s - CLOSING - WAITING...", __func__);
-
- wait_event(sdio_dld->dld_main_thread.exit_wait.wait_event,
- sdio_dld->dld_main_thread.exit_wait.wake_up_signal);
- pr_debug(MODULE_NAME ": %s - CLOSING - WOKE UP...", __func__);
-
- del_timer_sync(&sdio_dld->timer);
- del_timer_sync(&sdio_dld->push_timer);
-
- sdio_dld_dealloc_local_buffers();
-
- tty_unregister_device(sdio_dld->tty_drv, 0);
-
- status = tty_unregister_driver(sdio_dld->tty_drv);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - tty_unregister_driver() failed\n",
- __func__);
- }
-
-#ifdef CONFIG_DEBUG_FS
- gd.curr_i = curr_index;
- gd.duration_ms = sdio_dld_info.time_msec;
- gd.global_bytes_sent = sdio_dld_info.global_bytes_write_toio;
- gd.global_bytes_received = 0;
- gd.throughput_Mbs = sdio_dld_info.throughput;
- gd.host_outgoing_buffer_size_KB = sdio_dld->sdio_dloader_data.
- outgoing_data.buffer_size/BYTES_IN_KB;
- gd.client_up_buffer_size_KB = reg->ul_buff_size.reg_val/BYTES_IN_KB;
- gd.client_dl_buffer_size_KB = reg->dl_buff_size.reg_val/BYTES_IN_KB;
- gd.client_dl_buffer_address = reg->dl_buff_address.reg_val;
- gd.client_up_buffer_address = reg->up_buff_address.reg_val;
- gd.global_bytes_received = sdio_dld_info.global_bytes_read_fromio;
- gd.global_bytes_pushed = sdio_dld_info.global_bytes_push_tty;
-#endif
-
- /* saving register values before deallocating sdio_dld
- in order to use it in sdio_dld_print_info() through shell command */
- sdio_dld_info.cl_dl_rd_ptr = reg->dl_rd_ptr.reg_val;
- sdio_dld_info.cl_dl_wr_ptr = reg->dl_wr_ptr.reg_val;
- sdio_dld_info.cl_up_rd_ptr = reg->up_rd_ptr.reg_val;
- sdio_dld_info.cl_up_wr_ptr = reg->up_wr_ptr.reg_val;
-
- sdio_dld_info.host_read_ptr =
- sdio_dld->sdio_dloader_data.outgoing_data.offset_read_p;
-
- sdio_dld_info.host_write_ptr =
- sdio_dld->sdio_dloader_data.outgoing_data.offset_write_p;
-
- sdio_dld_info.cl_dl_buffer_size =
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_size.reg_val;
-
- sdio_dld_info.cl_up_buffer_size =
- sdio_dld->sdio_dloader_data.sdioc_reg.ul_buff_size.reg_val;
-
- sdio_dld_info.host_outgoing_buffer_size =
- sdio_dld->sdio_dloader_data.outgoing_data.buffer_size;
-
- sdio_dld_info.cl_dl_buffer_address =
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_address.reg_val;
-
- sdio_dld_info.cl_up_buffer_address =
- sdio_dld->sdio_dloader_data.sdioc_reg.up_buff_address.reg_val;
-
- sdio_dld_print_info();
-
- if (sdio_dld->done_callback)
- sdio_dld->done_callback();
-
- pr_info(MODULE_NAME ": %s - Freeing sdio_dld data structure, and "
- " returning...", __func__);
- kfree(sdio_dld);
-}
-
-/**
- * writing_size_to_buf
- * writes from src buffer into dest buffer. if dest buffer
- * reaches its end, rollover happens.
- *
- * @dest: destination buffer.
- * @src: source buffer.
- * @dest_wr_ptr: writing pointer in destination buffer.
- * @dest_size: destination buffer size.
- * @dest_rd_ptr: reading pointer in destination buffer.
- * @size_to_write: size of bytes to write.
- * @return -how many bytes actually written to destination
- * buffer.
- *
- * ONLY destination buffer is treated as cyclic buffer.
- */
-static int writing_size_to_buf(char *dest,
- const unsigned char *src,
- int *dest_wr_ptr,
- int dest_size,
- int dest_rd_ptr,
- int size_to_write)
-{
- int actually_written = 0;
- int size_to_add = *dest_wr_ptr;
-
- if (!dest) {
- pr_err(MODULE_NAME ": %s - param ""dest"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!src) {
- pr_err(MODULE_NAME ": %s - param ""src"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!dest_wr_ptr) {
- pr_err(MODULE_NAME ": %s - param ""dest_wr_ptr"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- for (actually_written = 0 ;
- actually_written < size_to_write ; ++actually_written) {
- /* checking if buffer is full */
- if (((size_to_add + 1) % dest_size) == dest_rd_ptr) {
- *dest_wr_ptr = size_to_add;
- return actually_written;
- }
-
- dest[size_to_add] = src[actually_written];
- size_to_add = (size_to_add+1)%dest_size;
- }
-
- *dest_wr_ptr = size_to_add;
-
- return actually_written;
-}
-
-/**
- * sdioc_bytes_till_end_of_buffer - this routine calculates how many bytes are
- * empty/in use. if calculation requires rap around - it will ignore the rap
- * around and will do the calculation untill the end of the buffer
- *
- * @write_ptr: writing pointer.
- * @read_ptr: reading pointer.
- * @total_size: buffer size.
- * @free_bytes: return value-how many free bytes.
- * @bytes_in_use: return value-how many bytes in use.
- * @return 0 on success or negative value on error.
- *
- * buffer is treated as a cyclic buffer.
- */
-static int sdioc_bytes_till_end_of_buffer(int write_ptr,
- int read_ptr,
- int total_size,
- int *free_bytes,
- int *bytes_in_use)
-{
- if (!free_bytes) {
- pr_err(MODULE_NAME ": %s - param ""free_bytes"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!bytes_in_use) {
- pr_err(MODULE_NAME ": %s - param ""bytes_in_use"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (write_ptr >= read_ptr) {
- if (read_ptr == 0)
- *free_bytes = total_size - write_ptr - 1;
- else
- *free_bytes = total_size - write_ptr;
- *bytes_in_use = write_ptr - read_ptr;
- } else {
- *bytes_in_use = total_size - read_ptr;
- *free_bytes = read_ptr - write_ptr - 1;
- }
-
- return 0;
-}
-
-/**
- * sdioc_bytes_free_in_buffer
- * this routine calculates how many bytes are free in a buffer
- * and how many are in use, according to its reading and
- * writing pointer offsets.
- *
- * @write_ptr: writing pointer.
- * @read_ptr: reading pointer.
- * @total_size: buffer size.
- * @free_bytes: return value-how many free bytes in buffer.
- * @bytes_in_use: return value-how many bytes in use in buffer.
- * @return 0 on success or negative value on error.
- *
- * buffer is treated as a cyclic buffer.
- */
-static int sdioc_bytes_free_in_buffer(int write_ptr,
- int read_ptr,
- int total_size,
- int *free_bytes,
- int *bytes_in_use)
-{
- if (!free_bytes) {
- pr_err(MODULE_NAME ": %s - param ""free_bytes"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!bytes_in_use) {
- pr_err(MODULE_NAME ": %s - param ""bytes_in_use"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- /* if pointers equel - buffers are empty. nothing to read/write */
-
- if (write_ptr >= read_ptr)
- *bytes_in_use = write_ptr - read_ptr;
- else
- *bytes_in_use = total_size - (read_ptr - write_ptr);
-
- *free_bytes = total_size - *bytes_in_use - 1;
-
- return 0;
-}
-
-/*
-* sdio_dld_write_room
-*
-* This is the write_room function of the tty driver.
-*
-* @tty: pointer to tty struct.
-* @return free bytes for write.
-*
-*/
-static int sdio_dld_write_room(struct tty_struct *tty)
-{
- return sdio_dld->sdio_dloader_data.outgoing_data.buffer_size;
-}
-
-/**
- * sdio_dld_write_callback
- * this is the write callback of the tty driver.
- *
- * @tty: pointer to tty struct.
- * @buf: buffer to write from.
- * @count: number of bytes to write.
- * @return bytes written or negative value on error.
- *
- * if destination buffer has not enough room for the incoming
- * data, returns an error.
- */
-static int sdio_dld_write_callback(struct tty_struct *tty,
- const unsigned char *buf, int count)
-{
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
- int dst_free_bytes = 0;
- int dummy = 0;
- int status = 0;
- int bytes_written = 0;
- int total_written = 0;
- static int write_retry;
- int pending_to_write = count;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_count = count;
- update_gd(SDIO_DLD_DEBUGFS_CASE_5_CODE);
-#endif
-
- pr_debug(MODULE_NAME ": %s - WRITING CALLBACK CALLED WITH %d bytes\n",
- __func__, count);
-
- if (!outgoing->data) {
- pr_err(MODULE_NAME ": %s - param ""outgoing->data"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- pr_debug(MODULE_NAME ": %s - WRITE CALLBACK size to write to outgoing"
- " buffer %d\n", __func__, count);
-
- /* as long as there is something to write to outgoing buffer */
- do {
- int bytes_to_write = 0;
- status = sdioc_bytes_free_in_buffer(
- outgoing->offset_write_p,
- outgoing->offset_read_p,
- outgoing->buffer_size,
- &dst_free_bytes,
- &dummy);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdioc_bytes_free_in_buffer(). status=%d\n",
- __func__, status);
- return status;
- }
-
- /*
- * if there is free room in outgoing buffer
- * lock mutex and request trigger notification from the main
- * task. unlock mutex, and wait for sinal
- */
- if (dst_free_bytes > 0) {
- write_retry = 0;
- /*
- * if there is more data to write to outgoing buffer
- * than it can receive, wait for signal from main task
- */
- if (pending_to_write > dst_free_bytes) {
-
- /* sampling updated dst_free_bytes */
- status = sdioc_bytes_free_in_buffer(
- outgoing->offset_write_p,
- outgoing->offset_read_p,
- outgoing->buffer_size,
- &dst_free_bytes,
- &dummy);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in "
- "Function "
- "sdioc_bytes_free_in_buffer(). "
- "status=%d\n", __func__, status);
- return status;
- }
- }
-
- bytes_to_write = min(pending_to_write, dst_free_bytes);
- bytes_written =
- writing_size_to_buf(outgoing->data,
- buf+total_written,
- &outgoing->offset_write_p,
- outgoing->buffer_size,
- outgoing->offset_read_p,
- bytes_to_write);
-
- /* keeping sdio_dld_info up to date */
- sdio_dld_info.host_write_ptr =
- sdio_dld->sdio_dloader_data.
- outgoing_data.offset_write_p;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_write_tty = bytes_written;
- update_gd(SDIO_DLD_DEBUGFS_CASE_3_CODE);
-#endif
- sdio_dld_info.global_bytes_write_tty += bytes_written;
-
- spin_lock_irqsave(&lock2, lock_flags2);
- if (sdio_dld->main_loop_event.wake_up_signal == 0) {
- sdio_dld->main_loop_event.wake_up_signal = 1;
- wake_up(&sdio_dld->main_loop_event.wait_event);
- }
- spin_unlock_irqrestore(&lock2, lock_flags2);
-
- /*
- * although outgoing buffer has enough room, writing
- * failed
- */
- if (bytes_written != bytes_to_write) {
- pr_err(MODULE_NAME ": %s - couldn't write "
- "%d bytes to " "outgoing buffer."
- "bytes_written=%d\n",
- __func__, bytes_to_write,
- bytes_written);
- return -EIO;
- }
-
- total_written += bytes_written;
- pending_to_write -= bytes_written;
- outgoing->num_of_bytes_in_use += bytes_written;
-
- pr_debug(MODULE_NAME ": %s - WRITE CHUNK to outgoing "
- "buffer. pending_to_write=%d, "
- "outgoing_free_bytes=%d, "
- "bytes_written=%d\n",
- __func__,
- pending_to_write,
- dst_free_bytes,
- bytes_written);
-
- } else {
- write_retry++;
-
- pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - NO ROOM."
- " pending_to_write=%d, write_retry=%d\n",
- __func__,
- pending_to_write,
- write_retry);
-
- spin_lock_irqsave(&lock1, lock_flags1);
- sdio_dld->write_callback_event.wake_up_signal = 0;
- spin_unlock_irqrestore(&lock1, lock_flags1);
-
- pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - "
- "WAITING...", __func__);
-#ifdef CONFIG_DEBUG_FS
- update_gd(SDIO_DLD_DEBUGFS_CASE_8_CODE);
-#endif
- wait_event(sdio_dld->write_callback_event.wait_event,
- sdio_dld->write_callback_event.
- wake_up_signal);
-#ifdef CONFIG_DEBUG_FS
- update_gd(SDIO_DLD_DEBUGFS_CASE_9_CODE);
-#endif
- pr_debug(MODULE_NAME ": %s - WRITE CALLBACK - "
- "WOKE UP...", __func__);
- }
- } while (pending_to_write > 0 && write_retry < WRITE_RETRIES);
-
- if (pending_to_write > 0) {
-
- pr_err(MODULE_NAME ": %s - WRITE CALLBACK - pending data is "
- "%d out of %d > 0. total written in this "
- "callback = %d\n",
- __func__, pending_to_write, count, total_written);
- }
-
- if (write_retry == WRITE_RETRIES) {
- pr_err(MODULE_NAME ": %s, write_retry=%d= max\n",
- __func__, write_retry);
- }
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_bytes_cb_tty = total_written;
- update_gd(SDIO_DLD_DEBUGFS_CASE_10_CODE);
-#endif
-
- return total_written;
-}
-
-/**
- * sdio_memcpy_fromio_wrapper -
- * reads from sdioc, and updats the sdioc registers according
- * to how many bytes were actually read.
- *
- * @str_func: a pointer to func struct.
- * @client_rd_ptr: sdioc value of downlink read ptr.
- * @client_wr_ptr: sdioc value of downlink write ptr.
- * @buffer_to_store: buffer to store incoming data.
- * @address_to_read: address to start reading from in sdioc.
- * @size_to_read: size of bytes to read.
- * @client_buffer_size: sdioc downlink buffer size.
- * @return 0 on success or negative value on error.
- */
-static int sdio_memcpy_fromio_wrapper(struct sdio_func *str_func,
- unsigned int client_rd_ptr,
- unsigned int client_wr_ptr,
- void *buffer_to_store,
- unsigned int address_to_read_from,
- int size_to_read,
- int client_buffer_size)
-{
- int status = 0;
- struct sdioc_reg_chunk *reg_str =
- &sdio_dld->sdio_dloader_data.sdioc_reg;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!buffer_to_store) {
- pr_err(MODULE_NAME ": %s - param ""buffer_to_store"" is "
- "NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (size_to_read < 0) {
- pr_err(MODULE_NAME ": %s - invalid size to read=%d\n",
- __func__, size_to_read);
- return -EINVAL;
- }
-
- sdio_claim_host(str_func);
-
- pr_debug(MODULE_NAME ": %s, READING DATA - from add %d, "
- "size_to_read=%d\n",
- __func__, address_to_read_from, size_to_read);
-
- status = sdio_memcpy_fromio(str_func,
- (void *)buffer_to_store,
- address_to_read_from,
- size_to_read);
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_fromio()"
- " DATA failed. status=%d.\n",
- __func__, status);
- sdio_release_host(str_func);
- return status;
- }
-
- /* updating an offset according to cyclic buffer size */
- reg_str->dl_rd_ptr.reg_val =
- (reg_str->dl_rd_ptr.reg_val + size_to_read) %
- client_buffer_size;
- /* keeping sdio_dld_info up to date */
- sdio_dld_info.cl_dl_rd_ptr = reg_str->dl_rd_ptr.reg_val;
-
- status = sdio_memcpy_toio(str_func,
- reg_str->dl_rd_ptr.reg_offset,
- (void *)®_str->dl_rd_ptr.reg_val,
- sizeof(reg_str->dl_rd_ptr.reg_val));
-
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
- "UPDATE PTR failed. status=%d.\n",
- __func__, status);
- }
-
- sdio_release_host(str_func);
- return status;
-}
-
-/**
- * sdio_memcpy_toio_wrapper
- * writes to sdioc, and updats the sdioc registers according
- * to how many bytes were actually read.
- *
- * @str_func: a pointer to func struct.
- * @client_wr_ptr: sdioc downlink write ptr.
- * @h_read_ptr: host incoming read ptrs
- * @buf_write_from: buffer to write from.
- * @bytes_to_write: number of bytes to write.
- * @return 0 on success or negative value on error.
- */
-static int sdio_memcpy_toio_wrapper(struct sdio_func *str_func,
- unsigned int client_wr_ptr,
- unsigned int h_read_ptr,
- void *buf_write_from,
- int bytes_to_write)
-{
- int status = 0;
- struct sdioc_reg_chunk *reg_str =
- &sdio_dld->sdio_dloader_data.sdioc_reg;
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!buf_write_from) {
- pr_err(MODULE_NAME ": %s - param ""buf_write_from"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_claim_host(str_func);
-
- pr_debug(MODULE_NAME ": %s, WRITING DATA TOIO to address 0x%x, "
- "bytes_to_write=%d\n",
- __func__,
- reg_str->up_buff_address.reg_val + reg_str->up_wr_ptr.reg_val,
- bytes_to_write);
-
- status = sdio_memcpy_toio(str_func,
- reg_str->up_buff_address.reg_val +
- reg_str->up_wr_ptr.reg_val,
- (void *) (outgoing->data + h_read_ptr),
- bytes_to_write);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
- "DATA failed. status=%d.\n", __func__, status);
- sdio_release_host(str_func);
- return status;
- }
-
- sdio_dld_info.global_bytes_write_toio += bytes_to_write;
- outgoing->num_of_bytes_in_use -= bytes_to_write;
-
- /*
- * if writing to client succeeded, then
- * 1. update the client up_wr_ptr
- * 2. update the host outgoing rd ptr
- **/
- reg_str->up_wr_ptr.reg_val =
- ((reg_str->up_wr_ptr.reg_val + bytes_to_write) %
- reg_str->ul_buff_size.reg_val);
-
- /* keeping sdio_dld_info up to date */
- sdio_dld_info.cl_up_wr_ptr = reg_str->up_wr_ptr.reg_val;
-
- outgoing->offset_read_p =
- ((outgoing->offset_read_p + bytes_to_write) %
- outgoing->buffer_size);
-
- /* keeping sdio_dld_info up to date*/
- sdio_dld_info.host_read_ptr = outgoing->offset_read_p;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_write_toio = bytes_to_write;
- update_gd(SDIO_DLD_DEBUGFS_CASE_4_CODE);
-#endif
-
- /* updating uplink write pointer according to size that was written */
- status = sdio_memcpy_toio(str_func,
- reg_str->up_wr_ptr.reg_offset,
- (void *)(®_str->up_wr_ptr.reg_val),
- sizeof(reg_str->up_wr_ptr.reg_val));
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
- "UPDATE PTR failed. status=%d.\n",
- __func__, status);
- }
-
- sdio_release_host(str_func);
- return status;
-}
-
-/**
- * sdio_dld_read
- * reads from sdioc
- *
- * @client_rd_ptr: sdioc downlink read ptr.
- * @client_wr_ptr: sdioc downlink write ptr.
- * @reg_str: sdioc register shadowing struct.
- * @str_func: a pointer to func struct.
- * @bytes_read:how many bytes read.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_read(unsigned int client_rd_ptr,
- unsigned int client_wr_ptr,
- struct sdioc_reg_chunk *reg_str,
- struct sdio_func *str_func,
- int *bytes_read)
-{
- int status = 0;
- struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
-
- if (!reg_str) {
- pr_err(MODULE_NAME ": %s - param ""reg_str"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!bytes_read) {
- pr_err(MODULE_NAME ": %s - param ""bytes_read"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- /* there is data to read in ONE chunk */
- if (client_wr_ptr > client_rd_ptr) {
- status = sdio_memcpy_fromio_wrapper(
- str_func,
- client_rd_ptr,
- client_wr_ptr,
- (void *)incoming->data,
- reg_str->dl_buff_address.reg_val + client_rd_ptr,
- client_wr_ptr - client_rd_ptr,
- reg_str->dl_buff_size.reg_val);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_memcpy_fromio_wrapper(). "
- "SINGLE CHUNK READ. status=%d\n",
- __func__, status);
- return status;
- }
-
- incoming->num_of_bytes_in_use += client_wr_ptr - client_rd_ptr;
- *bytes_read = client_wr_ptr - client_rd_ptr;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_to_read =
- client_wr_ptr - client_rd_ptr;
- update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
-#endif
- }
-
- /* there is data to read in TWO chunks */
- else {
- int dl_buf_size = reg_str->dl_buff_size.reg_val;
- int tail_size = dl_buf_size - client_rd_ptr;
-
- /* reading chunk#1: from rd_ptr to the end of the buffer */
- status = sdio_memcpy_fromio_wrapper(
- str_func,
- client_rd_ptr,
- dl_buf_size,
- (void *)incoming->data,
- reg_str->dl_buff_address.reg_val + client_rd_ptr,
- tail_size,
- dl_buf_size);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_memcpy_fromio_wrapper(). "
- "1 of 2 CHUNKS READ. status=%d\n",
- __func__, status);
- return status;
- }
-
- incoming->num_of_bytes_in_use += tail_size;
- *bytes_read = tail_size;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_to_read = tail_size;
- update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
-#endif
-
- /* reading chunk#2: reading from beginning buffer */
- status = sdio_memcpy_fromio_wrapper(
- str_func,
- client_rd_ptr,
- client_wr_ptr,
- (void *)(incoming->data + tail_size),
- reg_str->dl_buff_address.reg_val,
- client_wr_ptr,
- reg_str->dl_buff_size.reg_val);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_memcpy_fromio_wrapper(). "
- "2 of 2 CHUNKS READ. status=%d\n",
- __func__, status);
- return status;
- }
-
- incoming->num_of_bytes_in_use += client_wr_ptr;
- *bytes_read += client_wr_ptr;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_to_read = client_wr_ptr;
- update_gd(SDIO_DLD_DEBUGFS_CASE_11_CODE);
-#endif
- }
- return 0;
-}
-
-/**
- * sdio_dld_main_task
- * sdio downloader main task. reads mailboxf checks if there is
- * anything to read, checks if host has anything to
- * write.
- *
- * @card: a pointer to mmc_card.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_main_task(void *card)
-{
- int status = 0;
- struct tty_struct *tty = sdio_dld->tty_str;
- struct sdioc_reg_chunk *reg_str =
- &sdio_dld->sdio_dloader_data.sdioc_reg;
- int func = sdio_dld->sdioc_boot_func;
- struct sdio_func *str_func = NULL;
- struct sdio_data *outgoing = &sdio_dld->sdio_dloader_data.outgoing_data;
- struct sdio_data *incoming = &sdio_dld->sdio_dloader_data.incoming_data;
- struct sdio_dld_task *task = &sdio_dld->dld_main_thread;
- int retries = 0;
-#ifdef PUSH_STRING
- int bytes_pushed = 0;
-#endif
-
- msleep(SLEEP_MS);
-
- if (!card) {
- pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!tty) {
- pr_err(MODULE_NAME ": %s - param ""tty"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- str_func = ((struct mmc_card *)card)->
- sdio_func[REAL_FUNC_TO_FUNC_IN_ARRAY(func)];
-
- if (!str_func) {
- pr_err(MODULE_NAME ": %s - param ""str_func"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- while (true) {
- /* client pointers for both buffers */
- int client_ul_wr_ptr = 0;
- int client_ul_rd_ptr = 0;
- int client_dl_wr_ptr = 0;
- int client_dl_rd_ptr = 0;
-
- /* host pointer for outgoing buffer */
- int h_out_wr_ptr = 0;
- int h_out_rd_ptr = 0;
-
- int h_bytes_rdy_wr = 0;
- int c_bytes_rdy_rcve = 0;
-
- int need_to_write = 0;
- int need_to_read = 0;
-
- /*
- * forever, checking for signal to die, then read MailBox.
- * if nothing to read or nothing to write to client, sleep,
- * and again read MailBox
- */
- do {
- int dummy = 0;
-
- /* checking if a signal to die was sent */
- if (atomic_read(&task->please_close) == 1) {
-
- pr_debug(MODULE_NAME ": %s - 0x%x was written "
- "to 9K\n", __func__, SDIOC_EXIT_CODE);
-
- sdio_claim_host(str_func);
-
- /* returned value is not checked on purpose */
- sdio_memcpy_toio(
- str_func,
- reg_str->good_to_exit_ptr.reg_offset,
- (void *)®_str->good_to_exit_ptr.
- reg_val,
- sizeof(reg_str->good_to_exit_ptr.
- reg_val));
-
- sdio_release_host(str_func);
-
- task->exit_wait.wake_up_signal = 1;
- wake_up(&task->exit_wait.wait_event);
- return 0;
- }
-
- status = mailbox_to_seq_chunk_read_ptrs(str_func);
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "mailbox_to_seq_chunk_read_ptrs(). "
- "status=%d\n", __func__, status);
- return status;
- }
-
- /* calculate how many bytes the host has send */
- h_out_wr_ptr = outgoing->offset_write_p;
- h_out_rd_ptr = outgoing->offset_read_p;
-
- status = sdioc_bytes_till_end_of_buffer(
- h_out_wr_ptr,
- h_out_rd_ptr,
- outgoing->buffer_size,
- &dummy,
- &h_bytes_rdy_wr);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdioc_bytes_till_end_of_buffer(). "
- "status=%d\n", __func__, status);
- return status;
- }
-
- /* is there something to read from client */
- client_dl_wr_ptr = reg_str->dl_wr_ptr.reg_val;
- client_dl_rd_ptr = reg_str->dl_rd_ptr.reg_val;
-
- if (client_dl_rd_ptr != client_dl_wr_ptr)
- need_to_read = 1;
-
- /*
- * calculate how many bytes the client can receive
- * from host
- */
- client_ul_wr_ptr = reg_str->up_wr_ptr.reg_val;
- client_ul_rd_ptr = reg_str->up_rd_ptr.reg_val;
-
- status = sdioc_bytes_till_end_of_buffer(
- client_ul_wr_ptr,
- client_ul_rd_ptr,
- reg_str->ul_buff_size.reg_val,
- &c_bytes_rdy_rcve,
- &dummy);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdioc_bytes_till_end_of_buffer(). "
- "status=%d\n", __func__, status);
- return status;
- }
-
- /* if host has anything to write */
- if (h_bytes_rdy_wr > 0)
- need_to_write = 1;
-
- if (need_to_write || need_to_read)
- break;
-
- spin_lock_irqsave(&lock2, lock_flags2);
- sdio_dld->main_loop_event.wake_up_signal = 0;
- spin_unlock_irqrestore(&lock2, lock_flags2);
-
- pr_debug(MODULE_NAME ": %s - MAIN LOOP - WAITING...\n",
- __func__);
-#ifdef CONFIG_DEBUG_FS
- update_gd(SDIO_DLD_DEBUGFS_CASE_6_CODE);
-#endif
- wait_event(sdio_dld->main_loop_event.wait_event,
- sdio_dld->main_loop_event.wake_up_signal);
-#ifdef CONFIG_DEBUG_FS
- update_gd(SDIO_DLD_DEBUGFS_CASE_7_CODE);
-#endif
-
- pr_debug(MODULE_NAME ": %s - MAIN LOOP - WOKE UP...\n",
- __func__);
-
- } while (1);
-
- /* CHECK IF THERE IS ANYTHING TO READ IN CLIENT */
- if (need_to_read) {
-#ifdef PUSH_STRING
- int num_push = 0;
- int left = 0;
- int bytes_read;
-#else
- int i;
-#endif
- need_to_read = 0;
-
- status = sdio_dld_read(client_dl_rd_ptr,
- client_dl_wr_ptr,
- reg_str,
- str_func,
- &bytes_read);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_dld_read(). status=%d\n",
- __func__, status);
- return status;
- }
-
- sdio_dld_info.global_bytes_read_fromio +=
- bytes_read;
-
- bytes_pushed = 0;
-#ifdef PUSH_STRING
- left = incoming->num_of_bytes_in_use;
- start_timer(&sdio_dld->push_timer,
- sdio_dld->push_timer_ms);
- do {
- num_push = tty_insert_flip_string(
- tty,
- incoming->data+bytes_pushed,
- left);
-
- bytes_pushed += num_push;
- left -= num_push;
- tty_flip_buffer_push(tty);
- } while (left != 0);
-
- del_timer(&sdio_dld->push_timer);
-
- if (bytes_pushed != incoming->num_of_bytes_in_use) {
- pr_err(MODULE_NAME ": %s - failed\n",
- __func__);
- }
-#else
- pr_debug(MODULE_NAME ": %s - NEED TO READ %d\n",
- __func__, incoming->num_of_bytes_in_use);
-
- for (i = 0 ; i < incoming->num_of_bytes_in_use ; ++i) {
- int err = 0;
- err = tty_insert_flip_char(tty,
- incoming->data[i],
- TTY_NORMAL);
- tty_flip_buffer_push(tty);
- }
-
- pr_debug(MODULE_NAME ": %s - JUST READ\n", __func__);
-#endif /*PUSH_STRING*/
- sdio_dld_info.global_bytes_push_tty +=
- incoming->num_of_bytes_in_use;
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_push_to_tty = bytes_read;
- update_gd(SDIO_DLD_DEBUGFS_CASE_12_CODE);
-#endif
- incoming->num_of_bytes_in_use = 0;
- tty_flip_buffer_push(tty);
- }
-
- /* CHECK IF THERE IS ANYTHING TO WRITE IN HOST AND HOW MUCH */
- if (need_to_write) {
- int dummy = 0;
-
- do {
- int bytes_to_write = min(c_bytes_rdy_rcve,
- h_bytes_rdy_wr);
-
- /*
- * in case nothing to send or no room to
- * receive
- */
- if (bytes_to_write == 0)
- break;
-
- if (client_ul_rd_ptr == 0 &&
- (client_ul_rd_ptr != client_ul_wr_ptr))
- break;
-
- /*
- * if client_rd_ptr points to start, but there
- * is data to read wait until WRITE_TILL_END
- * before writing a chunk of data, to avoid
- * writing until (BUF_SIZE - 1), because it will
- * yield an extra write of "1" bytes
- */
- if (client_ul_rd_ptr == 0 &&
- (client_ul_rd_ptr != client_ul_wr_ptr) &&
- retries < WRITE_TILL_END_RETRIES) {
- retries++;
- break;
- }
- retries = 0;
-
-#ifdef CONFIG_DEBUG_FS
- debugfs_glob.global_8k_has = h_bytes_rdy_wr;
- debugfs_glob.global_9k_has = c_bytes_rdy_rcve;
- debugfs_glob.global_min = bytes_to_write;
- update_gd(SDIO_DLD_DEBUGFS_CASE_2_CODE);
-#endif
- need_to_write = 0;
-
- pr_debug(MODULE_NAME ": %s - NEED TO WRITE "
- "TOIO %d\n",
- __func__, bytes_to_write);
-
- status = sdio_memcpy_toio_wrapper(
- str_func,
- reg_str->up_wr_ptr.reg_val,
- outgoing->offset_read_p,
- (void *)((char *)outgoing->data +
- outgoing->offset_read_p),
- bytes_to_write);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in "
- "Function "
- "sdio_memcpy_toio_wrapper(). "
- "SINGLE CHUNK WRITE. "
- "status=%d\n",
- __func__, status);
- return status;
- }
-
- sdio_claim_host(str_func);
-
- status = sdio_memcpy_fromio(
- str_func,
- (void *)®_str->up_rd_ptr.reg_val,
- SDIOC_UL_RD_PTR,
- sizeof(reg_str->up_rd_ptr.reg_val));
-
- if (status) {
- pr_err(MODULE_NAME ": %s - "
- "sdio_memcpy_fromio() "
- "failed. status=%d\n",
- __func__, status);
- sdio_release_host(str_func);
-
- return status;
- }
-
- sdio_release_host(str_func);
-
- spin_lock_irqsave(&lock1, lock_flags1);
- if (sdio_dld->write_callback_event.
- wake_up_signal == 0) {
- sdio_dld->write_callback_event.
- wake_up_signal = 1;
- wake_up(&sdio_dld->
- write_callback_event.
- wait_event);
- }
-
- spin_unlock_irqrestore(&lock1, lock_flags1);
- client_ul_wr_ptr = reg_str->up_wr_ptr.reg_val;
- client_ul_rd_ptr = reg_str->up_rd_ptr.reg_val;
-
- status = sdioc_bytes_till_end_of_buffer(
- client_ul_wr_ptr,
- client_ul_rd_ptr,
- reg_str->ul_buff_size.reg_val,
- &c_bytes_rdy_rcve,
- &dummy);
-
- /* calculate how many bytes host has to send */
- h_out_wr_ptr = outgoing->offset_write_p;
- h_out_rd_ptr = outgoing->offset_read_p;
-
- status = sdioc_bytes_till_end_of_buffer(
- h_out_wr_ptr,
- h_out_rd_ptr,
- outgoing->buffer_size,
- &dummy,
- &h_bytes_rdy_wr);
-
- } while (h_out_wr_ptr != h_out_rd_ptr);
- }
- }
- return 0;
-}
-
-/**
- * sdio_dld_init_global
- * initialization of sdio_dld global struct
- *
- * @card: a pointer to mmc_card.
- * @return 0 on success or negative value on error.
- */
-static int sdio_dld_init_global(struct mmc_card *card,
- int(*done)(void))
-{
- if (!card) {
- pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!done) {
- pr_err(MODULE_NAME ": %s - param ""done"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_dld->done_callback = done;
- sdio_dld->card = card;
- init_waitqueue_head(&sdio_dld->dld_main_thread.exit_wait.wait_event);
- sdio_dld->write_callback_event.wake_up_signal = 1;
- sdio_dld->main_loop_event.wake_up_signal = 1;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_size.reg_offset =
- SDIOC_DL_BUFF_SIZE_OFFSET;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_rd_ptr.reg_offset =
- SDIOC_DL_RD_PTR;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_wr_ptr.reg_offset =
- SDIOC_DL_WR_PTR;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.ul_buff_size.reg_offset =
- SDIOC_UP_BUFF_SIZE_OFFSET;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.up_rd_ptr.reg_offset =
- SDIOC_UL_RD_PTR;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.up_wr_ptr.reg_offset =
- SDIOC_UL_WR_PTR;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.good_to_exit_ptr.reg_offset =
- SDIOC_EXIT_PTR;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.dl_buff_address.reg_offset =
- SDIOC_DL_BUFF_ADDRESS;
-
- sdio_dld->sdio_dloader_data.sdioc_reg.up_buff_address.reg_offset =
- SDIOC_UP_BUFF_ADDRESS;
-
- sdio_dld_set_op_mode(SDIO_DLD_NORMAL_MODE);
-
- return 0;
-}
-
-/**
- * sdio_downloader_setup
- * initializes the TTY driver
- *
- * @card: a pointer to mmc_card.
- * @num_of_devices: number of devices.
- * @channel_number: channel number.
- * @return 0 on success or negative value on error.
- *
- * The TTY stack needs to know in advance how many devices it should
- * plan to manage. Use this call to set up the ports that will
- * be exported through SDIO.
- */
-int sdio_downloader_setup(struct mmc_card *card,
- unsigned int num_of_devices,
- int channel_number,
- int(*done)(void))
-{
- int status = 0;
- int result = 0;
- int func_in_array = 0;
- struct sdio_func *str_func = NULL;
- struct device *tty_dev;
-
- if (num_of_devices == 0 || num_of_devices > MAX_NUM_DEVICES) {
- pr_err(MODULE_NAME ": %s - invalid number of devices\n",
- __func__);
- return -EINVAL;
- }
-
- if (!card) {
- pr_err(MODULE_NAME ": %s - param ""card"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- if (!done) {
- pr_err(MODULE_NAME ": %s - param ""done"" is NULL.\n",
- __func__);
- return -EINVAL;
- }
-
- sdio_dld = kzalloc(sizeof(struct sdio_downloader), GFP_KERNEL);
- if (!sdio_dld) {
- pr_err(MODULE_NAME ": %s - couldn't allocate sdio_dld data "
- "structure.", __func__);
- return -ENOMEM;
- }
-
-#ifdef CONFIG_DEBUG_FS
- bootloader_debugfs_init();
-#endif /* CONFIG_DEBUG_FS */
-
- status = sdio_dld_init_global(card, done);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_dld_init_global(). status=%d\n",
- __func__, status);
- kfree(sdio_dld);
- return status;
- }
-
- sdio_dld->tty_drv = alloc_tty_driver(num_of_devices);
-
- if (!sdio_dld->tty_drv) {
- pr_err(MODULE_NAME ": %s - param ""sdio_dld->tty_drv"" is "
- "NULL.\n", __func__);
- kfree(sdio_dld);
- return -EINVAL;
- }
-
- sdio_dld_set_op_mode((enum sdio_dld_op_mode)sdio_op_mode);
-
- /* according to op_mode, a different tty device is created */
- if (sdio_dld->op_mode == SDIO_DLD_BOOT_TEST_MODE)
- sdio_dld->tty_drv->name = TTY_SDIO_DEV_TEST;
- else
- sdio_dld->tty_drv->name = TTY_SDIO_DEV;
-
- sdio_dld->tty_drv->owner = THIS_MODULE;
- sdio_dld->tty_drv->driver_name = "SDIO_Dloader";
-
- /* uses dynamically assigned dev_t values */
- sdio_dld->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
- sdio_dld->tty_drv->subtype = SERIAL_TYPE_NORMAL;
- sdio_dld->tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
- | TTY_DRIVER_RESET_TERMIOS;
-
- /* initializing the tty driver */
- sdio_dld->tty_drv->init_termios = tty_std_termios;
- sdio_dld->tty_drv->init_termios.c_cflag =
- B4800 | CS8 | CREAD | HUPCL | CLOCAL;
- sdio_dld->tty_drv->init_termios.c_ispeed = INPUT_SPEED;
- sdio_dld->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED;
-
- tty_set_operations(sdio_dld->tty_drv, &sdio_dloader_tty_ops);
-
- status = tty_register_driver(sdio_dld->tty_drv);
- if (status) {
- put_tty_driver(sdio_dld->tty_drv);
- pr_err(MODULE_NAME ": %s - tty_register_driver() failed\n",
- __func__);
-
- sdio_dld->tty_drv = NULL;
- kfree(sdio_dld);
- return status;
- }
-
- tty_dev = tty_register_device(sdio_dld->tty_drv, 0, NULL);
- if (IS_ERR(tty_dev)) {
- pr_err(MODULE_NAME ": %s - tty_register_device() "
- "failed\n", __func__);
- tty_unregister_driver(sdio_dld->tty_drv);
- kfree(sdio_dld);
- return PTR_ERR(tty_dev);
- }
-
- sdio_dld->sdioc_boot_func = SDIOC_CHAN_TO_FUNC_NUM(channel_number);
- func_in_array = REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func);
- str_func = sdio_dld->card->sdio_func[func_in_array];
- status = sdio_dld_init_func(str_func);
- if (status) {
- pr_err(MODULE_NAME ": %s - Failure in Function "
- "sdio_dld_init_func(). status=%d\n",
- __func__, status);
- goto exit_err;
- }
-
-#ifdef CONFIG_DEBUG_FS
- sdio_dld_debug_init();
-#endif
-
- sdio_claim_host(str_func);
-
- /*
- * notifing the client by writing what mode we are by writing
- * to a special register
- */
- status = sdio_memcpy_toio(str_func,
- SDIOC_OP_MODE_PTR,
- (void *)&sdio_dld->op_mode,
- sizeof(sdio_dld->op_mode));
-
- sdio_release_host(str_func);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - sdio_memcpy_toio() "
- "writing to OP_MODE_REGISTER failed. "
- "status=%d.\n",
- __func__, status);
- goto exit_err;
- }
-
- return 0;
-
-exit_err:
- tty_unregister_device(sdio_dld->tty_drv, 0);
- result = tty_unregister_driver(sdio_dld->tty_drv);
- if (result)
- pr_err(MODULE_NAME ": %s - tty_unregister_driver() "
- "failed. result=%d\n", __func__, -result);
- kfree(sdio_dld);
- return status;
-}
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SDIO Downloader");
-MODULE_AUTHOR("Yaniv Gardi <ygardi@codeaurora.org>");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/arch/arm/mach-msm/sdio_al_private.h b/arch/arm/mach-msm/sdio_al_private.h
deleted file mode 100644
index 3a5ab79..0000000
--- a/arch/arm/mach-msm/sdio_al_private.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Abstraction-Layer internal interface.
- */
-
-#ifndef __SDIO_AL_PRIVATE__
-#define __SDIO_AL_PRIVATE__
-
-#include <linux/mmc/card.h>
-#include <linux/platform_device.h>
-#include <mach/sdio_al.h>
-
-#define DRV_VERSION "1.30"
-#define MODULE_NAME "sdio_al"
-#define SDIOC_CHAN_TO_FUNC_NUM(x) ((x)+2)
-#define REAL_FUNC_TO_FUNC_IN_ARRAY(x) ((x)-1)
-#define SDIO_PREFIX "SDIO_"
-#define PEER_CHANNEL_NAME_SIZE 4
-#define CHANNEL_NAME_SIZE (sizeof(SDIO_PREFIX) + PEER_CHANNEL_NAME_SIZE)
-#define SDIO_TEST_POSTFIX_SIZE 5
-#define MAX_NUM_OF_SDIO_DEVICES 2
-#define TEST_CH_NAME_SIZE (CHANNEL_NAME_SIZE + SDIO_TEST_POSTFIX_SIZE)
-
-struct sdio_al_device; /* Forward Declaration */
-
-enum sdio_channel_state {
- SDIO_CHANNEL_STATE_INVALID, /* before reading software header */
- SDIO_CHANNEL_STATE_IDLE, /* channel valid, not opened */
- SDIO_CHANNEL_STATE_CLOSED, /* was closed */
- SDIO_CHANNEL_STATE_OPEN, /* opened */
- SDIO_CHANNEL_STATE_CLOSING, /* during flush, when closing */
-};
-/**
- * Peer SDIO-Client channel configuration.
- *
- * @is_ready - channel is ready and the data is valid.
- *
- * @max_rx_threshold - maximum rx threshold, according to the
- * total buffers size on the peer pipe.
- * @max_tx_threshold - maximum tx threshold, according to the
- * total buffers size on the peer pipe.
- * @tx_buf_size - size of a single buffer on the peer pipe; a
- * transfer smaller than the buffer size still
- * make the buffer unusable for the next transfer.
- * @max_packet_size
- * @is_host_ok_to_sleep - Host marks this bit when it's okay to
- * sleep (no pending transactions)
- */
-struct peer_sdioc_channel_config {
- u32 is_ready;
- u32 max_rx_threshold; /* Downlink */
- u32 max_tx_threshold; /* Uplink */
- u32 tx_buf_size;
- u32 max_packet_size;
- u32 is_host_ok_to_sleep;
- u32 is_packet_mode;
- u32 peer_operation;
- u32 is_low_latency_ch;
- u32 reserved[23];
-};
-
-
-/**
- * Peer SDIO-Client channel statsitics.
- *
- * @last_any_read_avail - the last read avail in all the
- * channels including this channel.
- * @last_read_avail - the last read_avail that was read from HW
- * mailbox.
- * @last_old_read_avail - the last read_avail channel shadow.
- * @total_notifs - the total number of read notifications sent
- * to this channel client
- * @total_read_times - the total number of successful sdio_read
- * calls for this channel
- */
-struct sdio_channel_statistics {
- int last_any_read_avail;
- int last_read_avail;
- int last_old_read_avail;
- int total_notifs;
- int total_read_times;
-};
-
-/**
- * SDIO Channel context.
- *
- * @name - channel name. Used by the caller to open the
- * channel.
- *
- * @read_threshold - Threshold on SDIO-Client mailbox for Rx
- * Data available bytes. When the limit exceed
- * the SDIO-Client generates an interrupt to the
- * host.
- *
- * @write_threshold - Threshold on SDIO-Client mailbox for Tx
- * Data available bytes. When the limit exceed
- * the SDIO-Client generates an interrupt to the
- * host.
- *
- * @def_read_threshold - Default theshold on SDIO-Client for Rx
- *
- * @min_write_avail - Threshold of minimal available bytes
- * to write. Below that threshold the host
- * will initiate reading the mailbox.
- *
- * @poll_delay_msec - Delay between polling the mailbox. When
- * the SDIO-Client doesn't generates EOT
- * interrupt for Rx Available bytes, the host
- * should poll the SDIO-Client mailbox.
- *
- * @is_packet_mode - The host get interrupt when a packet is
- * available at the SDIO-client (pipe EOT
- * indication).
- *
- * @num - channel number.
- *
- * @notify - Client's callback. Should not call sdio read/write.
- *
- * @priv - Client's private context, provided to callback.
- *
- * @is_valid - Channel is used (we have a list of
- * SDIO_AL_MAX_CHANNELS and not all of them are in
- * use).
- *
- * @is_open - Channel is open.
- *
- * @func - SDIO Function handle.
- *
- * @rx_pipe_index - SDIO-Client Pipe Index for Rx Data.
- *
- * @tx_pipe_index - SDIO-Client Pipe Index for Tx Data.
- *
- * @ch_lock - Channel lock to protect channel specific Data
- *
- * @rx_pending_bytes - Total number of Rx pending bytes, at Rx
- * packet list. Maximum of 16KB-1 limited by
- * SDIO-Client specification.
- *
- * @read_avail - Available bytes to read.
- *
- * @write_avail - Available bytes to write.
- *
- * @rx_size_list_head - The head of Rx Pending Packets List.
- *
- * @pdev - platform device - clients to probe for the sdio-al.
- *
- * @signature - Context Validity check.
- *
- * @sdio_al_dev - a pointer to the sdio_al_device instance of
- * this channel
- *
- * @statistics - channel statistics
- *
- */
-struct sdio_channel {
- /* Channel Configuration Parameters*/
- char name[CHANNEL_NAME_SIZE];
- char ch_test_name[TEST_CH_NAME_SIZE];
- int read_threshold;
- int write_threshold;
- int def_read_threshold;
- int threshold_change_cnt;
- int min_write_avail;
- int poll_delay_msec;
- int is_packet_mode;
- int is_low_latency_ch;
-
- struct peer_sdioc_channel_config ch_config;
-
- /* Channel Info */
- int num;
-
- void (*notify)(void *priv, unsigned channel_event);
- void *priv;
-
- int state;
-
- struct sdio_func *func;
-
- int rx_pipe_index;
- int tx_pipe_index;
-
- struct mutex ch_lock;
-
- u32 read_avail;
- u32 write_avail;
-
- u32 peer_tx_buf_size;
-
- u16 rx_pending_bytes;
-
- struct list_head rx_size_list_head;
-
- struct platform_device *pdev;
-
- u32 total_rx_bytes;
- u32 total_tx_bytes;
-
- u32 signature;
-
- struct sdio_al_device *sdio_al_dev;
-
- struct sdio_channel_statistics statistics;
-};
-
-/**
- * sdio_downloader_setup
- * initializes the TTY driver
- *
- * @card: a pointer to mmc_card.
- * @num_of_devices: number of devices.
- * @channel_number: channel number.
- * @return 0 on success or negative value on error.
- *
- * The TTY stack needs to know in advance how many devices it should
- * plan to manage. Use this call to set up the ports that will
- * be exported through SDIO.
- */
-int sdio_downloader_setup(struct mmc_card *card,
- unsigned int num_of_devices,
- int func_number,
- int(*func)(void));
-
-/**
- * test_channel_init
- * initializes a test channel
- *
- * @name: the channel name.
- * @return 0 on success or negative value on error.
- *
- */
-int test_channel_init(char *name);
-
-/**
- * sdio_al_register_lpm_cb
- * Allow the sdio_al test to register for lpm voting
- * notifications
- *
- * @device_handle: the device handle.
- * @wakeup_callback: callback function to be called when voting.
- *
- */
-void sdio_al_register_lpm_cb(void *device_handle,
- int(*lpm_callback)(void *, int));
-
-/**
- * sdio_al_unregister_lpm_cb
- * Allow the sdio_al test to unregister for lpm voting
- * notifications
- *
- * @device_handle: the device handle.
- *
- */
-void sdio_al_unregister_lpm_cb(void *device_handle);
-
-#endif /* __SDIO_AL_PRIVATE__ */
diff --git a/arch/arm/mach-msm/sdio_al_test.c b/arch/arm/mach-msm/sdio_al_test.c
deleted file mode 100644
index 2c9f675..0000000
--- a/arch/arm/mach-msm/sdio_al_test.c
+++ /dev/null
@@ -1,6500 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO-Abstraction-Layer Test Module.
- *
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/platform_device.h>
-#include <mach/sdio_smem.h>
-#include <linux/wakelock.h>
-#include <linux/uaccess.h>
-
-#include "sdio_al_private.h"
-#include <linux/debugfs.h>
-
-#include <linux/kthread.h>
-enum lpm_test_msg_type {
- LPM_NO_MSG, /* 0 */
- LPM_MSG_SEND, /* 1 */
- LPM_MSG_REC, /* 2 */
- LPM_SLEEP, /* 3 */
- LPM_WAKEUP, /* 4 */
- LPM_NOTIFY /* 5 */
-};
-
-#define LPM_NO_MSG_NAME "LPM No Event"
-#define LPM_MSG_SEND_NAME "LPM Send Msg Event"
-#define LPM_MSG_REC_NAME "LPM Receive Msg Event"
-#define LPM_SLEEP_NAME "LPM Sleep Event"
-#define LPM_WAKEUP_NAME "LPM Wakeup Event"
-
-/** Module name string */
-#define TEST_MODULE_NAME "sdio_al_test"
-
-#define TEST_SIGNATURE 0x12345678
-#define TEST_CONFIG_SIGNATURE 0xBEEFCAFE
-
-#define MAX_XFER_SIZE (16*1024)
-#define SMEM_MAX_XFER_SIZE 0xBC000
-#define A2_MIN_PACKET_SIZE 5
-#define RMNT_PACKET_SIZE (4*1024)
-#define DUN_PACKET_SIZE (2*1024)
-#define CSVT_PACKET_SIZE 1700
-
-#define TEST_DBG(x...) if (test_ctx->runtime_debug) pr_info(x)
-
-#define LPM_TEST_NUM_OF_PACKETS 100
-#define LPM_MAX_OPEN_CHAN_PER_DEV 4
-#define LPM_ARRAY_SIZE (7*LPM_TEST_NUM_OF_PACKETS*LPM_MAX_OPEN_CHAN_PER_DEV)
-#define SDIO_LPM_TEST "sdio_lpm_test_reading_task"
-#define LPM_TEST_CONFIG_SIGNATURE 0xDEADBABE
-#define LPM_MSG_NAME_SIZE 20
-#define MAX_STR_SIZE 10
-#define MAX_AVG_RTT_TIME_USEC 2500
-#define SDIO_RMNT_RTT_PACKET_SIZE 32
-#define SDIO_CSVT_RTT_PACKET_SIZE 1900
-
-#define A2_HEADER_OVERHEAD 8
-
-enum rx_process_state {
- RX_PROCESS_PACKET_INIT,
- RX_PROCESS_A2_HEADER,
- RX_PROCESS_PACKET_DATA,
-};
-
-enum sdio_test_case_type {
- SDIO_TEST_LOOPBACK_HOST,
- SDIO_TEST_LOOPBACK_CLIENT,
- SDIO_TEST_LPM_HOST_WAKER,
- SDIO_TEST_LPM_CLIENT_WAKER,
- SDIO_TEST_LPM_RANDOM,
- SDIO_TEST_HOST_SENDER_NO_LP,
- SDIO_TEST_CLOSE_CHANNEL,
- SDIO_TEST_A2_VALIDATION,
- /* The following tests are not part of the 9k tests and should be
- * kept last in case new tests are added
- */
- SDIO_TEST_PERF,
- SDIO_TEST_RTT,
- SDIO_TEST_MODEM_RESET,
-};
-
-struct lpm_task {
- struct task_struct *lpm_task;
- const char *task_name;
-};
-
-struct lpm_entry_type {
- enum lpm_test_msg_type msg_type;
- char msg_name[LPM_MSG_NAME_SIZE];
- u32 counter;
- u32 current_ms;
- u32 read_avail_mask;
- char chan_name[CHANNEL_NAME_SIZE];
-};
-
-struct lpm_msg {
- u32 signature;
- u32 counter;
- u32 reserve1;
- u32 reserve2;
-};
-
-struct test_config_msg {
- u32 signature;
- u32 test_case;
- u32 test_param;
- u32 num_packets;
- u32 num_iterations;
-};
-
-struct test_result_msg {
- u32 signature;
- u32 is_successful;
-};
-
-struct test_work {
- struct work_struct work;
- struct test_channel *test_ch;
-};
-
-enum sdio_channels_ids {
- SDIO_RPC,
- SDIO_QMI,
- SDIO_RMNT,
- SDIO_DIAG,
- SDIO_DUN,
- SDIO_SMEM,
- SDIO_CSVT,
- SDIO_MAX_CHANNELS
-};
-
-enum sdio_test_results {
- TEST_NO_RESULT,
- TEST_FAILED,
- TEST_PASSED
-};
-
-enum sdio_lpm_vote_state {
- SDIO_NO_VOTE,
- SDIO_VOTE_FOR_SLEEP,
- SDIO_VOTE_AGAINST_SLEEP
-};
-
-struct sdio_test_device {
- int open_channels_counter_to_recv;
- int open_channels_counter_to_send;
- struct lpm_entry_type *lpm_arr;
- int array_size;
- void *sdio_al_device;
- spinlock_t lpm_array_lock;
- unsigned long lpm_array_lock_flags;
- u32 next_avail_entry_in_array;
- struct lpm_task lpm_test_task;
- u32 next_mask_id;
- u32 read_avail_mask;
- int modem_result_per_dev;
- int final_result_per_dev;
-};
-
-struct test_channel {
- struct sdio_channel *ch;
-
- char name[CHANNEL_NAME_SIZE];
- int ch_id;
-
- struct sdio_test_device *test_device;
-
- u32 *buf;
- u32 buf_size;
-
- struct workqueue_struct *workqueue;
- struct test_work test_work;
-
- u32 rx_bytes;
- u32 tx_bytes;
-
- wait_queue_head_t wait_q;
- atomic_t rx_notify_count;
- atomic_t tx_notify_count;
- atomic_t any_notify_count;
- atomic_t wakeup_client;
- atomic_t card_detected_event;
-
- int wait_counter;
-
- int is_used;
- int test_type;
- int ch_ready;
-
- struct test_config_msg config_msg;
-
- int test_completed;
- int test_result;
- struct timer_list timer;
- int timer_interval_ms;
-
- struct timer_list timeout_timer;
- int timeout_ms;
- void *sdio_al_device;
- int is_ok_to_sleep;
- unsigned int packet_length;
- int random_packet_size;
- int next_index_in_sent_msg_per_chan;
- int channel_mask_id;
- int modem_result_per_chan;
- int notify_counter_per_chan;
- int max_burst_size; /* number of writes before close/open */
- int card_removed;
-};
-
-struct sdio_al_test_debug {
- u32 dun_throughput;
- u32 rmnt_throughput;
- struct dentry *debug_root;
- struct dentry *debug_test_result;
- struct dentry *debug_dun_throughput;
- struct dentry *debug_rmnt_throughput;
- struct dentry *rpc_sender_test;
- struct dentry *rpc_qmi_diag_sender_test;
- struct dentry *smem_test;
- struct dentry *smem_rpc_test;
- struct dentry *rmnet_a2_validation_test;
- struct dentry *dun_a2_validation_test;
- struct dentry *rmnet_a2_perf_test;
- struct dentry *dun_a2_perf_test;
- struct dentry *csvt_a2_perf_test;
- struct dentry *rmnet_dun_a2_perf_test;
- struct dentry *rpc_sender_rmnet_a2_perf_test;
- struct dentry *all_channels_test;
- struct dentry *host_sender_no_lp_diag_test;
- struct dentry *host_sender_no_lp_diag_rpc_test;
- struct dentry *rmnet_small_packets_test;
- struct dentry *rmnet_rtt_test;
- struct dentry *csvt_rtt_test;
- struct dentry *modem_reset_rpc_test;
- struct dentry *modem_reset_rmnet_test;
- struct dentry *modem_reset_channels_4bit_dev_test;
- struct dentry *modem_reset_channels_8bit_dev_test;
- struct dentry *modem_reset_all_channels_test;
- struct dentry *open_close_test;
- struct dentry *open_close_dun_rmnet_test;
- struct dentry *close_chan_lpm_test;
- struct dentry *lpm_test_client_wakes_host_test;
- struct dentry *lpm_test_host_wakes_client_test;
- struct dentry *lpm_test_random_single_channel_test;
- struct dentry *lpm_test_random_multi_channel_test;
-};
-
-struct test_context {
- dev_t dev_num;
- struct device *dev;
- struct cdev *cdev;
- int number_of_active_devices;
- int max_number_of_devices;
-
- struct sdio_test_device test_dev_arr[MAX_NUM_OF_SDIO_DEVICES];
-
- struct test_channel *test_ch;
-
- struct test_channel *test_ch_arr[SDIO_MAX_CHANNELS];
-
- long testcase;
-
- const char *name;
-
- int exit_flag;
-
- u32 signature;
-
- int runtime_debug;
-
- struct platform_device *smem_pdev;
- struct sdio_smem_client *sdio_smem;
- int smem_was_init;
- u8 *smem_buf;
- uint32_t smem_counter;
-
- struct platform_device *csvt_app_pdev;
-
- wait_queue_head_t wait_q;
- int test_completed;
- int test_result;
- struct sdio_al_test_debug debug;
-
- struct wake_lock wake_lock;
-
- unsigned int lpm_pseudo_random_seed;
-};
-
-/* FORWARD DECLARATIONS */
-static int set_params_loopback_9k(struct test_channel *tch);
-static int set_params_smem_test(struct test_channel *tch);
-static int set_params_a2_validation(struct test_channel *tch);
-static int set_params_a2_perf(struct test_channel *tch);
-static int set_params_8k_sender_no_lp(struct test_channel *tch);
-static int set_params_a2_small_pkts(struct test_channel *tch);
-static int set_params_rtt(struct test_channel *tch);
-static int set_params_loopback_9k_close(struct test_channel *tch);
-static int close_channel_lpm_test(int channel_num);
-static int set_params_lpm_test(struct test_channel *tch,
- enum sdio_test_case_type test,
- int timer_interval_ms);
-static void set_pseudo_random_seed(void);
-static int set_params_modem_reset(struct test_channel *tch);
-static int test_start(void);
-static void rx_cleanup(struct test_channel *test_ch, int *rx_packet_count);
-static void sdio_al_test_cleanup_channels(void);
-static void notify(void *priv, unsigned channel_event);
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int sdio_smem_open(struct sdio_smem_client *sdio_smem);
-#endif
-
-/*
- * Seed for pseudo random time sleeping in Random LPM test.
- * If not set, current time in jiffies is used.
- */
-static unsigned int seed;
-module_param(seed, int, 0);
-static struct test_context *test_ctx;
-
-static void sdio_al_test_initial_dev_and_chan(struct test_context *test_ctx)
-{
- int i = 0;
-
- if (!test_ctx) {
- pr_err(TEST_MODULE_NAME ":%s - test_ctx is NULL.\n", __func__);
- return;
- }
-
- for (i = 0 ; i < MAX_NUM_OF_SDIO_DEVICES ; ++i)
- test_ctx->test_dev_arr[i].sdio_al_device = NULL;
-
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
- if (!tch)
- continue;
- tch->is_used = 0;
- }
-
- sdio_al_test_cleanup_channels();
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-static int message_repeat;
-
-static int sdio_al_test_extract_number(const char __user *buf,
- size_t count)
-{
- int ret = 0;
- int number = -1;
- char local_buf[MAX_STR_SIZE] = {0};
- char *start = NULL;
-
- if (count > MAX_STR_SIZE) {
- pr_err(TEST_MODULE_NAME ": %s - MAX_STR_SIZE(%d) < count(%d). "
- "Please choose smaller number\n",
- __func__, MAX_STR_SIZE, (int)count);
- return -EINVAL;
- }
-
- if (copy_from_user(local_buf, buf, count)) {
- pr_err(TEST_MODULE_NAME ": %s - copy_from_user() failed\n",
- __func__);
- return -EINVAL;
- }
-
- /* adding null termination to the string */
- local_buf[count] = '\0';
-
- /* stripping leading and trailing white spaces */
- start = strstrip(local_buf);
-
- ret = kstrtoint(start, 10, &number);
-
- if (ret) {
- pr_err(TEST_MODULE_NAME " : %s - kstrtoint() failed\n",
- __func__);
- return ret;
- }
-
- return number;
-}
-
-static int sdio_al_test_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- message_repeat = 1;
- return 0;
-}
-
-static void sdio_al_test_cleanup_channels(void)
-{
- int channel_num;
- int dummy = 0;
-
- for (channel_num = 0 ; channel_num < SDIO_MAX_CHANNELS ;
- ++channel_num) {
- if (channel_num == SDIO_SMEM)
- continue;
-
- rx_cleanup(test_ctx->test_ch_arr[channel_num], &dummy);
- }
-
- return;
-}
-
-/* RPC SENDER TEST */
-static ssize_t rpc_sender_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RPC SENDER TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rpc_sender_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRPC_SENDER_TEST\n"
- "===============\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rpc_sender_test_ops = {
- .open = sdio_al_test_open,
- .write = rpc_sender_test_write,
- .read = rpc_sender_test_read,
-};
-
-/* RPC, QMI & DIAG SENDER TEST */
-static ssize_t rpc_qmi_diag_sender_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RPC, QMI AND DIAG SENDER TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_QMI]);
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_DIAG]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rpc_qmi_diag_sender_test_read(struct file *file,
- char __user
- *buffer, size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRPC_QMI_DIAG_SENDER_TEST\n"
- "========================\n"
- "Description:\n"
- "TBD\n");
-
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rpc_qmi_diag_sender_test_ops = {
- .open = sdio_al_test_open,
- .write = rpc_qmi_diag_sender_test_write,
- .read = rpc_qmi_diag_sender_test_read,
-};
-
-/* SMEM TEST */
-static ssize_t smem_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- SMEM TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t smem_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nSMEM_TEST\n"
- "=========\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations smem_test_ops = {
- .open = sdio_al_test_open,
- .write = smem_test_write,
- .read = smem_test_read,
-};
-
-/* SMEM & RPC TEST */
-static ssize_t smem_rpc_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- SMEM AND RPC TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t smem_rpc_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nSMEM_RPC_TEST\n"
- "=============\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations smem_rpc_test_ops = {
- .open = sdio_al_test_open,
- .write = smem_rpc_test_write,
- .read = smem_rpc_test_read,
-};
-
-/* RMNET A2 VALIDATION TEST */
-static ssize_t rmnet_a2_validation_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RMNET A2 VALIDATION TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_validation(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rmnet_a2_validation_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRMNET_A2_VALIDATION_TEST\n"
- "=========================\n"
- "Description:\n"
- "In this test, the HOST sends multiple packets to the\n"
- "CLIENT and validates the packets loop backed from A2\n"
- "for the RMNET channel.\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rmnet_a2_validation_test_ops = {
- .open = sdio_al_test_open,
- .write = rmnet_a2_validation_test_write,
- .read = rmnet_a2_validation_test_read,
-};
-
-/* DUN A2 VALIDATION TEST */
-static ssize_t dun_a2_validation_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- DUN A2 VALIDATION TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_validation(test_ctx->test_ch_arr[SDIO_DUN]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t dun_a2_validation_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nDUN_A2_VALIDATION_TEST\n"
- "=========================\n"
- "Description:\n"
- "In this test, the HOST sends multiple packets to the\n"
- "CLIENT and validates the packets loop backed from A2\n"
- "for the DUN channel.\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations dun_a2_validation_test_ops = {
- .open = sdio_al_test_open,
- .write = dun_a2_validation_test_write,
- .read = dun_a2_validation_test_read,
-};
-
-/* RMNET A2 PERFORMANCE TEST */
-static ssize_t rmnet_a2_perf_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RMNET A2 PERFORMANCE TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rmnet_a2_perf_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRMNET_A2_PERFORMANCE_TEST\n"
- "=========================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rmnet_a2_perf_test_ops = {
- .open = sdio_al_test_open,
- .write = rmnet_a2_perf_test_write,
- .read = rmnet_a2_perf_test_read,
-};
-
-/* DUN A2 PERFORMANCE TEST */
-static ssize_t dun_a2_perf_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- DUN A2 PERFORMANCE TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t dun_a2_perf_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nDUN_A2_PERFORMANCE_TEST\n"
- "=======================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations dun_a2_perf_test_ops = {
- .open = sdio_al_test_open,
- .write = dun_a2_perf_test_write,
- .read = dun_a2_perf_test_read,
-};
-
-/* CSVT A2 PERFORMANCE TEST */
-static ssize_t csvt_a2_perf_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- CSVT A2 PERFORMANCE TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t csvt_a2_perf_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nCSVT_A2_PERFORMANCE_TEST\n"
- "========================\n"
- "Description:\n"
- "Loopback test on the CSVT Channel, in order to check "
- "throughput performance.\n"
- "Packet size that are sent on the CSVT channel in this "
- "test is %d.bytes\n\n"
- "END OF DESCRIPTION\n", CSVT_PACKET_SIZE);
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations csvt_a2_perf_test_ops = {
- .open = sdio_al_test_open,
- .write = csvt_a2_perf_test_write,
- .read = csvt_a2_perf_test_read,
-};
-
-/* RMNET DUN A2 PERFORMANCE TEST */
-static ssize_t rmnet_dun_a2_perf_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RMNET AND DUN A2 PERFORMANCE TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rmnet_dun_a2_perf_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRMNET_DUN_A2_PERFORMANCE_TEST\n"
- "=============================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rmnet_dun_a2_perf_test_ops = {
- .open = sdio_al_test_open,
- .write = rmnet_dun_a2_perf_test_write,
- .read = rmnet_dun_a2_perf_test_read,
-};
-
-/* RPC SENDER & RMNET A2 PERFORMANCE TEST */
-static ssize_t rpc_sender_rmnet_a2_perf_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "--RPC SENDER AND RMNET A2 "
- "PERFORMANCE --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rpc_sender_rmnet_a2_perf_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRPC_SENDER_RMNET_A2_PERFORMANCE_TEST\n"
- "====================================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rpc_sender_rmnet_a2_perf_test_ops = {
- .open = sdio_al_test_open,
- .write = rpc_sender_rmnet_a2_perf_test_write,
- .read = rpc_sender_rmnet_a2_perf_test_read,
-};
-
-/* ALL CHANNELS TEST */
-static ssize_t all_channels_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- ALL THE CHANNELS TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_QMI]);
- set_params_loopback_9k(test_ctx->test_ch_arr[SDIO_DIAG]);
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_RMNT]);
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_DUN]);
- set_params_smem_test(test_ctx->test_ch_arr[SDIO_SMEM]);
- set_params_a2_perf(test_ctx->test_ch_arr[SDIO_CSVT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t all_channels_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nALL_CHANNELS_TEST\n"
- "=================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations all_channels_test_ops = {
- .open = sdio_al_test_open,
- .write = all_channels_test_write,
- .read = all_channels_test_read,
-};
-
-/* HOST SENDER NO LP DIAG TEST */
-static ssize_t host_sender_no_lp_diag_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t host_sender_no_lp_diag_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nHOST_SENDER_NO_LP_DIAG_TEST\n"
- "===========================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations host_sender_no_lp_diag_test_ops = {
- .open = sdio_al_test_open,
- .write = host_sender_no_lp_diag_test_write,
- .read = host_sender_no_lp_diag_test_read,
-};
-
-/* HOST SENDER NO LP DIAG, RPC TEST */
-static ssize_t host_sender_no_lp_diag_rpc_test_write(
- struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- HOST SENDER NO LP FOR DIAG, RPC "
- "TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_DIAG]);
- set_params_8k_sender_no_lp(test_ctx->test_ch_arr[SDIO_RPC]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t host_sender_no_lp_diag_rpc_test_read(
- struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nHOST_SENDER_NO_LP_DIAG_RPC_TEST\n"
- "===================================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations host_sender_no_lp_diag_rpc_test_ops = {
- .open = sdio_al_test_open,
- .write = host_sender_no_lp_diag_rpc_test_write,
- .read = host_sender_no_lp_diag_rpc_test_read,
-};
-
-/* RMNET SMALL PACKETS TEST */
-static ssize_t rmnet_small_packets_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RMNET SMALL PACKETS (5-128) TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_a2_small_pkts(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rmnet_small_packets_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRMNET_SMALL_PACKETS_TEST\n"
- "========================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rmnet_small_packets_test_ops = {
- .open = sdio_al_test_open,
- .write = rmnet_small_packets_test_write,
- .read = rmnet_small_packets_test_read,
-};
-
-/* RMNET RTT TEST */
-static ssize_t rmnet_rtt_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- RMNET RTT TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_rtt(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t rmnet_rtt_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nRMNET_RTT_TEST\n"
- "==============\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations rmnet_rtt_test_ops = {
- .open = sdio_al_test_open,
- .write = rmnet_rtt_test_write,
- .read = rmnet_rtt_test_read,
-};
-
-/* CSVT RTT TEST */
-static ssize_t csvt_rtt_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- CSVT RTT TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_rtt(test_ctx->test_ch_arr[SDIO_CSVT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t csvt_rtt_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nCSVT_RTT_TEST\n"
- "==============\n"
- "Description:\n"
- "In this test the HOST send a message of %d bytes "
- "to the CLIENT\n\n"
- "END OF DESCRIPTION\n", SDIO_CSVT_RTT_PACKET_SIZE);
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations csvt_rtt_test_ops = {
- .open = sdio_al_test_open,
- .write = csvt_rtt_test_write,
- .read = csvt_rtt_test_read,
-};
-
-/* MODEM RESET RPC TEST */
-static ssize_t modem_reset_rpc_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- MODEM RESET - RPC CHANNEL TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t modem_reset_rpc_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nMODEM_RESET_RPC_TEST\n"
- "====================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations modem_reset_rpc_test_ops = {
- .open = sdio_al_test_open,
- .write = modem_reset_rpc_test_write,
- .read = modem_reset_rpc_test_read,
-};
-
-/* MODEM RESET RMNET TEST */
-static ssize_t modem_reset_rmnet_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- MODEM RESET - RMNT CHANNEL TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t modem_reset_rmnet_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nMODEM_RESET_RMNET_TEST\n"
- "======================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations modem_reset_rmnet_test_ops = {
- .open = sdio_al_test_open,
- .write = modem_reset_rmnet_test_write,
- .read = modem_reset_rmnet_test_read,
-};
-
-/* MODEM RESET - CHANNELS IN 4BIT DEVICE TEST */
-static ssize_t modem_reset_channels_4bit_dev_test_write(
- struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS IN "
- "4BIT DEVICE TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_QMI]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t modem_reset_channels_4bit_dev_test_read(
- struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nMODEM_RESET_CHANNELS_4BIT_DEV_TEST\n"
- "==================================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations modem_reset_channels_4bit_dev_test_ops = {
- .open = sdio_al_test_open,
- .write = modem_reset_channels_4bit_dev_test_write,
- .read = modem_reset_channels_4bit_dev_test_read,
-};
-
-/* MODEM RESET - CHANNELS IN 8BIT DEVICE TEST */
-static ssize_t modem_reset_channels_8bit_dev_test_write(
- struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS IN "
- "8BIT DEVICE TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t modem_reset_channels_8bit_dev_test_read(
- struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nMODEM_RESET_CHANNELS_8BIT_DEV_TEST\n"
- "==================================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations modem_reset_channels_8bit_dev_test_ops = {
- .open = sdio_al_test_open,
- .write = modem_reset_channels_8bit_dev_test_write,
- .read = modem_reset_channels_8bit_dev_test_read,
-};
-
-/* MODEM RESET - ALL CHANNELS TEST */
-static ssize_t modem_reset_all_channels_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- MODEM RESET - ALL CHANNELS TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RPC]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_QMI]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DIAG]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_RMNT]);
- set_params_modem_reset(test_ctx->test_ch_arr[SDIO_DUN]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t modem_reset_all_channels_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nMODEM_RESET_ALL_CHANNELS_TEST\n"
- "=============================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations modem_reset_all_channels_test_ops = {
- .open = sdio_al_test_open,
- .write = modem_reset_all_channels_test_write,
- .read = modem_reset_all_channels_test_read,
-};
-
-/* HOST SENDER WITH OPEN/CLOSE TEST */
-static ssize_t open_close_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- struct test_channel **ch_arr = test_ctx->test_ch_arr;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- HOST SENDER WITH OPEN/CLOSE TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k_close(ch_arr[SDIO_DIAG]);
- set_params_loopback_9k_close(ch_arr[SDIO_RPC]);
- set_params_loopback_9k_close(ch_arr[SDIO_SMEM]);
- set_params_loopback_9k_close(ch_arr[SDIO_QMI]);
- set_params_loopback_9k_close(ch_arr[SDIO_RMNT]);
- set_params_loopback_9k_close(ch_arr[SDIO_DUN]);
- set_params_loopback_9k_close(ch_arr[SDIO_CSVT]);
-
- ret = test_start();
-
- if (ret)
- break;
-
- pr_info(TEST_MODULE_NAME " -- correctness test for"
- "DIAG ");
- set_params_loopback_9k(ch_arr[SDIO_DIAG]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t open_close_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nOPEN_CLOSE_TEST\n"
- "============================\n"
- "Description:\n"
- "In this test the host sends 5k packets to the modem in the "
- "following sequence: Send a random burst of packets on "
- "Diag and Rmnet channels, read 0 or a random number "
- "of packets, close and re-open the channel. At the end of the "
- "test, the channel is verified by running a loopback test\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations open_close_test_ops = {
- .open = sdio_al_test_open,
- .write = open_close_test_write,
- .read = open_close_test_read,
-};
-
-/* HOST SENDER WITH OPEN/CLOSE FOR DUN & RMNET TEST */
-static ssize_t open_close_dun_rmnet_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- struct test_channel **ch_arr = test_ctx->test_ch_arr;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- HOST SENDER WITH OPEN/CLOSE FOR "
- "DUN AND RMNET TEST --");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_loopback_9k_close(ch_arr[SDIO_DUN]);
- set_params_loopback_9k_close(ch_arr[SDIO_RMNT]);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t open_close_dun_rmnet_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nOPEN_CLOSE_DUN_RMNET_TEST\n"
- "============================\n"
- "Description:\n"
- "In this test the host sends 5k packets to the modem in the "
- "following sequence: Send a random burst of packets on "
- "DUN and Rmnet channels, read 0 or a random number "
- "of packets, close and re-open the channel.\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations open_close_dun_rmnet_test_ops = {
- .open = sdio_al_test_open,
- .write = open_close_dun_rmnet_test_write,
- .read = open_close_dun_rmnet_test_read,
-};
-
-/* CLOSE CHANNEL & LPM TEST HOST WAKES THE CLIENT TEST */
-static ssize_t close_chan_lpm_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int channel_num = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- CLOSE CHANNEL & LPM TEST "
- "HOST WAKES THE CLIENT TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- for (channel_num = 0 ; channel_num < SDIO_MAX_CHANNELS ;
- channel_num++) {
-
- ret = close_channel_lpm_test(channel_num);
-
- if (ret)
- break;
-
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
- SDIO_TEST_LPM_HOST_WAKER, 120);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- if (ret) {
- pr_err(TEST_MODULE_NAME " -- Close channel & LPM Test "
- "FAILED: %d --\n", ret);
- } else {
- pr_err(TEST_MODULE_NAME " -- Close channel & LPM Test "
- "PASSED\n");
- }
- }
-
- return count;
-}
-
-static ssize_t close_chan_lpm_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nCLOSE_CHAN_LPM_TEST\n"
- "===================\n"
- "Description:\n"
- "TBD\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations close_chan_lpm_test_ops = {
- .open = sdio_al_test_open,
- .write = close_chan_lpm_test_write,
- .read = close_chan_lpm_test_read,
-};
-
-/* LPM TEST FOR DEVICE 1. CLIENT WAKES THE HOST TEST */
-static ssize_t lpm_test_client_wakes_host_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- LPM TEST FOR DEVICE 1. CLIENT "
- "WAKES THE HOST TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
- SDIO_TEST_LPM_CLIENT_WAKER, 90);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t lpm_test_client_wakes_host_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nLPM_TEST_CLIENT_WAKES_HOST_TEST\n"
- "===============================\n"
- "Description:\n"
- "In this test, the HOST is going into LPM mode,\n"
- "and the CLIENT is responsible to send it a message\n"
- "in order to wake it up\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations lpm_test_client_wakes_host_test_ops = {
- .open = sdio_al_test_open,
- .write = lpm_test_client_wakes_host_test_write,
- .read = lpm_test_client_wakes_host_test_read,
-};
-
-/* LPM TEST FOR DEVICE 1. HOST WAKES THE CLIENT TEST */
-static ssize_t lpm_test_host_wakes_client_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- LPM TEST FOR DEVICE 1. HOST "
- "WAKES THE CLIENT TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
- SDIO_TEST_LPM_HOST_WAKER, 120);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t lpm_test_host_wakes_client_test_read(struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nLPM_TEST_HOST_WAKES_CLIENT_TEST\n"
- "===============================\n"
- "Description:\n"
- "In this test, the CLIENT goes into LPM mode, and the\n"
- "HOST is responsible to send it a message\n"
- "in order to wake it up\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations lpm_test_host_wakes_client_test_ops = {
- .open = sdio_al_test_open,
- .write = lpm_test_host_wakes_client_test_write,
- .read = lpm_test_host_wakes_client_test_read,
-};
-
-/* LPM TEST RANDOM, SINGLE CHANNEL TEST */
-static ssize_t lpm_test_random_single_channel_test_write(
- struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- LPM TEST RANDOM SINGLE "
- "CHANNEL TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_pseudo_random_seed();
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
- SDIO_TEST_LPM_RANDOM, 0);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t lpm_test_random_single_channel_test_read(
- struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nLPM_TEST_RANDOM_SINGLE_CHANNEL_TEST\n"
- "===================================\n"
- "Description:\n"
- "In this test, the HOST and CLIENT "
- "send messages to each other,\n"
- "random in time, over RPC channel only.\n"
- "All events are being recorded, and later on,\n"
- "they are being analysed by the HOST and by the CLIENT\n,"
- "in order to check if the LPM mechanism worked properly,\n"
- "meaning:"
- " When all the relevant conditions are met, a device should:\n"
- "1. Go to sleep\n"
- "2. Wake up\n"
- "3. Stay awake\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations lpm_test_random_single_channel_test_ops = {
- .open = sdio_al_test_open,
- .write = lpm_test_random_single_channel_test_write,
- .read = lpm_test_random_single_channel_test_read,
-};
-
-/* LPM TEST RANDOM, MULTI CHANNEL TEST */
-static ssize_t lpm_test_random_multi_channel_test_write(
- struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- pr_info(TEST_MODULE_NAME "-- LPM TEST RANDOM MULTI CHANNEL TEST --\n");
-
- number = sdio_al_test_extract_number(buf, count);
-
- if (number < 0) {
- pr_err(TEST_MODULE_NAME " : %s - sdio_al_test_extract_number() "
- "failed. number = %d\n", __func__, number);
- return count;
- }
-
- for (i = 0 ; i < number ; ++i) {
- pr_info(TEST_MODULE_NAME " - Cycle # %d / %d\n", i+1, number);
- pr_info(TEST_MODULE_NAME " ===================");
-
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- set_pseudo_random_seed();
-
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_RPC],
- SDIO_TEST_LPM_RANDOM, 0);
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_DIAG],
- SDIO_TEST_LPM_RANDOM, 0);
- set_params_lpm_test(test_ctx->test_ch_arr[SDIO_QMI],
- SDIO_TEST_LPM_RANDOM, 0);
-
- ret = test_start();
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-static ssize_t lpm_test_random_multi_channel_test_read(
- struct file *file,
- char __user *buffer,
- size_t count,
- loff_t *offset)
-{
- memset((void *)buffer, 0, count);
-
- snprintf(buffer, count,
- "\nLPM_TEST_RANDOM_MULTI_CHANNEL_TEST\n"
- "==================================\n"
- "Description:\n"
- "In this test, the HOST and CLIENT "
- "send messages to each other,\n"
- "random in time, over RPC, QMI AND DIAG channels\n"
- "(i.e, on both SDIO devices).\n"
- "All events are being recorded, and later on,\n"
- "they are being analysed by the HOST and by the CLIENT,\n"
- "in order to check if the LPM mechanism worked properly,\n"
- "meaning:"
- " When all the relevant conditions are met, a device should:\n"
- "1. Go to sleep\n"
- "2. Wake up\n"
- "3. Stay awake\n\n"
- "END OF DESCRIPTION\n");
-
- if (message_repeat == 1) {
- message_repeat = 0;
- return strnlen(buffer, count);
- } else {
- return 0;
- }
-}
-
-const struct file_operations lpm_test_random_multi_channel_test_ops = {
- .open = sdio_al_test_open,
- .write = lpm_test_random_multi_channel_test_write,
- .read = lpm_test_random_multi_channel_test_read,
-};
-
-static int sdio_al_test_debugfs_init(void)
-{
- test_ctx->debug.debug_root = debugfs_create_dir("sdio_al_test",
- NULL);
- if (!test_ctx->debug.debug_root)
- return -ENOENT;
-
- test_ctx->debug.debug_test_result = debugfs_create_u32(
- "test_result",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- &test_ctx->test_result);
-
- test_ctx->debug.debug_dun_throughput = debugfs_create_u32(
- "dun_throughput",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- &test_ctx->debug.dun_throughput);
-
- test_ctx->debug.debug_rmnt_throughput = debugfs_create_u32(
- "rmnt_throughput",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- &test_ctx->debug.rmnt_throughput);
-
- test_ctx->debug.rpc_sender_test =
- debugfs_create_file("10_rpc_sender_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rpc_sender_test_ops);
-
- test_ctx->debug.rpc_qmi_diag_sender_test =
- debugfs_create_file("20_rpc_qmi_diag_sender_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rpc_qmi_diag_sender_test_ops);
-
- test_ctx->debug.rmnet_a2_validation_test =
- debugfs_create_file("30_rmnet_a2_validation_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rmnet_a2_validation_test_ops);
-
- test_ctx->debug.dun_a2_validation_test =
- debugfs_create_file("40_dun_a2_validation_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &dun_a2_validation_test_ops);
-
- test_ctx->debug.rmnet_a2_perf_test =
- debugfs_create_file("50_rmnet_a2_perf_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rmnet_a2_perf_test_ops);
-
- test_ctx->debug.dun_a2_perf_test =
- debugfs_create_file("60_dun_a2_perf_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &dun_a2_perf_test_ops);
-
- test_ctx->debug.csvt_a2_perf_test =
- debugfs_create_file("71_csvt_a2_perf_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &csvt_a2_perf_test_ops);
-
- test_ctx->debug.rmnet_dun_a2_perf_test =
- debugfs_create_file("70_rmnet_dun_a2_perf_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rmnet_dun_a2_perf_test_ops);
-
- test_ctx->debug.rpc_sender_rmnet_a2_perf_test =
- debugfs_create_file("80_rpc_sender_rmnet_a2_perf_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rpc_sender_rmnet_a2_perf_test_ops);
-
- test_ctx->debug.smem_test =
- debugfs_create_file("90_smem_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &smem_test_ops);
-
- test_ctx->debug.smem_rpc_test =
- debugfs_create_file("100_smem_rpc_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &smem_rpc_test_ops);
-
- test_ctx->debug.all_channels_test =
- debugfs_create_file("150_all_channels_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &all_channels_test_ops);
-
- test_ctx->debug.host_sender_no_lp_diag_test =
- debugfs_create_file("160_host_sender_no_lp_diag_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &host_sender_no_lp_diag_test_ops);
-
- test_ctx->debug.host_sender_no_lp_diag_rpc_test =
- debugfs_create_file("170_host_sender_no_lp_diag_rpc_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &host_sender_no_lp_diag_rpc_test_ops);
-
- test_ctx->debug.rmnet_small_packets_test =
- debugfs_create_file("180_rmnet_small_packets_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rmnet_small_packets_test_ops);
-
- test_ctx->debug.rmnet_rtt_test =
- debugfs_create_file("190_rmnet_rtt_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &rmnet_rtt_test_ops);
-
- test_ctx->debug.csvt_rtt_test =
- debugfs_create_file("191_csvt_rtt_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &csvt_rtt_test_ops);
-
- test_ctx->debug.modem_reset_rpc_test =
- debugfs_create_file("220_modem_reset_rpc_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &modem_reset_rpc_test_ops);
-
- test_ctx->debug.modem_reset_rmnet_test =
- debugfs_create_file("230_modem_reset_rmnet_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &modem_reset_rmnet_test_ops);
-
- test_ctx->debug.modem_reset_channels_4bit_dev_test =
- debugfs_create_file("240_modem_reset_channels_4bit_dev_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &modem_reset_channels_4bit_dev_test_ops);
-
- test_ctx->debug.modem_reset_channels_8bit_dev_test =
- debugfs_create_file("250_modem_reset_channels_8bit_dev_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &modem_reset_channels_8bit_dev_test_ops);
-
- test_ctx->debug.modem_reset_all_channels_test =
- debugfs_create_file("260_modem_reset_all_channels_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &modem_reset_all_channels_test_ops);
-
- test_ctx->debug.open_close_test =
- debugfs_create_file("270_open_close_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &open_close_test_ops);
-
- test_ctx->debug.open_close_dun_rmnet_test =
- debugfs_create_file("271_open_close_dun_rmnet_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &open_close_dun_rmnet_test_ops);
-
- test_ctx->debug.close_chan_lpm_test =
- debugfs_create_file("280_close_chan_lpm_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &close_chan_lpm_test_ops);
-
- test_ctx->debug.lpm_test_client_wakes_host_test =
- debugfs_create_file("600_lpm_test_client_wakes_host_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &lpm_test_client_wakes_host_test_ops);
-
- test_ctx->debug.lpm_test_host_wakes_client_test =
- debugfs_create_file("610_lpm_test_host_wakes_client_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &lpm_test_host_wakes_client_test_ops);
-
- test_ctx->debug.lpm_test_random_single_channel_test =
- debugfs_create_file("620_lpm_test_random_single_channel_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &lpm_test_random_single_channel_test_ops);
-
- test_ctx->debug.lpm_test_random_multi_channel_test =
- debugfs_create_file("630_lpm_test_random_multi_channel_test",
- S_IRUGO | S_IWUGO,
- test_ctx->debug.debug_root,
- NULL,
- &lpm_test_random_multi_channel_test_ops);
-
- if ((!test_ctx->debug.debug_dun_throughput) &&
- (!test_ctx->debug.debug_rmnt_throughput)) {
- debugfs_remove_recursive(test_ctx->debug.debug_root);
- test_ctx->debug.debug_root = NULL;
- return -ENOENT;
- }
- return 0;
-}
-
-static void sdio_al_test_debugfs_cleanup(void)
-{
- debugfs_remove(test_ctx->debug.debug_dun_throughput);
- debugfs_remove(test_ctx->debug.debug_rmnt_throughput);
- debugfs_remove(test_ctx->debug.debug_root);
-}
-#endif
-
-static int channel_name_to_id(char *name)
-{
- pr_info(TEST_MODULE_NAME "%s: channel name %s\n",
- __func__, name);
-
- if (!strncmp(name, "SDIO_RPC_TEST",
- strnlen("SDIO_RPC_TEST", CHANNEL_NAME_SIZE)))
- return SDIO_RPC;
- else if (!strncmp(name, "SDIO_QMI_TEST",
- strnlen("SDIO_QMI_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_QMI;
- else if (!strncmp(name, "SDIO_RMNT_TEST",
- strnlen("SDIO_RMNT_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_RMNT;
- else if (!strncmp(name, "SDIO_DIAG_TEST",
- strnlen("SDIO_DIAG", TEST_CH_NAME_SIZE)))
- return SDIO_DIAG;
- else if (!strncmp(name, "SDIO_DUN_TEST",
- strnlen("SDIO_DUN_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_DUN;
- else if (!strncmp(name, "SDIO_SMEM_TEST",
- strnlen("SDIO_SMEM_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_SMEM;
- else if (!strncmp(name, "SDIO_CSVT_TEST",
- strnlen("SDIO_CSVT_TEST", TEST_CH_NAME_SIZE)))
- return SDIO_CSVT;
- else
- return SDIO_MAX_CHANNELS;
-
- return SDIO_MAX_CHANNELS;
-}
-
-/**
- * Allocate and add SDIO_SMEM platform device
- */
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int add_sdio_smem(void)
-{
- int ret = 0;
-
- test_ctx->smem_pdev = platform_device_alloc("SDIO_SMEM", -1);
- ret = platform_device_add(test_ctx->smem_pdev);
- if (ret) {
- pr_err(TEST_MODULE_NAME ": platform_device_add failed, "
- "ret=%d\n", ret);
- return ret;
- }
- return 0;
-}
-#endif
-
-static int open_sdio_ch(struct test_channel *tch)
-{
- int ret = 0;
-
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
- return -EINVAL;
- }
-
- if (!tch->ch_ready) {
- TEST_DBG(TEST_MODULE_NAME ":openning channel %s\n",
- tch->name);
- if (tch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
- if (!test_ctx->smem_pdev)
- ret = add_sdio_smem();
- else
- ret = sdio_smem_open(test_ctx->sdio_smem);
- if (ret) {
- pr_err(TEST_MODULE_NAME
- ":openning channel %s failed\n",
- tch->name);
- tch->ch_ready = false;
- return -EINVAL;
- }
-#endif
- } else {
- tch->ch_ready = true;
- ret = sdio_open(tch->name , &tch->ch, tch,
- notify);
- if (ret) {
- pr_err(TEST_MODULE_NAME
- ":openning channel %s failed\n",
- tch->name);
- tch->ch_ready = false;
- return -EINVAL;
- }
- }
- }
- return ret;
-}
-
-static int close_sdio_ch(struct test_channel *tch)
-{
- int ret = 0;
-
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
- return -EINVAL;
- }
-
- if (tch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
- TEST_DBG(TEST_MODULE_NAME":%s closing channel %s",
- __func__, tch->name);
- ret = sdio_smem_unregister_client();
- test_ctx->smem_counter = 0;
-#endif
- } else {
- ret = sdio_close(tch->ch);
- }
-
- if (ret) {
- pr_err(TEST_MODULE_NAME":%s close channel %s"
- " failed\n", __func__, tch->name);
- } else {
- TEST_DBG(TEST_MODULE_NAME":%s close channel %s"
- " success\n", __func__, tch->name);
- tch->ch_ready = false;
- }
- return ret;
-}
-
-/**
- * Config message
- */
-
-static void send_config_msg(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 write_avail = 0;
- int size = sizeof(test_ch->config_msg);
-
- pr_debug(TEST_MODULE_NAME "%s\n", __func__);
-
- memcpy(test_ch->buf, (void *)&test_ch->config_msg, size);
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- pr_info(TEST_MODULE_NAME ":Sending the config message.\n");
-
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- pr_debug(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- pr_debug(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
- return;
- }
-
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret)
- pr_err(TEST_MODULE_NAME ":%s sdio_write err=%d.\n",
- __func__, -ret);
- else
- pr_info(TEST_MODULE_NAME ":%s sent config_msg successfully.\n",
- __func__);
-}
-
-/**
- * Loopback Test
- */
-static void loopback_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
-
- while (1) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- TEST_DBG(TEST_MODULE_NAME "--LOOPBACK WAIT FOR EVENT--.\n");
- /* wait for data ready event */
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
-
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail == 0)
- continue;
-
-
- write_avail = sdio_write_avail(test_ch->ch);
- if (write_avail < read_avail) {
- pr_info(TEST_MODULE_NAME
- ":not enough write avail.\n");
- continue;
- }
-
- ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
- if (ret) {
- pr_info(TEST_MODULE_NAME
- ":worker, sdio_read err=%d.\n", -ret);
- continue;
- }
- test_ch->rx_bytes += read_avail;
-
- TEST_DBG(TEST_MODULE_NAME ":worker total rx bytes = 0x%x.\n",
- test_ch->rx_bytes);
-
-
- ret = sdio_write(test_ch->ch,
- test_ch->buf, read_avail);
- if (ret) {
- pr_info(TEST_MODULE_NAME
- ":loopback sdio_write err=%d.\n",
- -ret);
- continue;
- }
- test_ch->tx_bytes += read_avail;
-
- TEST_DBG(TEST_MODULE_NAME
- ":loopback total tx bytes = 0x%x.\n",
- test_ch->tx_bytes);
- } /* end of while */
-}
-
-/**
- * Check if all tests completed
- */
-static void check_test_completion(void)
-{
- int i;
-
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
- continue;
- if (!tch->test_completed) {
- pr_info(TEST_MODULE_NAME ": %s - Channel %s test is "
- "not completed", __func__, tch->name);
- return;
- }
- }
- pr_info(TEST_MODULE_NAME ": %s - Test is completed", __func__);
- test_ctx->test_completed = 1;
- wake_up(&test_ctx->wait_q);
-}
-
-static int pseudo_random_seed(unsigned int *seed_number)
-{
- if (!seed_number)
- return 0;
-
- *seed_number = (unsigned int)(((unsigned long)*seed_number *
- (unsigned long)1103515367) + 35757);
- return (int)((*seed_number / (64*1024)) % 500);
-}
-
-/* this function must be locked before accessing it */
-static void lpm_test_update_entry(struct test_channel *tch,
- enum lpm_test_msg_type msg_type,
- char *msg_name,
- int counter)
-{
- u32 index = 0;
- static int print_full = 1;
- struct sdio_test_device *test_device;
-
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
- return;
- }
-
- test_device = tch->test_device;
-
- if (!test_device) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
- return;
- }
-
- if (!test_device->lpm_arr) {
- pr_err(TEST_MODULE_NAME ": %s - NULL lpm_arr\n", __func__);
- return;
- }
-
- if (test_device->next_avail_entry_in_array >=
- test_device->array_size) {
- pr_err(TEST_MODULE_NAME ": %s - lpm array is full",
- __func__);
-
- if (print_full) {
- print_hex_dump(KERN_INFO, TEST_MODULE_NAME ": lpm_arr:",
- 0, 32, 2,
- (void *)test_device->lpm_arr,
- sizeof(test_device->lpm_arr), false);
- print_full = 0;
- }
- return;
- }
-
- index = test_device->next_avail_entry_in_array;
- if ((msg_type == LPM_MSG_SEND) || (msg_type == LPM_MSG_REC))
- test_device->lpm_arr[index].counter = counter;
- else
- test_device->lpm_arr[index].counter = 0;
-
- test_device->lpm_arr[index].msg_type = msg_type;
- memcpy(test_device->lpm_arr[index].msg_name, msg_name,
- LPM_MSG_NAME_SIZE);
- test_device->lpm_arr[index].current_ms =
- jiffies_to_msecs(get_jiffies_64());
-
- test_device->lpm_arr[index].read_avail_mask =
- test_device->read_avail_mask;
-
- if ((msg_type == LPM_SLEEP) || (msg_type == LPM_WAKEUP))
- memcpy(test_device->lpm_arr[index].chan_name, "DEVICE ",
- CHANNEL_NAME_SIZE);
- else
- memcpy(test_device->lpm_arr[index].chan_name, tch->name,
- CHANNEL_NAME_SIZE);
-
- test_device->next_avail_entry_in_array++;
-}
-
-static int wait_for_result_msg(struct test_channel *test_ch)
-{
- u32 read_avail = 0;
- int ret = 0;
-
- pr_info(TEST_MODULE_NAME ": %s - START, channel %s\n",
- __func__, test_ch->name);
-
- while (1) {
- read_avail = sdio_read_avail(test_ch->ch);
-
- if (read_avail == 0) {
- pr_info(TEST_MODULE_NAME
- ": read_avail is 0 for chan %s\n",
- test_ch->name);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
- continue;
- }
-
- memset(test_ch->buf, 0x00, test_ch->buf_size);
-
- ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
- if (ret) {
- pr_info(TEST_MODULE_NAME ": sdio_read for chan"
- "%s failed, err=%d.\n",
- test_ch->name, -ret);
- goto exit_err;
- }
-
- if (test_ch->buf[0] != TEST_CONFIG_SIGNATURE) {
- pr_info(TEST_MODULE_NAME ": Not a test_result "
- "signature. expected 0x%x. received 0x%x "
- "for chan %s\n",
- TEST_CONFIG_SIGNATURE,
- test_ch->buf[0],
- test_ch->name);
- continue;
- } else {
- pr_info(TEST_MODULE_NAME ": Signature is "
- "TEST_CONFIG_SIGNATURE as expected for"
- "channel %s\n", test_ch->name);
- break;
- }
- }
-
- return test_ch->buf[1];
-
-exit_err:
- return 0;
-}
-
-static void print_random_lpm_test_array(struct sdio_test_device *test_dev)
-{
- int i;
-
- if (!test_dev) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
- return;
- }
-
- for (i = 0 ; i < test_dev->next_avail_entry_in_array ; ++i) {
- if (i == 0)
- pr_err(TEST_MODULE_NAME ": index %4d, chan=%2s, "
- "code=%1d=%4s, msg#%1d, ms from before=-1, "
- "read_mask=0x%d, ms=%2u",
- i,
- test_dev->lpm_arr[i].chan_name,
- test_dev->lpm_arr[i].msg_type,
- test_dev->lpm_arr[i].msg_name,
- test_dev->lpm_arr[i].counter,
- test_dev->lpm_arr[i].read_avail_mask,
- test_dev->lpm_arr[i].current_ms);
- else
- pr_err(TEST_MODULE_NAME ": index "
- "%4d, %2s, code=%1d=%4s, msg#%1d, ms from "
- "before=%2u, read_mask=0x%d, ms=%2u",
- i,
- test_dev->lpm_arr[i].chan_name,
- test_dev->lpm_arr[i].msg_type,
- test_dev->lpm_arr[i].msg_name,
- test_dev->lpm_arr[i].counter,
- test_dev->lpm_arr[i].current_ms -
- test_dev->lpm_arr[i-1].current_ms,
- test_dev->lpm_arr[i].read_avail_mask,
- test_dev->lpm_arr[i].current_ms);
-
- udelay(1000);
- }
-}
-
-static int check_random_lpm_test_array(struct sdio_test_device *test_dev)
-{
- int i = 0, j = 0;
- unsigned int delta_ms = 0;
- int arr_ind = 0;
- int ret = 0;
- int notify_counter = 0;
- int sleep_counter = 0;
- int wakeup_counter = 0;
- int lpm_activity_counter = 0;
-
- if (!test_dev) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
- return -ENODEV;
- }
-
- for (i = 0; i < test_dev->next_avail_entry_in_array; i++) {
- notify_counter = 0;
- sleep_counter = 0;
- wakeup_counter = 0;
-
- if ((test_dev->lpm_arr[i].msg_type == LPM_MSG_SEND) ||
- (test_dev->lpm_arr[i].msg_type == LPM_MSG_REC)) {
- /* find the next message in the array */
- arr_ind = test_dev->next_avail_entry_in_array;
- for (j = i+1; j < arr_ind; j++) {
- if ((test_dev->lpm_arr[j].msg_type ==
- LPM_MSG_SEND) ||
- (test_dev->lpm_arr[j].msg_type ==
- LPM_MSG_REC) ||
- (test_dev->lpm_arr[j].msg_type ==
- LPM_NOTIFY))
- break;
- if (test_dev->lpm_arr[j].msg_type ==
- LPM_SLEEP)
- sleep_counter++;
- if (test_dev->lpm_arr[j].msg_type ==
- LPM_WAKEUP)
- wakeup_counter++;
- }
- if (j == arr_ind) {
- ret = 0;
- break;
- }
-
- delta_ms = test_dev->lpm_arr[j].current_ms -
- test_dev->lpm_arr[i].current_ms;
- if (delta_ms < 30) {
- if ((sleep_counter == 0)
- && (wakeup_counter == 0)) {
- continue;
- } else {
- pr_err(TEST_MODULE_NAME "%s: lpm "
- "activity while delta is less "
- "than 30, i=%d, j=%d, "
- "sleep_counter=%d, "
- "wakeup_counter=%d",
- __func__, i, j,
- sleep_counter, wakeup_counter);
- ret = -ENODEV;
- break;
- }
- } else {
- if ((delta_ms > 90) &&
- (test_dev->lpm_arr[i].
- read_avail_mask == 0)) {
- if (j != i+3) {
- pr_err(TEST_MODULE_NAME
- "%s: unexpected "
- "lpm activity "
- "while delta is "
- "bigger than "
- "90, i=%d, "
- "j=%d, "
- "notify_counter"
- "=%d",
- __func__, i, j,
- notify_counter);
- ret = -ENODEV;
- break;
- }
- lpm_activity_counter++;
- }
- }
- }
- }
-
- pr_info(TEST_MODULE_NAME ": %s - lpm_activity_counter=%d",
- __func__, lpm_activity_counter);
-
- return ret;
-}
-
-static int lpm_test_main_task(void *ptr)
-{
- u32 read_avail = 0;
- int last_msg_index = 0;
- struct test_channel *test_ch = (struct test_channel *)ptr;
- struct sdio_test_device *test_dev;
- struct lpm_msg lpm_msg;
- int ret = 0;
- int host_result = 0;
-
- if (!test_ch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
- return -ENODEV;
- }
-
- pr_err(TEST_MODULE_NAME ": %s - STARTED. channel %s\n",
- __func__, test_ch->name);
-
- test_dev = test_ch->test_device;
-
- if (!test_dev) {
- pr_err(TEST_MODULE_NAME ": %s - NULL Test Device\n", __func__);
- return -ENODEV;
- }
-
- while (last_msg_index < test_ch->config_msg.num_packets - 1) {
-
- TEST_DBG(TEST_MODULE_NAME ": %s - "
- "IN LOOP last_msg_index=%d\n",
- __func__, last_msg_index);
-
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail == 0) {
- TEST_DBG(TEST_MODULE_NAME
- ":read_avail 0 for chan %s, "
- "wait for event\n",
- test_ch->name);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
-
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail == 0) {
- pr_err(TEST_MODULE_NAME
- ":read_avail size %d for chan %s not as"
- " expected\n",
- read_avail, test_ch->name);
- continue;
- }
- }
-
- memset(test_ch->buf, 0x00, sizeof(test_ch->buf));
-
- ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sdio_read for chan %s"
- " err=%d.\n", test_ch->name, -ret);
- goto exit_err;
- }
-
- memcpy((void *)&lpm_msg, test_ch->buf, sizeof(lpm_msg));
-
- /*
- * when reading from channel, we want to turn off the bit
- * mask that implies that there is pending data on that channel
- */
- if (test_ch->test_device != NULL) {
- spin_lock_irqsave(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
-
- test_ch->notify_counter_per_chan--;
-
- /*
- * if the channel has no pending data, turn off the
- * pending data bit mask of the channel
- */
- if (test_ch->notify_counter_per_chan == 0) {
- test_ch->test_device->read_avail_mask =
- test_ch->test_device->read_avail_mask &
- ~test_ch->channel_mask_id;
- }
-
- last_msg_index = lpm_msg.counter;
- lpm_test_update_entry(test_ch,
- LPM_MSG_REC,
- "RECEIVE",
- last_msg_index);
-
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- }
- }
-
- pr_info(TEST_MODULE_NAME ":%s: Finished to recieve all (%d) "
- "packets from the modem %s. Waiting for result_msg",
- __func__, test_ch->config_msg.num_packets, test_ch->name);
-
- /* Wait for the resault message from the modem */
- test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
-
- /*
- * the DEVICE modem result is a failure if one of the channels on
- * that device, got modem_result = 0. this is why we bitwise "AND" each
- * time another channel completes its task
- */
- test_dev->modem_result_per_dev &= test_ch->modem_result_per_chan;
-
- /*
- * when reading from channel, we want to turn off the bit
- * mask that implies that there is pending data on that channel
- */
- spin_lock_irqsave(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
-
- test_dev->open_channels_counter_to_recv--;
-
- /* turning off the read_avail bit of the channel */
- test_ch->test_device->read_avail_mask =
- test_ch->test_device->read_avail_mask &
- ~test_ch->channel_mask_id;
-
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
-
- /* Wait for all the packets to be sent to the modem */
- while (1) {
- spin_lock_irqsave(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
-
- if (test_ch->next_index_in_sent_msg_per_chan >=
- test_ch->config_msg.num_packets - 1) {
-
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- break;
- } else {
- pr_info(TEST_MODULE_NAME ":%s: Didn't finished to send "
- "all packets, "
- "next_index_in_sent_msg_per_chan = %d ",
- __func__,
- test_ch->next_index_in_sent_msg_per_chan);
- }
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- msleep(60);
- }
-
- /*
- * if device has still open channels to test, then the test on the
- * device is still running but the test on current channel is completed
- */
- if (test_dev->open_channels_counter_to_recv != 0 ||
- test_dev->open_channels_counter_to_send != 0) {
- test_ch->test_completed = 1;
- return 0;
- } else {
- test_ctx->number_of_active_devices--;
- sdio_al_unregister_lpm_cb(test_ch->sdio_al_device);
-
- if (test_ch->test_type == SDIO_TEST_LPM_RANDOM)
- host_result = check_random_lpm_test_array(test_dev);
-
- if (host_result ||
- !test_dev->modem_result_per_dev ||
- test_ctx->runtime_debug)
- print_random_lpm_test_array(test_dev);
-
- pr_info(TEST_MODULE_NAME ": %s - host_result=%d.(0 for "
- "SUCCESS) device_modem_result=%d (1 for SUCCESS)",
- __func__, host_result, test_dev->modem_result_per_dev);
-
- test_ch->test_completed = 1;
- if (test_dev->modem_result_per_dev && !host_result) {
- pr_info(TEST_MODULE_NAME ": %s - Random LPM "
- "TEST_PASSED for device %d of %d\n",
- __func__,
- (test_ctx->max_number_of_devices-
- test_ctx->number_of_active_devices),
- test_ctx->max_number_of_devices);
- test_dev->final_result_per_dev = 1; /* PASSED */
- } else {
- pr_info(TEST_MODULE_NAME ": %s - Random LPM "
- "TEST_FAILED for device %d of %d\n",
- __func__,
- (test_ctx->max_number_of_devices-
- test_ctx->number_of_active_devices),
- test_ctx->max_number_of_devices);
- test_dev->final_result_per_dev = 0; /* FAILED */
- }
-
- check_test_completion();
-
- kfree(test_ch->test_device->lpm_arr);
-
- return 0;
- }
-
-exit_err:
- pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
- test_ch->name);
- test_ch->test_completed = 1;
- test_dev->open_channels_counter_to_recv--;
- test_dev->next_avail_entry_in_array = 0;
- test_ch->next_index_in_sent_msg_per_chan = 0;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return -ENODEV;
-}
-
-static int lpm_test_create_read_thread(struct test_channel *test_ch)
-{
- struct sdio_test_device *test_dev;
-
- pr_info(TEST_MODULE_NAME ": %s - STARTED channel %s\n",
- __func__, test_ch->name);
-
- if (!test_ch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
- return -ENODEV;
- }
-
- test_dev = test_ch->test_device;
-
- if (!test_dev) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test device\n", __func__);
- return -ENODEV;
- }
-
- test_dev->lpm_test_task.task_name = SDIO_LPM_TEST;
-
- test_dev->lpm_test_task.lpm_task =
- kthread_create(lpm_test_main_task,
- (void *)(test_ch),
- test_dev->lpm_test_task.task_name);
-
- if (IS_ERR(test_dev->lpm_test_task.lpm_task)) {
- pr_err(TEST_MODULE_NAME ": %s - kthread_create() failed\n",
- __func__);
- return -ENOMEM;
- }
-
- wake_up_process(test_dev->lpm_test_task.lpm_task);
-
- return 0;
-}
-
-static void lpm_continuous_rand_test(struct test_channel *test_ch)
-{
- unsigned int local_ms = 0;
- int ret = 0;
- unsigned int write_avail = 0;
- struct sdio_test_device *test_dev;
-
- pr_info(MODULE_NAME ": %s - STARTED\n", __func__);
-
- if (!test_ch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
- return;
- }
-
- test_dev = test_ch->test_device;
-
- if (!test_dev) {
- pr_err(TEST_MODULE_NAME ": %s - NULL Test Device\n", __func__);
- return;
- }
-
- ret = lpm_test_create_read_thread(test_ch);
- if (ret != 0) {
- pr_err(TEST_MODULE_NAME ": %s - failed to create lpm reading "
- "thread", __func__);
- }
-
- while (1) {
-
- struct lpm_msg msg;
- u32 ret = 0;
-
- /* sleeping period is dependent on number of open channels */
- test_ch->config_msg.test_param =
- test_ctx->lpm_pseudo_random_seed;
-
- local_ms = test_dev->open_channels_counter_to_send *
- test_ctx->lpm_pseudo_random_seed;
- TEST_DBG(TEST_MODULE_NAME ":%s: SLEEPING for %d ms",
- __func__, local_ms);
- msleep(local_ms);
-
- msg.counter = test_ch->next_index_in_sent_msg_per_chan;
- msg.signature = LPM_TEST_CONFIG_SIGNATURE;
- msg.reserve1 = 0;
- msg.reserve2 = 0;
-
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- pr_debug(TEST_MODULE_NAME ": %s: write_avail=%d\n",
- __func__, write_avail);
- if (write_avail < sizeof(msg)) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- if (write_avail < sizeof(msg)) {
- pr_info(TEST_MODULE_NAME ": %s: not enough write "
- "avail.\n", __func__);
- break;
- }
-
- ret = sdio_write(test_ch->ch, (u32 *)&msg, sizeof(msg));
- if (ret)
- pr_err(TEST_MODULE_NAME ":%s: sdio_write err=%d.\n",
- __func__, -ret);
-
- TEST_DBG(TEST_MODULE_NAME ": %s: for chan %s, write, "
- "msg # %d\n",
- __func__,
- test_ch->name,
- test_ch->next_index_in_sent_msg_per_chan);
-
- if (test_ch->test_type == SDIO_TEST_LPM_RANDOM) {
- spin_lock_irqsave(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- lpm_test_update_entry(test_ch, LPM_MSG_SEND,
- "SEND ",
- test_ch->
- next_index_in_sent_msg_per_chan);
-
- test_ch->next_index_in_sent_msg_per_chan++;
-
- if (test_ch->next_index_in_sent_msg_per_chan ==
- test_ch->config_msg.num_packets) {
- spin_unlock_irqrestore(
- &test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- break;
- }
-
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- }
- }
-
- spin_lock_irqsave(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
- test_dev->open_channels_counter_to_send--;
- spin_unlock_irqrestore(&test_dev->lpm_array_lock,
- test_dev->lpm_array_lock_flags);
-
- pr_info(TEST_MODULE_NAME ": %s: - Finished to send all (%d) "
- "packets to the modem on channel %s",
- __func__, test_ch->config_msg.num_packets, test_ch->name);
-
- return;
-}
-
-static void lpm_test(struct test_channel *test_ch)
-{
- pr_info(TEST_MODULE_NAME ": %s - START channel %s\n", __func__,
- test_ch->name);
-
- if (!test_ch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL test channel\n", __func__);
- return;
- }
-
- test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
- pr_debug(TEST_MODULE_NAME ": %s - delete the timeout timer\n",
- __func__);
- del_timer_sync(&test_ch->timeout_timer);
-
- if (test_ch->modem_result_per_chan == 0) {
- pr_err(TEST_MODULE_NAME ": LPM TEST - Client didn't sleep. "
- "Result Msg - is_successful=%d\n", test_ch->buf[1]);
- goto exit_err;
- } else {
- pr_info(TEST_MODULE_NAME ": %s -"
- "LPM 9K WAS SLEEPING - PASS\n", __func__);
- if (test_ch->test_result == TEST_PASSED) {
- pr_info(TEST_MODULE_NAME ": LPM TEST_PASSED\n");
- test_ch->test_completed = 1;
- check_test_completion();
- } else {
- pr_err(TEST_MODULE_NAME ": LPM TEST - Host didn't "
- "sleep. Client slept\n");
- goto exit_err;
- }
- }
-
- return;
-
-exit_err:
- pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-
-/**
- * LPM Test while the host wakes up the modem
- */
-static void lpm_test_host_waker(struct test_channel *test_ch)
-{
- pr_info(TEST_MODULE_NAME ": %s - START\n", __func__);
- wait_event(test_ch->wait_q, atomic_read(&test_ch->wakeup_client));
- atomic_set(&test_ch->wakeup_client, 0);
-
- pr_info(TEST_MODULE_NAME ": %s - Sending the config_msg to wakeup "
- " the client\n", __func__);
- send_config_msg(test_ch);
-
- lpm_test(test_ch);
-}
-
-/**
- * Writes number of packets into test channel
- * @test_ch: test channel control struct
- * @burst_size: number of packets to send
- */
-static int write_packet_burst(struct test_channel *test_ch,
- int burst_size)
-{
- int ret = 0;
- int packet_count = 0;
- unsigned int random_num = 0;
- int size = test_ch->packet_length; /* first packet size */
- u32 write_avail = 0;
-
- while (packet_count < burst_size) {
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":%s write_avail=%d,size=%d on chan"
- " %s\n", __func__,
- write_avail, size, test_ch->name);
- if (write_avail < size) {
- TEST_DBG(TEST_MODULE_NAME ":%s wait for event on"
- " chan %s\n", __func__, test_ch->name);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
- write_avail = sdio_write_avail(test_ch->ch);
- if (write_avail < size) {
- pr_info(TEST_MODULE_NAME ":%s not enough write"
- " avail %d, need %d on chan %s\n",
- __func__, write_avail, size,
- test_ch->name);
- continue;
- }
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s sdio_write "
- "failed (%d) on chan %s\n", __func__,
- ret, test_ch->name);
- break;
- }
- udelay(1000); /*low bus usage while running number of channels*/
- TEST_DBG(TEST_MODULE_NAME ":%s() successfully write %d bytes"
- ", packet_count=%d on chan %s\n", __func__,
- size, packet_count, test_ch->name);
- test_ch->tx_bytes += size;
- packet_count++;
- /* get next packet size */
- random_num = get_random_int();
- size = (random_num % test_ch->packet_length) + 1;
- }
- return ret;
-}
-
-/**
- * Reads packet from test channel and checks that packet number
- * encoded into the packet is equal to packet_counter
- * This function is applicable for packet mode channels only
- *
- * @test_ch: test channel
- * @size: expected packet size
- * @packet_counter: number to validate readed packet
- */
-static int read_data_from_packet_ch(struct test_channel *test_ch,
- unsigned int size,
- int packet_counter)
-{
- u32 read_avail = 0;
- int ret = 0;
-
- if (!test_ch || !test_ch->ch) {
- pr_err(TEST_MODULE_NAME
- ":%s: NULL channel\n", __func__);
- return -EINVAL;
- }
-
- if (!test_ch->ch->is_packet_mode) {
- pr_err(TEST_MODULE_NAME
- ":%s:not packet mode ch %s\n",
- __func__, test_ch->name);
- return -EINVAL;
- }
- read_avail = sdio_read_avail(test_ch->ch);
- /* wait for read data ready event */
- if (read_avail < size) {
- TEST_DBG(TEST_MODULE_NAME ":%s() wait for rx data on "
- "chan %s\n", __func__, test_ch->name);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
- }
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":%s read_avail=%d bytes on chan %s\n",
- __func__, read_avail, test_ch->name);
-
- if (read_avail != size) {
- pr_err(TEST_MODULE_NAME
- ":read_avail size %d for chan %s not as "
- "expected size %d\n",
- read_avail, test_ch->name, size);
- return -EINVAL;
- }
-
- ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s() sdio_read for chan %s (%d)\n",
- __func__, test_ch->name, -ret);
- return ret;
- }
- if ((test_ch->buf[0] != packet_counter) && (size != 1)) {
- pr_err(TEST_MODULE_NAME ":Read WRONG DATA"
- " for chan %s, size=%d\n",
- test_ch->name, size);
- return -EINVAL;
- }
- return 0;
-}
-
-
-/**
- * Reads packet from test channel and checks that packet number
- * encoded into the packet is equal to packet_counter
- * This function is applicable for streaming mode channels only
- *
- * @test_ch: test channel
- * @size: expected packet size
- * @packet_counter: number to validate readed packet
- */
-static int read_data_from_stream_ch(struct test_channel *test_ch,
- unsigned int size,
- int packet_counter)
-{
- u32 read_avail = 0;
- int ret = 0;
-
- if (!test_ch || !test_ch->ch) {
- pr_err(TEST_MODULE_NAME
- ":%s: NULL channel\n", __func__);
- return -EINVAL;
- }
-
- if (test_ch->ch->is_packet_mode) {
- pr_err(TEST_MODULE_NAME
- ":%s:not streaming mode ch %s\n",
- __func__, test_ch->name);
- return -EINVAL;
- }
- read_avail = sdio_read_avail(test_ch->ch);
- /* wait for read data ready event */
- if (read_avail < size) {
- TEST_DBG(TEST_MODULE_NAME ":%s() wait for rx data on "
- "chan %s\n", __func__, test_ch->name);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
- }
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":%s read_avail=%d bytes on chan %s\n",
- __func__, read_avail, test_ch->name);
-
- if (read_avail < size) {
- pr_err(TEST_MODULE_NAME
- ":read_avail size %d for chan %s not as "
- "expected size %d\n",
- read_avail, test_ch->name, size);
- return -EINVAL;
- }
-
- ret = sdio_read(test_ch->ch, test_ch->buf, size + A2_HEADER_OVERHEAD);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s() sdio_read for chan %s (%d)\n",
- __func__, test_ch->name, -ret);
- return ret;
- }
- if ((test_ch->buf[A2_HEADER_OVERHEAD/4] != packet_counter) &&
- (size != 1)) {
- pr_err(TEST_MODULE_NAME ":Read WRONG DATA"
- " for chan %s, size=%d, packet_counter=%d\n",
- test_ch->name, size, packet_counter);
- print_hex_dump(KERN_INFO, TEST_MODULE_NAME ": rmnet:",
- 0, 32, 2,
- (void *)test_ch->buf,
- size + A2_HEADER_OVERHEAD, false);
- return -EINVAL;
- }
- return 0;
-}
-
-/**
- * Test close channel feature for SDIO_SMEM channel:
- * close && re-open the SDIO_SMEM channel.
- */
-#ifdef CONFIG_MSM_SDIO_SMEM
-static void open_close_smem_test(struct test_channel *test_ch)
-{
- int i = 0;
- int ret = 0;
-
- pr_info(TEST_MODULE_NAME ":%s\n", __func__);
-
- for (i = 0; i < 100 ; ++i) {
- ret = close_sdio_ch(test_ch);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s close_sdio_ch for ch %s"
- " failed\n",
- __func__, test_ch->name);
- goto exit_err;
- }
- ret = open_sdio_ch(test_ch);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s open_sdio_ch for ch %s "
- " failed\n",
- __func__, test_ch->name);
- goto exit_err;
- }
- }
-
- pr_info(TEST_MODULE_NAME ":%s TEST PASS for chan %s.\n", __func__,
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-exit_err:
- pr_info(TEST_MODULE_NAME ":%s TEST FAIL for chan %s.\n", __func__,
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-#endif
-
-/**
- * Test close channel feature:
- * 1. write random packet number into channel
- * 2. read some data from channel (do this only for second half of
- * requested packets to send).
- * 3. close && re-open then repeat 1.
- *
- * Total packets to send: test_ch->config_msg.num_packets.
- * Burst size is random in [1..test_ch->max_burst_size] range
- * Packet size is random in [1..test_ch->packet_length]
- */
-static void open_close_test(struct test_channel *test_ch)
-{
- int ret = 0;
- u32 read_avail = 0;
- int total_packet_count = 0;
- int size = 0;
- u16 *buf16 = NULL;
- int i;
- int max_packet_count = 0;
- unsigned int random_num = 0;
- int curr_burst_size = 0;
-
- if (!test_ch || !test_ch->ch) {
- pr_err(TEST_MODULE_NAME ":%s NULL channel\n",
- __func__);
- return;
- }
-
- curr_burst_size = test_ch->max_burst_size;
- size = test_ch->packet_length;
- buf16 = (u16 *) test_ch->buf;
-
- /* the test sends configured number of packets in
- 2 portions: first without reading between write bursts,
- second with it */
- max_packet_count = test_ch->config_msg.num_packets / 2;
-
- pr_info(TEST_MODULE_NAME ":%s channel %s, total packets:%d,"
- " max packet size %d, max burst size:%d\n",
- __func__, test_ch->name,
- test_ch->config_msg.num_packets, test_ch->packet_length,
- test_ch->max_burst_size);
- for (i = 0 ; i < size / 2 ; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
- for (i = 0; i < 2 ; i++) {
- total_packet_count = 0;
- while (total_packet_count < max_packet_count) {
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":%s exit test\n",
- __func__);
- return;
- }
- test_ch->buf[0] = total_packet_count;
- random_num = get_random_int();
- curr_burst_size = (random_num %
- test_ch->max_burst_size) + 1;
-
- /* limit burst size to send
- * no more than configured packets */
- if (curr_burst_size + total_packet_count >
- max_packet_count) {
- curr_burst_size = max_packet_count -
- total_packet_count;
- }
- TEST_DBG(TEST_MODULE_NAME ":%s Current burst size:%d"
- " on chan %s\n", __func__,
- curr_burst_size, test_ch->name);
- ret = write_packet_burst(test_ch, curr_burst_size);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s write burst failed (%d), ch %s\n",
- __func__, ret, test_ch->name);
- goto exit_err;
- }
- if (i > 0) {
- /* read from channel */
- if (test_ch->ch->is_packet_mode)
- ret = read_data_from_packet_ch(test_ch,
- size,
- total_packet_count);
- else
- ret = read_data_from_stream_ch(test_ch,
- size,
- total_packet_count);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s read"
- " failed:%d, chan %s\n",
- __func__, ret,
- test_ch->name);
- goto exit_err;
- }
- }
- TEST_DBG(TEST_MODULE_NAME ":%s before close, ch %s\n",
- __func__, test_ch->name);
- ret = close_sdio_ch(test_ch);
- if (ret) {
- pr_err(TEST_MODULE_NAME":%s close channel %s"
- " failed (%d)\n",
- __func__, test_ch->name, ret);
- goto exit_err;
- } else {
- TEST_DBG(TEST_MODULE_NAME":%s close channel %s"
- " success\n", __func__,
- test_ch->name);
- total_packet_count += curr_burst_size;
- atomic_set(&test_ch->rx_notify_count, 0);
- atomic_set(&test_ch->tx_notify_count, 0);
- atomic_set(&test_ch->any_notify_count, 0);
- }
- TEST_DBG(TEST_MODULE_NAME ":%s before open, ch %s\n",
- __func__, test_ch->name);
- ret = open_sdio_ch(test_ch);
- if (ret) {
- pr_err(TEST_MODULE_NAME":%s open channel %s"
- " failed (%d)\n",
- __func__, test_ch->name, ret);
- goto exit_err;
- } else {
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail > 0) {
- pr_err(TEST_MODULE_NAME": after open"
- " ch %s read_availis not zero"
- " (%d bytes)\n",
- test_ch->name, read_avail);
- goto exit_err;
- }
- }
- TEST_DBG(TEST_MODULE_NAME ":%s total tx = %d,"
- " packet# = %d, size = %d for ch %s\n",
- __func__, test_ch->tx_bytes,
- total_packet_count, size,
- test_ch->name);
- } /* end of while */
- }
- pr_info(TEST_MODULE_NAME ":%s Test end: total rx bytes = 0x%x,"
- " total tx bytes = 0x%x for chan %s\n", __func__,
- test_ch->rx_bytes, test_ch->tx_bytes, test_ch->name);
- pr_info(TEST_MODULE_NAME ":%s TEST PASS for chan %s.\n", __func__,
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-exit_err:
- pr_info(TEST_MODULE_NAME ":%s TEST FAIL for chan %s.\n", __func__,
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-/**
- * sender Test
- */
-static void sender_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
- int packet_count = 0;
- int size = 512;
- u16 *buf16 = (u16 *) test_ch->buf;
- int i;
- int max_packet_count = 10000;
- int random_num = 0;
-
- max_packet_count = test_ch->config_msg.num_packets;
-
- for (i = 0 ; i < size / 2 ; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
-
- pr_info(TEST_MODULE_NAME
- ":SENDER TEST START for chan %s\n", test_ch->name);
-
- while (packet_count < max_packet_count) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- random_num = get_random_int();
- size = (random_num % test_ch->packet_length) + 1;
-
- TEST_DBG(TEST_MODULE_NAME "SENDER WAIT FOR EVENT for chan %s\n",
- test_ch->name);
-
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
- continue;
- }
-
- test_ch->buf[0] = packet_count;
-
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sender sdio_write err=%d.\n",
- -ret);
- goto exit_err;
- }
-
- /* wait for read data ready event */
- TEST_DBG(TEST_MODULE_NAME ":sender wait for rx data for "
- "chan %s\n",
- test_ch->name);
- read_avail = sdio_read_avail(test_ch->ch);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->rx_notify_count));
- atomic_dec(&test_ch->rx_notify_count);
-
- read_avail = sdio_read_avail(test_ch->ch);
-
- if (read_avail != size) {
- pr_info(TEST_MODULE_NAME
- ":read_avail size %d for chan %s not as "
- "expected size %d.\n",
- read_avail, test_ch->name, size);
- goto exit_err;
- }
-
- memset(test_ch->buf, 0x00, size);
-
- ret = sdio_read(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sender sdio_read for chan %s"
- " err=%d.\n",
- test_ch->name, -ret);
- goto exit_err;
- }
-
-
- if ((test_ch->buf[0] != packet_count) && (size != 1)) {
- pr_info(TEST_MODULE_NAME ":sender sdio_read WRONG DATA"
- " for chan %s, size=%d\n",
- test_ch->name, size);
- goto exit_err;
- }
-
- test_ch->tx_bytes += size;
- test_ch->rx_bytes += size;
- packet_count++;
-
- TEST_DBG(TEST_MODULE_NAME
- ":sender total rx bytes = 0x%x , packet#=%d, size=%d"
- " for chan %s\n",
- test_ch->rx_bytes, packet_count, size, test_ch->name);
- TEST_DBG(TEST_MODULE_NAME
- ":sender total tx bytes = 0x%x , packet#=%d, size=%d"
- " for chan %s\n",
- test_ch->tx_bytes, packet_count, size, test_ch->name);
-
- } /* end of while */
-
- pr_info(TEST_MODULE_NAME
- ":SENDER TEST END: total rx bytes = 0x%x, "
- " total tx bytes = 0x%x for chan %s\n",
- test_ch->rx_bytes, test_ch->tx_bytes, test_ch->name);
-
- pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s.\n",
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-
-exit_err:
- pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-/**
- * A2 Perf Test
- */
-static void a2_performance_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
- int tx_packet_count = 0;
- int rx_packet_count = 0;
- int size = 0;
- u16 *buf16 = (u16 *) test_ch->buf;
- int i;
- int total_bytes = 0;
- int max_packets = 10000;
- u32 packet_size = test_ch->buf_size;
- int rand_size = 0;
-
- u64 start_jiffy, end_jiffy, delta_jiffies;
- unsigned int time_msec = 0;
- u32 throughput = 0;
-
- max_packets = test_ch->config_msg.num_packets;
- packet_size = test_ch->packet_length;
-
- for (i = 0; i < packet_size / 2; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
- pr_info(TEST_MODULE_NAME ": A2 PERFORMANCE TEST START for chan %s\n",
- test_ch->name);
-
- start_jiffy = get_jiffies_64(); /* read the current time */
-
- while (tx_packet_count < max_packets) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- if (test_ch->random_packet_size) {
- rand_size = get_random_int();
- packet_size = (rand_size % test_ch->packet_length) + 1;
- if (packet_size < A2_MIN_PACKET_SIZE)
- packet_size = A2_MIN_PACKET_SIZE;
- }
-
- /* wait for data ready event */
- /* use a func to avoid compiler optimizations */
- write_avail = sdio_write_avail(test_ch->ch);
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d, "
- "read_avail=%d for chan %s\n",
- test_ch->name, write_avail, read_avail,
- test_ch->name);
- if ((write_avail == 0) && (read_avail == 0)) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->any_notify_count));
- atomic_set(&test_ch->any_notify_count, 0);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
- test_ch->name, write_avail);
- if (write_avail > 0) {
- size = min(packet_size, write_avail) ;
- TEST_DBG(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
- size, test_ch->name);
- test_ch->buf[0] = tx_packet_count;
- test_ch->buf[(size/4)-1] = tx_packet_count;
-
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sdio_write err=%d"
- " for chan %s\n",
- -ret, test_ch->name);
- goto exit_err;
- }
- tx_packet_count++;
- test_ch->tx_bytes += size;
- }
-
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
- test_ch->name, read_avail);
- if (read_avail > 0) {
- size = min(packet_size, read_avail);
- pr_debug(TEST_MODULE_NAME ":rx size = %d.\n", size);
- ret = sdio_read(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ": sdio_read size %d "
- " err=%d"
- " for chan %s\n",
- size, -ret, test_ch->name);
- goto exit_err;
- }
- rx_packet_count++;
- test_ch->rx_bytes += size;
- }
-
- TEST_DBG(TEST_MODULE_NAME
- ":total rx bytes = %d , rx_packet#=%d"
- " for chan %s\n",
- test_ch->rx_bytes, rx_packet_count, test_ch->name);
- TEST_DBG(TEST_MODULE_NAME
- ":total tx bytes = %d , tx_packet#=%d"
- " for chan %s\n",
- test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
- } /* while (tx_packet_count < max_packets ) */
-
- end_jiffy = get_jiffies_64(); /* read the current time */
-
- delta_jiffies = end_jiffy - start_jiffy;
- time_msec = jiffies_to_msecs(delta_jiffies);
-
- pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for"
- " chan %s.\n",
- test_ch->rx_bytes, rx_packet_count, test_ch->name);
- pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d"
- " for chan %s.\n",
- test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
- total_bytes = (test_ch->tx_bytes + test_ch->rx_bytes);
- pr_err(TEST_MODULE_NAME ":total bytes = %d, time msec = %d"
- " for chan %s\n",
- total_bytes , (int) time_msec, test_ch->name);
-
- if (!test_ch->random_packet_size) {
- if (time_msec) {
- throughput = (total_bytes / time_msec) * 8 / 1000;
- pr_err(TEST_MODULE_NAME ": %s - Performance = "
- "%d Mbit/sec for chan %s\n",
- __func__, throughput, test_ch->name);
- } else {
- pr_err(TEST_MODULE_NAME ": %s - time_msec = 0 Couldn't "
- "calculate performence for chan %s\n",
- __func__, test_ch->name);
- }
-
- }
-
-#ifdef CONFIG_DEBUG_FS
- switch (test_ch->ch_id) {
- case SDIO_DUN:
- test_ctx->debug.dun_throughput = throughput;
- break;
- case SDIO_RMNT:
- test_ctx->debug.rmnt_throughput = throughput;
- break;
- default:
- pr_err(TEST_MODULE_NAME "No debugfs for this channel "
- "throughput");
- }
-#endif
-
- pr_err(TEST_MODULE_NAME ": A2 PERFORMANCE TEST END for chan %s.\n",
- test_ch->name);
-
- pr_err(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-
-exit_err:
- pr_err(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-/**
- * rx_cleanup
- * This function reads all the messages sent by the modem until
- * the read_avail is 0 after 1 second of sleep.
- * The function returns the number of packets that was received.
- */
-static void rx_cleanup(struct test_channel *test_ch, int *rx_packet_count)
-{
- int read_avail = 0;
- int ret = 0;
- int counter = 0;
-
- if (!test_ch || !test_ch->ch) {
- pr_err(TEST_MODULE_NAME ":%s NULL channel\n",
- __func__);
- return;
- }
-
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
- test_ch->name, read_avail);
-
- /* If no pending messages, wait to see if the modem sends data */
- if (read_avail == 0) {
- msleep(1000);
- read_avail = sdio_read_avail(test_ch->ch);
- }
-
- while ((read_avail > 0) && (counter < 10)) {
- TEST_DBG(TEST_MODULE_NAME ": read_avail=%d for ch %s\n",
- read_avail, test_ch->name);
-
- ret = sdio_read(test_ch->ch, test_ch->buf, read_avail);
- if (ret) {
- pr_info(TEST_MODULE_NAME ": sdio_read size %d "
- " err=%d for chan %s\n",
- read_avail, -ret, test_ch->name);
- break;
- }
- (*rx_packet_count)++;
- test_ch->rx_bytes += read_avail;
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail == 0) {
- msleep(1000);
- counter++;
- read_avail = sdio_read_avail(test_ch->ch);
- }
- }
- pr_info(TEST_MODULE_NAME ": finished cleanup for ch %s, "
- "rx_packet_count=%d, total rx bytes=%d\n",
- test_ch->name, *rx_packet_count, test_ch->rx_bytes);
-}
-
-
-/**
- * A2 RTT Test
- * This function sends a packet and calculate the RTT time of
- * this packet.
- * The test also calculte Min, Max and Average RTT
- */
-static void a2_rtt_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
- int tx_packet_count = 0;
- int rx_packet_count = 0;
- u16 *buf16 = NULL;
- int i;
- int max_packets = 0;
- u32 packet_size = 0;
- s64 start_time, end_time;
- int delta_usec = 0;
- int time_average = 0;
- int min_delta_usec = 0xFFFF;
- int max_delta_usec = 0;
- int total_time = 0;
- int expected_read_size = 0;
- int delay_ms = 0;
- int slow_rtt_counter = 0;
- int read_avail_so_far = 0;
-
- if (test_ch) {
- /*
- * Cleanup the pending RX data (such as loopback of the
- * config msg)
- */
- rx_cleanup(test_ch, &rx_packet_count);
- rx_packet_count = 0;
- } else {
- return;
- }
-
- max_packets = test_ch->config_msg.num_packets;
- packet_size = test_ch->packet_length;
- buf16 = (u16 *) test_ch->buf;
-
- for (i = 0; i < packet_size / 2; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
- pr_info(TEST_MODULE_NAME ": A2 RTT TEST START for chan %s\n",
- test_ch->name);
-
- switch (test_ch->ch_id) {
- case SDIO_RMNT:
- delay_ms = 100;
- break;
- case SDIO_CSVT:
- delay_ms = 0;
- break;
- default:
- pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n",
- __func__);
- return;
- }
-
- while (tx_packet_count < max_packets) {
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
- start_time = 0;
- end_time = 0;
- read_avail_so_far = 0;
-
- if (delay_ms)
- msleep(delay_ms);
-
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":ch %s: write_avail=%d\n",
- test_ch->name, write_avail);
- if (write_avail == 0) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
- test_ch->name, write_avail);
- if (write_avail > 0) {
- TEST_DBG(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
- packet_size, test_ch->name);
- test_ch->buf[0] = tx_packet_count;
-
- start_time = ktime_to_us(ktime_get());
- ret = sdio_write(test_ch->ch, test_ch->buf,
- packet_size);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":sdio_write err=%d"
- " for chan %s\n",
- -ret, test_ch->name);
- goto exit_err;
- }
- tx_packet_count++;
- test_ch->tx_bytes += packet_size;
- } else {
- pr_err(TEST_MODULE_NAME ": Invalid write_avail"
- " %d for chan %s\n",
- write_avail, test_ch->name);
- goto exit_err;
- }
-
- expected_read_size = packet_size + A2_HEADER_OVERHEAD;
-
- while (read_avail_so_far < expected_read_size) {
-
- read_avail = sdio_read_avail(test_ch->ch);
-
- if (!read_avail) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->
- rx_notify_count));
-
- atomic_dec(&test_ch->rx_notify_count);
- continue;
- }
-
- read_avail_so_far += read_avail;
-
- if (read_avail_so_far > expected_read_size) {
- pr_err(TEST_MODULE_NAME ": %s - Invalid "
- "read_avail(%d) read_avail_so_far(%d) "
- "can't be larger than "
- "expected_read_size(%d).",
- __func__,
- read_avail,
- read_avail_so_far,
- expected_read_size);
- goto exit_err;
- }
-
- /*
- * must read entire pending bytes, so later, we will
- * get a notification when more data arrives
- */
- ret = sdio_read(test_ch->ch, test_ch->buf,
- read_avail);
-
- if (ret) {
- pr_info(TEST_MODULE_NAME ": sdio_read size %d "
- " err=%d for chan %s\n",
- read_avail, -ret,
- test_ch->name);
- goto exit_err;
- }
- }
-
- end_time = ktime_to_us(ktime_get());
- rx_packet_count++;
- test_ch->rx_bytes += expected_read_size;
-
- delta_usec = (int)(end_time - start_time);
- total_time += delta_usec;
- if (delta_usec < min_delta_usec)
- min_delta_usec = delta_usec;
- if (delta_usec > max_delta_usec)
- max_delta_usec = delta_usec;
-
- /* checking the RTT per channel criteria */
- if (delta_usec > MAX_AVG_RTT_TIME_USEC) {
- pr_err(TEST_MODULE_NAME ": %s - "
- "msg # %d - rtt time (%d usec) is "
- "longer than %d usec\n",
- __func__,
- tx_packet_count,
- delta_usec,
- MAX_AVG_RTT_TIME_USEC);
- slow_rtt_counter++;
- }
-
- TEST_DBG(TEST_MODULE_NAME
- ":RTT time=%d for packet #%d for chan %s\n",
- delta_usec, tx_packet_count, test_ch->name);
- } /* while (tx_packet_count < max_packets ) */
-
- pr_info(TEST_MODULE_NAME ": %s - tx_packet_count = %d\n",
- __func__, tx_packet_count);
-
- pr_info(TEST_MODULE_NAME ": %s - total rx bytes = 0x%x, "
- "rx_packet# = %d for chan %s.\n",
- __func__, test_ch->rx_bytes, rx_packet_count, test_ch->name);
-
- pr_info(TEST_MODULE_NAME ": %s - total tx bytes = 0x%x, "
- "tx_packet# = %d for chan %s.\n",
- __func__, test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
- pr_info(TEST_MODULE_NAME ": %s - slow_rtt_counter = %d for "
- "chan %s.\n",
- __func__, slow_rtt_counter, test_ch->name);
-
- if (tx_packet_count) {
- time_average = total_time / tx_packet_count;
- pr_info(TEST_MODULE_NAME ":Average RTT time = %d for chan %s\n",
- time_average, test_ch->name);
- } else {
- pr_err(TEST_MODULE_NAME ": %s - tx_packet_count=0. couldn't "
- "calculate average rtt time", __func__);
- }
-
- pr_info(TEST_MODULE_NAME ":MIN RTT time = %d for chan %s\n",
- min_delta_usec, test_ch->name);
- pr_info(TEST_MODULE_NAME ":MAX RTT time = %d for chan %s\n",
- max_delta_usec, test_ch->name);
-
- pr_info(TEST_MODULE_NAME ": A2 RTT TEST END for chan %s.\n",
- test_ch->name);
-
- if (ret)
- goto exit_err;
-
- if (time_average == 0 || time_average > MAX_AVG_RTT_TIME_USEC) {
- pr_err(TEST_MODULE_NAME ": %s - average_time = %d. Invalid "
- "value",
- __func__, time_average);
- goto exit_err;
-
- }
-
- pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-
-exit_err:
- pr_err(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-/**
- * Process Rx Data - Helper for A2 Validation Test
- * @test_ch(in/out) : Test channel that contains Rx data buffer to process.
- *
- * @rx_unprocessed_bytes(in) : Number of bytes to process in the buffer.
- *
- * @rx_process_packet_state(in/out) :
- * Current processing state (used to identify what to process
- * next in a partial packet)
- *
- * @rx_packet_size(in/out) :
- * Number of bytes remaining in the packet to be processed.
- *
- * @rx_packet_count(in/out) :
- * Number of packets processed.
- */
-static int process_rx_data(struct test_channel *test_ch,
- u32 rx_unprocessed_bytes,
- int *rx_process_packet_state,
- u16 *rx_packet_size,
- int *rx_packet_count)
-{
- u8 *buf = (u8 *)test_ch->buf;
- int eop = 0;
- int i = 0;
- int ret = 0;
- u32 *ptr = 0;
- u16 size = 0;
-
- /* process rx data */
- while (rx_unprocessed_bytes) {
- TEST_DBG(TEST_MODULE_NAME ": unprocessed bytes : %u\n",
- rx_unprocessed_bytes);
-
- switch (*rx_process_packet_state) {
- case RX_PROCESS_PACKET_INIT:
- /* process the A2 header */
- TEST_DBG(TEST_MODULE_NAME ": "
- "RX_PROCESS_PACKET_INIT\n");
- *rx_process_packet_state = RX_PROCESS_PACKET_INIT;
- if (rx_unprocessed_bytes < 4)
- break;
-
- i += 4;
- rx_unprocessed_bytes -= 4;
-
- case RX_PROCESS_A2_HEADER:
- /* process the rest of A2 header */
- TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_A2_HEADER\n");
- *rx_process_packet_state = RX_PROCESS_A2_HEADER;
- if (rx_unprocessed_bytes < 4)
- break;
-
- ptr = (u32 *)&buf[i];
- /*
- * upper 2 bytes of the last 4 bytes of A2 header
- * contains the size of the packet
- */
- *rx_packet_size = *ptr >> 0x10;
-
- i += 4;
- rx_unprocessed_bytes -= 4;
-
- case RX_PROCESS_PACKET_DATA:
- /* process the2_2_ packet data */
- TEST_DBG(TEST_MODULE_NAME ": RX_PROCESS_PACKET_DATA "
- "- packet size - %u\n", *rx_packet_size);
- *rx_process_packet_state = RX_PROCESS_PACKET_DATA;
-
- size = *rx_packet_size;
- if (*rx_packet_size <= rx_unprocessed_bytes) {
- eop = *rx_packet_size;
- *rx_packet_size = 0;
- } else {
- eop = rx_unprocessed_bytes;
- *rx_packet_size = *rx_packet_size -
- rx_unprocessed_bytes;
- }
-
- /* no more bytes available to process */
- if (!eop)
- break;
- /*
- * end of packet is starting from
- * the current position
- */
- eop = eop + i;
- TEST_DBG(TEST_MODULE_NAME ": size - %u, "
- "packet size - %u eop - %d\n",
- size, *rx_packet_size, eop);
-
- /* validate the data */
- for (; i < eop; i++) {
- if (buf[i] != (test_ch->rx_bytes % 256)) {
- pr_err(TEST_MODULE_NAME ": "
- "Corrupt data. buf:%u, "
- "data:%u\n", buf[i],
- test_ch->rx_bytes % 256);
- ret = -EINVAL;
- goto err;
- }
- rx_unprocessed_bytes--;
- test_ch->rx_bytes++;
- }
-
- /* have more data to be processed */
- if (*rx_packet_size)
- break;
-
- /*
- * A2 sends data in 4 byte alignment,
- * skip the padding
- */
- if (size % 4) {
- i += 4 - (size % 4);
- rx_unprocessed_bytes -= 4 - (size % 4);
- }
- *rx_packet_count = *rx_packet_count + 1;
-
- /* re init the state to process new packet */
- *rx_process_packet_state = RX_PROCESS_PACKET_INIT;
- break;
- default:
- pr_err(TEST_MODULE_NAME ": Invalid case: %d\n",
- *rx_process_packet_state);
- ret = -EINVAL;
- goto err;
- }
- TEST_DBG(TEST_MODULE_NAME ": Continue processing "
- "if more data is available\n");
- }
-
-err:
- return ret;
-}
-
-/**
- * A2 Validation Test
- * Send packets and validate the returned packets.
- * Transmit one packet at a time, while process multiple rx
- * packets in a single transaction.
- * A transaction is of size min(random number, write_avail).
- * A packet consists of a min of 1 byte to channel supported max.
- */
-static void a2_validation_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
- int tx_packet_count = 0;
- int rx_packet_count = 0;
- int initial_rx_packet_count = 0;
- u32 size = 0;
- u8 *buf8 = (u8 *)test_ch->buf;
- int i = 0;
- int max_packets = test_ch->config_msg.num_packets;
- u16 tx_packet_size = 0;
- u16 rx_packet_size = 0;
- u32 random_num = 0;
- int rx_process_packet_state = RX_PROCESS_PACKET_INIT;
-
- pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST START for chan %s\n",
- test_ch->name);
-
- /* Wait for the initial rx messages before starting the test. */
- rx_cleanup(test_ch, &initial_rx_packet_count);
-
- test_ch->tx_bytes = 0;
- test_ch->rx_bytes = 0;
-
- /* Continue till we have transmitted and received all packets */
- while ((tx_packet_count < max_packets) ||
- (rx_packet_count < max_packets)) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- random_num = get_random_int();
- size = (random_num % test_ch->packet_length) + 1;
- TEST_DBG(TEST_MODULE_NAME ": Random tx packet size =%u", size);
-
- /*
- * wait for data ready event
- * use a func to avoid compiler optimizations
- */
- write_avail = sdio_write_avail(test_ch->ch);
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ": write_avail=%d, "
- "read_avail=%d for chan %s\n",
- write_avail, read_avail, test_ch->name);
-
- if ((write_avail == 0) && (read_avail == 0)) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->any_notify_count));
- atomic_set(&test_ch->any_notify_count, 0);
- }
-
- /* Transmit data */
- write_avail = sdio_write_avail(test_ch->ch);
- if ((tx_packet_count < max_packets) && (write_avail > 0)) {
- tx_packet_size = min(size, write_avail) ;
- TEST_DBG(TEST_MODULE_NAME ": tx size = %u, "
- "write_avail = %u tx_packet# = %d\n",
- tx_packet_size, write_avail,
- tx_packet_count);
- memset(test_ch->buf, 0, test_ch->buf_size);
- /* populate the buffer */
- for (i = 0; i < tx_packet_size; i++) {
- buf8[i] = test_ch->tx_bytes % 256;
- test_ch->tx_bytes++;
- }
-
- ret = sdio_write(test_ch->ch, test_ch->buf,
- tx_packet_size);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":sdio_write err=%d"
- " for chan %s\n",
- -ret, test_ch->name);
- goto exit_err;
- }
- tx_packet_count++;
- }
-
- /* Receive data */
- read_avail = sdio_read_avail(test_ch->ch);
- if (read_avail > 0) {
- TEST_DBG(TEST_MODULE_NAME ": rx size = %u, "
- "rx_packet#=%d.\n",
- read_avail, rx_packet_count);
- memset(test_ch->buf, 0, test_ch->buf_size);
-
- ret = sdio_read(test_ch->ch, test_ch->buf,
- read_avail);
- if (ret) {
- pr_err(TEST_MODULE_NAME ": sdio_read "
- "size %d err=%d for chan %s\n",
- size, -ret, test_ch->name);
- goto exit_err;
- }
-
- /* Process data */
- ret = process_rx_data(test_ch, read_avail,
- &rx_process_packet_state,
- &rx_packet_size,
- &rx_packet_count);
-
- if (ret != 0)
- goto exit_err;
- }
- TEST_DBG(TEST_MODULE_NAME ": Continue loop ...\n");
- }
-
- if (test_ch->tx_bytes != test_ch->rx_bytes) {
- pr_err(TEST_MODULE_NAME ": Total number of bytes "
- "transmitted (%u) does not match the total "
- "number of bytes received (%u).", test_ch->tx_bytes,
- test_ch->rx_bytes);
- goto exit_err;
- }
-
- pr_info(TEST_MODULE_NAME ": A2 VALIDATION TEST END for chan %s.\n",
- test_ch->name);
-
- pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-
-exit_err:
- pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-/**
- * sender No loopback Test
- */
-static void sender_no_loopback_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 write_avail = 0;
- int packet_count = 0;
- int size = 512;
- u16 *buf16 = (u16 *) test_ch->buf;
- int i;
- int max_packet_count = 10000;
- unsigned int random_num = 0;
-
- max_packet_count = test_ch->config_msg.num_packets;
-
- for (i = 0 ; i < size / 2 ; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
- pr_info(TEST_MODULE_NAME
- ":SENDER NO LP TEST START for chan %s\n", test_ch->name);
-
- while (packet_count < max_packet_count) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- random_num = get_random_int();
- size = (random_num % test_ch->packet_length) + 1;
-
- TEST_DBG(TEST_MODULE_NAME ":SENDER WAIT FOR EVENT "
- "for chan %s\n",
- test_ch->name);
-
- /* wait for data ready event */
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->tx_notify_count));
- atomic_dec(&test_ch->tx_notify_count);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":write_avail=%d\n", write_avail);
- if (write_avail < size) {
- pr_info(TEST_MODULE_NAME ":not enough write avail.\n");
- continue;
- }
-
- test_ch->buf[0] = packet_count;
-
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sender sdio_write err=%d.\n",
- -ret);
- goto exit_err;
- }
-
- test_ch->tx_bytes += size;
- packet_count++;
-
- TEST_DBG(TEST_MODULE_NAME
- ":sender total tx bytes = 0x%x , packet#=%d, size=%d"
- " for chan %s\n",
- test_ch->tx_bytes, packet_count, size, test_ch->name);
-
- } /* end of while */
-
- pr_info(TEST_MODULE_NAME
- ":SENDER TEST END: total tx bytes = 0x%x, "
- " for chan %s\n",
- test_ch->tx_bytes, test_ch->name);
-
- test_ch->modem_result_per_chan = wait_for_result_msg(test_ch);
-
- if (test_ch->modem_result_per_chan) {
- pr_info(TEST_MODULE_NAME ": TEST PASS for chan %s.\n",
- test_ch->name);
- test_ch->test_result = TEST_PASSED;
- } else {
- pr_info(TEST_MODULE_NAME ": TEST FAILURE for chan %s.\n",
- test_ch->name);
- test_ch->test_result = TEST_FAILED;
- }
- test_ch->test_completed = 1;
- check_test_completion();
- return;
-
-exit_err:
- pr_info(TEST_MODULE_NAME ": TEST FAIL for chan %s.\n",
- test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-
-/**
- * Modem reset Test
- * The test verifies that it finished sending all the packets
- * while there might be modem reset in the middle
- */
-static void modem_reset_test(struct test_channel *test_ch)
-{
- int ret = 0 ;
- u32 read_avail = 0;
- u32 write_avail = 0;
- int tx_packet_count = 0;
- int rx_packet_count = 0;
- int size = 0;
- u16 *buf16 = (u16 *) test_ch->buf;
- int i;
- int max_packets = 10000;
- u32 packet_size = test_ch->buf_size;
- int is_err = 0;
-
- max_packets = test_ch->config_msg.num_packets;
- packet_size = test_ch->packet_length;
-
- for (i = 0; i < packet_size / 2; i++)
- buf16[i] = (u16) (i & 0xFFFF);
-
- pr_info(TEST_MODULE_NAME ": Modem Reset TEST START for chan %s\n",
- test_ch->name);
-
- while (tx_packet_count < max_packets) {
-
- if (test_ctx->exit_flag) {
- pr_info(TEST_MODULE_NAME ":Exit Test.\n");
- return;
- }
-
- if (test_ch->card_removed) {
- pr_info(TEST_MODULE_NAME ": card removal was detected "
- "for chan %s, tx_total=0x%x\n",
- test_ch->name, test_ch->tx_bytes);
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->card_detected_event));
- atomic_set(&test_ch->card_detected_event, 0);
- pr_info(TEST_MODULE_NAME ": card_detected_event "
- "for chan %s\n", test_ch->name);
- if (test_ch->card_removed)
- continue;
- is_err = 0;
- /* Need to wait for the modem to be ready */
- msleep(5000);
- pr_info(TEST_MODULE_NAME ": sending the config message "
- "for chan %s\n", test_ch->name);
- send_config_msg(test_ch);
- }
-
- /* wait for data ready event */
- /* use a func to avoid compiler optimizations */
- write_avail = sdio_write_avail(test_ch->ch);
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d, "
- "read_avail=%d for chan %s\n",
- test_ch->name, write_avail, read_avail,
- test_ch->name);
- if ((write_avail == 0) && (read_avail == 0)) {
- wait_event(test_ch->wait_q,
- atomic_read(&test_ch->any_notify_count));
- atomic_set(&test_ch->any_notify_count, 0);
- }
- if (atomic_read(&test_ch->card_detected_event)) {
- atomic_set(&test_ch->card_detected_event, 0);
- pr_info(TEST_MODULE_NAME ": card_detected_event "
- "for chan %s, tx_total=0x%x\n",
- test_ch->name, test_ch->tx_bytes);
- if (test_ch->card_removed)
- continue;
- /* Need to wait for the modem to be ready */
- msleep(5000);
- is_err = 0;
- pr_info(TEST_MODULE_NAME ": sending the config message "
- "for chan %s\n", test_ch->name);
- send_config_msg(test_ch);
- }
-
- write_avail = sdio_write_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, write_avail=%d\n",
- test_ch->name, write_avail);
- if (write_avail > 0) {
- size = min(packet_size, write_avail) ;
- pr_debug(TEST_MODULE_NAME ":tx size = %d for chan %s\n",
- size, test_ch->name);
- test_ch->buf[0] = tx_packet_count;
- test_ch->buf[(size/4)-1] = tx_packet_count;
-
- TEST_DBG(TEST_MODULE_NAME ":channel %s, sdio_write, "
- "size=%d\n", test_ch->name, size);
- if (is_err) {
- msleep(100);
- continue;
- }
- ret = sdio_write(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ":sdio_write err=%d"
- " for chan %s\n",
- -ret, test_ch->name);
- is_err = 1;
- msleep(20);
- continue;
- }
- tx_packet_count++;
- test_ch->tx_bytes += size;
- test_ch->config_msg.num_packets--;
- }
-
- read_avail = sdio_read_avail(test_ch->ch);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, read_avail=%d\n",
- test_ch->name, read_avail);
- if (read_avail > 0) {
- size = min(packet_size, read_avail);
- pr_debug(TEST_MODULE_NAME ":rx size = %d.\n", size);
- TEST_DBG(TEST_MODULE_NAME ":channel %s, sdio_read, "
- "size=%d\n", test_ch->name, size);
- if (is_err) {
- msleep(100);
- continue;
- }
- ret = sdio_read(test_ch->ch, test_ch->buf, size);
- if (ret) {
- pr_info(TEST_MODULE_NAME ": sdio_read size %d "
- " err=%d"
- " for chan %s\n",
- size, -ret, test_ch->name);
- is_err = 1;
- msleep(20);
- continue;
- }
- rx_packet_count++;
- test_ch->rx_bytes += size;
- }
-
- TEST_DBG(TEST_MODULE_NAME
- ":total rx bytes = %d , rx_packet#=%d"
- " for chan %s\n",
- test_ch->rx_bytes, rx_packet_count, test_ch->name);
- TEST_DBG(TEST_MODULE_NAME
- ":total tx bytes = %d , tx_packet#=%d"
- " for chan %s\n",
- test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
- udelay(500);
-
- } /* while (tx_packet_count < max_packets ) */
-
- pr_info(TEST_MODULE_NAME ":total rx bytes = 0x%x , rx_packet#=%d for"
- " chan %s.\n",
- test_ch->rx_bytes, rx_packet_count, test_ch->name);
- pr_info(TEST_MODULE_NAME ":total tx bytes = 0x%x , tx_packet#=%d"
- " for chan %s.\n",
- test_ch->tx_bytes, tx_packet_count, test_ch->name);
-
- pr_err(TEST_MODULE_NAME ": Modem Reset TEST END for chan %s.\n",
- test_ch->name);
-
- pr_err(TEST_MODULE_NAME ": TEST PASS for chan %s\n", test_ch->name);
- test_ch->test_completed = 1;
- test_ch->test_result = TEST_PASSED;
- check_test_completion();
- return;
-}
-
-/**
- * Worker thread to handle the tests types
- */
-static void worker(struct work_struct *work)
-{
- struct test_channel *test_ch = NULL;
- struct test_work *test_work = container_of(work,
- struct test_work,
- work);
- int test_type = 0;
-
- test_ch = test_work->test_ch;
-
- if (test_ch == NULL) {
- pr_err(TEST_MODULE_NAME ":NULL test_ch\n");
- return;
- }
-
- test_type = test_ch->test_type;
-
- switch (test_type) {
- case SDIO_TEST_LOOPBACK_HOST:
- loopback_test(test_ch);
- break;
- case SDIO_TEST_LOOPBACK_CLIENT:
- sender_test(test_ch);
- break;
- case SDIO_TEST_PERF:
- a2_performance_test(test_ch);
- break;
- case SDIO_TEST_LPM_CLIENT_WAKER:
- lpm_test(test_ch);
- break;
- case SDIO_TEST_LPM_HOST_WAKER:
- lpm_test_host_waker(test_ch);
- break;
- case SDIO_TEST_HOST_SENDER_NO_LP:
- sender_no_loopback_test(test_ch);
- break;
- case SDIO_TEST_LPM_RANDOM:
- lpm_continuous_rand_test(test_ch);
- break;
- case SDIO_TEST_RTT:
- a2_rtt_test(test_ch);
- break;
- case SDIO_TEST_CLOSE_CHANNEL:
- if (test_ch->ch_id != SDIO_SMEM)
- open_close_test(test_ch);
- break;
- case SDIO_TEST_MODEM_RESET:
- modem_reset_test(test_ch);
- break;
- case SDIO_TEST_A2_VALIDATION:
- a2_validation_test(test_ch);
- break;
- default:
- pr_err(TEST_MODULE_NAME ":Bad Test type = %d.\n",
- (int) test_type);
- }
-}
-
-
-/**
- * Notification Callback
- *
- * Notify the worker
- *
- */
-static void notify(void *priv, unsigned channel_event)
-{
- struct test_channel *test_ch = (struct test_channel *) priv;
-
- pr_debug(TEST_MODULE_NAME ": %s - notify event=%d.\n",
- __func__, channel_event);
-
- if (test_ch->ch == NULL) {
- pr_info(TEST_MODULE_NAME ": %s - notify before ch ready.\n",
- __func__);
- return;
- }
-
- switch (channel_event) {
- case SDIO_EVENT_DATA_READ_AVAIL:
- atomic_inc(&test_ch->rx_notify_count);
- atomic_set(&test_ch->any_notify_count, 1);
- TEST_DBG(TEST_MODULE_NAME ": %s - SDIO_EVENT_DATA_READ_AVAIL, "
- "any_notify_count=%d, rx_notify_count=%d\n",
- __func__,
- atomic_read(&test_ch->any_notify_count),
- atomic_read(&test_ch->rx_notify_count));
- /*
- * when there is pending data on a channel we would like to
- * turn on the bit mask that implies that there is pending
- * data for that channel on that deivce
- */
- if (test_ch->test_device != NULL &&
- test_ch->test_type == SDIO_TEST_LPM_RANDOM) {
- spin_lock_irqsave(&test_ch->test_device->lpm_array_lock,
- test_ch->test_device->
- lpm_array_lock_flags);
- test_ch->test_device->read_avail_mask |=
- test_ch->channel_mask_id;
- test_ch->notify_counter_per_chan++;
-
- lpm_test_update_entry(test_ch, LPM_NOTIFY, "NOTIFY", 0);
- spin_unlock_irqrestore(&test_ch->test_device->
- lpm_array_lock,
- test_ch->test_device->
- lpm_array_lock_flags);
- }
- break;
-
- case SDIO_EVENT_DATA_WRITE_AVAIL:
- atomic_inc(&test_ch->tx_notify_count);
- atomic_set(&test_ch->any_notify_count, 1);
- TEST_DBG(TEST_MODULE_NAME ": %s - SDIO_EVENT_DATA_WRITE_AVAIL, "
- "any_notify_count=%d, tx_notify_count=%d\n",
- __func__,
- atomic_read(&test_ch->any_notify_count),
- atomic_read(&test_ch->tx_notify_count));
- break;
-
- default:
- BUG();
- }
- wake_up(&test_ch->wait_q);
-
-}
-
-#ifdef CONFIG_MSM_SDIO_SMEM
-static int sdio_smem_test_cb(int event)
-{
- struct test_channel *tch = test_ctx->test_ch_arr[SDIO_SMEM];
- int i;
- int *smem_buf = (int *)test_ctx->smem_buf;
- uint32_t val = 0;
- int ret = 0;
-
- pr_debug(TEST_MODULE_NAME ":%s: Received event %d\n", __func__, event);
-
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s NULL tch\n", __func__);
- return -EINVAL;
- }
-
- switch (event) {
- case SDIO_SMEM_EVENT_READ_DONE:
- tch->rx_bytes += SMEM_MAX_XFER_SIZE;
- for (i = 0; i < SMEM_MAX_XFER_SIZE;) {
- val = (int)*smem_buf;
- if ((val != test_ctx->smem_counter) && tch->is_used) {
- pr_err(TEST_MODULE_NAME ":%s: Invalid value %d "
- "expected %d in smem arr",
- __func__, val, test_ctx->smem_counter);
- pr_err(TEST_MODULE_NAME ":SMEM test FAILED\n");
- tch->test_completed = 1;
- tch->test_result = TEST_FAILED;
- check_test_completion();
- ret = -EINVAL;
- goto exit;
- }
- i += 4;
- smem_buf++;
- test_ctx->smem_counter++;
- }
- if (tch->rx_bytes >= 40000000) {
- if ((!tch->test_completed) && tch->is_used) {
- pr_info(TEST_MODULE_NAME ":SMEM test PASSED\n");
- tch->test_completed = 1;
- tch->test_result = TEST_PASSED;
- check_test_completion();
- }
- }
- break;
- case SDIO_SMEM_EVENT_READ_ERR:
- if (tch->is_used) {
- pr_err(TEST_MODULE_NAME ":Read overflow, "
- "SMEM test FAILED\n");
- tch->test_completed = 1;
- tch->test_result = TEST_FAILED;
- ret = -EIO;
- }
- break;
- default:
- if (tch->is_used) {
- pr_err(TEST_MODULE_NAME ":Unhandled event %d\n", event);
- ret = -EINVAL;
- }
- break;
- }
-exit:
- return ret;
-}
-
-static int sdio_smem_open(struct sdio_smem_client *sdio_smem)
-{
- int ret = 0;
-
- if (!sdio_smem) {
- pr_info(TEST_MODULE_NAME "%s: NULL sdio_smem_client\n",
- __func__);
- return -EINVAL;
- }
-
- if (test_ctx->test_ch_arr[SDIO_SMEM]->ch_ready) {
- pr_info(TEST_MODULE_NAME "%s: SDIO_SMEM channel is already opened\n",
- __func__);
- return 0;
- }
-
- test_ctx->test_ch_arr[SDIO_SMEM]->ch_ready = 1;
- sdio_smem->buf = test_ctx->smem_buf;
- sdio_smem->size = SMEM_MAX_XFER_SIZE;
- sdio_smem->cb_func = sdio_smem_test_cb;
- ret = sdio_smem_register_client();
- if (ret)
- pr_info(TEST_MODULE_NAME "%s: Error (%d) registering sdio_smem "
- "test client\n",
- __func__, ret);
-
- return ret;
-}
-
-static int sdio_smem_test_probe(struct platform_device *pdev)
-{
- test_ctx->sdio_smem = container_of(pdev, struct sdio_smem_client,
- plat_dev);
-
- return sdio_smem_open(test_ctx->sdio_smem);
-}
-
-static struct platform_driver sdio_smem_client_drv = {
- .probe = sdio_smem_test_probe,
- .driver = {
- .name = "SDIO_SMEM_CLIENT",
- .owner = THIS_MODULE,
- },
-};
-#endif
-
-static void sdio_test_lpm_timeout_handler(unsigned long data)
-{
- struct test_channel *tch = (struct test_channel *)data;
-
- pr_info(TEST_MODULE_NAME ": %s - LPM TEST TIMEOUT Expired after "
- "%d ms\n", __func__, tch->timeout_ms);
- tch->test_completed = 1;
- pr_info(TEST_MODULE_NAME ": %s - tch->test_result = TEST_FAILED\n",
- __func__);
- tch->test_completed = 1;
- tch->test_result = TEST_FAILED;
- check_test_completion();
- return;
-}
-
-static void sdio_test_lpm_timer_handler(unsigned long data)
-{
- struct test_channel *tch = (struct test_channel *)data;
-
- pr_info(TEST_MODULE_NAME ": %s - LPM TEST Timer Expired after "
- "%d ms\n", __func__, tch->timer_interval_ms);
-
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s - LPM TEST FAILED. "
- "tch is NULL\n", __func__);
- return;
- }
-
- if (!tch->ch) {
- pr_err(TEST_MODULE_NAME ": %s - LPM TEST FAILED. tch->ch "
- "is NULL\n", __func__);
- tch->test_result = TEST_FAILED;
- return;
- }
-
- /* Verfiy that we voted for sleep */
- if (tch->is_ok_to_sleep) {
- tch->test_result = TEST_PASSED;
- pr_info(TEST_MODULE_NAME ": %s - 8K voted for sleep\n",
- __func__);
- } else {
- tch->test_result = TEST_FAILED;
- pr_info(TEST_MODULE_NAME ": %s - 8K voted against sleep\n",
- __func__);
-
- }
-
- sdio_al_unregister_lpm_cb(tch->sdio_al_device);
-
- if (tch->test_type == SDIO_TEST_LPM_HOST_WAKER) {
- atomic_set(&tch->wakeup_client, 1);
- wake_up(&tch->wait_q);
- }
-}
-
-int sdio_test_wakeup_callback(void *device_handle, int is_vote_for_sleep)
-{
- int i = 0;
-
- TEST_DBG(TEST_MODULE_NAME ": %s is_vote_for_sleep=%d!!!",
- __func__, is_vote_for_sleep);
-
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
- continue;
- if (tch->sdio_al_device == device_handle) {
- tch->is_ok_to_sleep = is_vote_for_sleep;
-
- if (tch->test_type == SDIO_TEST_LPM_RANDOM) {
- spin_lock_irqsave(&tch->test_device->
- lpm_array_lock,
- tch->test_device->
- lpm_array_lock_flags);
- if (is_vote_for_sleep == 1)
- lpm_test_update_entry(tch,
- LPM_SLEEP,
- "SLEEP ", 0);
- else
- lpm_test_update_entry(tch,
- LPM_WAKEUP,
- "WAKEUP", 0);
-
- spin_unlock_irqrestore(&tch->test_device->
- lpm_array_lock,
- tch->test_device->
- lpm_array_lock_flags);
- break;
- }
- }
- }
-
- return 0;
-}
-
-static int sdio_test_find_dev(struct test_channel *tch)
-{
- int j;
- int null_index = -1;
-
- for (j = 0 ; j < MAX_NUM_OF_SDIO_DEVICES; ++j) {
-
- struct sdio_test_device *test_dev =
- &test_ctx->test_dev_arr[j];
-
- if (test_dev->sdio_al_device == NULL) {
- if (null_index == -1)
- null_index = j;
- continue;
- }
-
- if (test_dev->sdio_al_device ==
- tch->ch->sdio_al_dev) {
- test_dev->open_channels_counter_to_recv++;
- test_dev->open_channels_counter_to_send++;
- tch->test_device = test_dev;
- /* setting mask id for pending data for
- this channel */
- tch->channel_mask_id = test_dev->next_mask_id;
- test_dev->next_mask_id *= 2;
- pr_info(TEST_MODULE_NAME ": %s - channel %s "
- "got read_mask_id = 0x%x. device "
- "next_mask_id=0x%x",
- __func__, tch->name, tch->channel_mask_id,
- test_dev->next_mask_id);
- break;
- }
- }
-
- /*
- * happens ones a new device is "discovered" while testing. i.e
- * if testing a few channels, a new deivce will be "discovered" once
- * the first channel of a device is being tested
- */
- if (j == MAX_NUM_OF_SDIO_DEVICES) {
-
- struct sdio_test_device *test_dev =
- &test_ctx->
- test_dev_arr[null_index];
- test_dev->sdio_al_device =
- tch->ch->sdio_al_dev;
-
- test_ctx->number_of_active_devices++;
- test_ctx->max_number_of_devices++;
- test_dev->open_channels_counter_to_recv++;
- test_dev->open_channels_counter_to_send++;
- test_dev->next_avail_entry_in_array = 0;
- tch->test_device = test_dev;
- tch->test_device->array_size =
- LPM_ARRAY_SIZE;
- test_dev->modem_result_per_dev = 1;
- tch->modem_result_per_chan = 0;
- test_dev->next_avail_entry_in_array = 0;
-
- spin_lock_init(&test_dev->
- lpm_array_lock);
-
- if (tch->test_type == SDIO_TEST_LPM_RANDOM) {
- pr_err(MODULE_NAME ": %s - "
- "Allocating Msg Array for "
- "Maximum open channels for device (%d) "
- "Channels. Array has %d entries",
- __func__,
- LPM_MAX_OPEN_CHAN_PER_DEV,
- test_dev->array_size);
-
- test_dev->lpm_arr =
- kzalloc(sizeof(
- struct lpm_entry_type) *
- tch->
- test_device->array_size,
- GFP_KERNEL);
-
- if (!test_dev->lpm_arr) {
- pr_err(MODULE_NAME ": %s - "
- "lpm_arr is NULL",
- __func__);
- return -ENOMEM;
- }
- }
-
- /*
- * in new device, initialize next_mask_id, and setting
- * mask_id to the channel
- */
- test_dev->next_mask_id = 0x1;
- tch->channel_mask_id = test_dev->next_mask_id;
- test_dev->next_mask_id *= 2;
- pr_info(TEST_MODULE_NAME ": %s - channel %s got "
- "read_mask_id = 0x%x. device next_mask_id=0x%x",
- __func__,
- tch->name,
- tch->channel_mask_id,
- test_dev->next_mask_id);
- }
-
- return 0;
-}
-
-static void check_test_result(void)
-{
- int result = 1;
- int i = 0;
-
- test_ctx->max_number_of_devices = 0;
-
- pr_info(TEST_MODULE_NAME ": %s - Woke Up\n", __func__);
-
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
- continue;
-
- if (tch->test_type == SDIO_TEST_LPM_RANDOM)
- result &= tch->test_device->final_result_per_dev;
- else
- if (tch->test_result == TEST_FAILED) {
- pr_info(TEST_MODULE_NAME ": %s - "
- "Test FAILED\n", __func__);
- test_ctx->test_result = TEST_FAILED;
- pr_err(TEST_MODULE_NAME ": %s - "
- "test_result %d",
- __func__, test_ctx->test_result);
- return;
- }
- }
-
- if (result == 0) {
- pr_info(TEST_MODULE_NAME ": %s - Test FAILED\n", __func__);
- test_ctx->test_result = TEST_FAILED;
- pr_err(TEST_MODULE_NAME ": %s - "
- "test_result %d",
- __func__, test_ctx->test_result);
- return;
- }
-
- pr_info(TEST_MODULE_NAME ": %s - Test PASSED", __func__);
- test_ctx->test_result = TEST_PASSED;
- pr_err(TEST_MODULE_NAME ": %s - "
- "test_result %d",
- __func__, test_ctx->test_result);
- return;
-}
-
-/**
- * Test Main
- */
-static int test_start(void)
-{
- int ret = -ENOMEM;
- int i;
-
- pr_debug(TEST_MODULE_NAME ":Starting Test ....\n");
-
- test_ctx->test_completed = 0;
- test_ctx->test_result = TEST_NO_RESULT;
- test_ctx->debug.dun_throughput = 0;
- test_ctx->debug.rmnt_throughput = 0;
- test_ctx->number_of_active_devices = 0;
-
- pr_err(TEST_MODULE_NAME ": %s - test_result %d",
- __func__, test_ctx->test_result);
-
- memset(test_ctx->test_dev_arr, 0,
- sizeof(struct sdio_test_device)*MAX_NUM_OF_SDIO_DEVICES);
-
- /* Open The Channels */
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used))
- continue;
-
- tch->rx_bytes = 0;
- tch->tx_bytes = 0;
-
- atomic_set(&tch->tx_notify_count, 0);
- atomic_set(&tch->rx_notify_count, 0);
- atomic_set(&tch->any_notify_count, 0);
- atomic_set(&tch->wakeup_client, 0);
-
- /* in case there are values left from previous tests */
- tch->notify_counter_per_chan = 0;
- tch->next_index_in_sent_msg_per_chan = 0;
-
- memset(tch->buf, 0x00, tch->buf_size);
- tch->test_result = TEST_NO_RESULT;
-
- tch->test_completed = 0;
-
- ret = open_sdio_ch(tch);
- if (ret)
- continue;
-
- if (tch->ch_id != SDIO_SMEM) {
- ret = sdio_test_find_dev(tch);
-
- if (ret) {
- pr_err(TEST_MODULE_NAME ": %s - "
- "sdio_test_find_dev() returned with "
- "error", __func__);
- return -ENODEV;
- }
-
- tch->sdio_al_device = tch->ch->sdio_al_dev;
- }
-
- if ((tch->test_type == SDIO_TEST_LPM_HOST_WAKER) ||
- (tch->test_type == SDIO_TEST_LPM_CLIENT_WAKER) ||
- (tch->test_type == SDIO_TEST_LPM_RANDOM))
- sdio_al_register_lpm_cb(tch->sdio_al_device,
- sdio_test_wakeup_callback);
- }
-
- /*
- * make some space between opening the channels and sending the
- * config messages
- */
- msleep(100);
-
- /*
- * try to delay send_config_msg of all channels to after the point
- * when we open them all
- */
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used))
- continue;
-
- if ((tch->ch_ready) && (tch->ch_id != SDIO_SMEM))
- send_config_msg(tch);
-
- if ((tch->test_type == SDIO_TEST_LPM_HOST_WAKER) ||
- (tch->test_type == SDIO_TEST_LPM_CLIENT_WAKER) ||
- (tch->test_type == SDIO_TEST_LPM_RANDOM)) {
- if (tch->timer_interval_ms > 0) {
- pr_info(TEST_MODULE_NAME ": %s - init timer, "
- "ms=%d\n",
- __func__, tch->timer_interval_ms);
- init_timer(&tch->timer);
- tch->timer.data = (unsigned long)tch;
- tch->timer.function =
- sdio_test_lpm_timer_handler;
- tch->timer.expires = jiffies +
- msecs_to_jiffies(tch->timer_interval_ms);
- add_timer(&tch->timer);
- }
- }
- }
-
- pr_debug(TEST_MODULE_NAME ":queue_work..\n");
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used) || (!tch->ch_ready))
- continue;
-
- if (tch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
- if (tch->test_type == SDIO_TEST_CLOSE_CHANNEL)
- open_close_smem_test(tch);
-#endif
- } else {
- queue_work(tch->workqueue, &tch->test_work.work);
- }
-
- }
-
- pr_info(TEST_MODULE_NAME ": %s - Waiting for the test completion\n",
- __func__);
-
- wait_event(test_ctx->wait_q, test_ctx->test_completed);
- check_test_result();
-
- /*
- * Close the channels and zero the is_used flag so that if the modem
- * will be reset after the test completion we won't re-open
- * the channels
- */
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
-
- if ((!tch) || (!tch->is_used))
- continue;
- if (!tch->ch_ready) {
- tch->is_used = 0;
- continue;
- }
-
- close_sdio_ch(tch);
- tch->is_used = 0;
- }
-
- if (test_ctx->test_result == TEST_PASSED)
- return 0;
- else
- return -EINVAL;
-}
-
-static int set_params_loopback_9k(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_LOOPBACK_CLIENT;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
- tch->config_msg.num_packets = 10000;
- tch->config_msg.num_iterations = 1;
-
- tch->packet_length = 512;
- if (tch->ch_id == SDIO_RPC)
- tch->packet_length = 128;
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-static int set_params_loopback_9k_close(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_CLOSE_CHANNEL;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
- tch->config_msg.num_packets = 5000;
- tch->config_msg.num_iterations = 1;
- tch->max_burst_size = 10;
- switch (tch->ch_id) {
- case SDIO_DUN:
- case SDIO_RPC:
- tch->packet_length = 128; /* max is 2K*/
- break;
- case SDIO_DIAG:
- case SDIO_RMNT:
- default:
- tch->packet_length = 512; /* max is 4k */
- }
- tch->timer_interval_ms = 0;
- return 0;
-}
-static int set_params_a2_perf(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_PERF;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-
- switch (tch->ch_id) {
- case SDIO_DIAG:
- tch->packet_length = 512;
- break;
- case SDIO_DUN:
- tch->packet_length = DUN_PACKET_SIZE;
- break;
- case SDIO_CSVT:
- tch->packet_length = CSVT_PACKET_SIZE;
- break;
- default:
- tch->packet_length = MAX_XFER_SIZE;
- break;
- }
-
- pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__,
- tch->packet_length);
-
- tch->config_msg.num_packets = 10000;
- tch->config_msg.num_iterations = 1;
- tch->random_packet_size = 0;
-
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_rtt(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_RTT;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-
- switch (tch->ch_id) {
- case SDIO_RMNT:
- tch->packet_length = SDIO_RMNT_RTT_PACKET_SIZE;
- break;
- case SDIO_CSVT:
- tch->packet_length = SDIO_CSVT_RTT_PACKET_SIZE;
- break;
- default:
- pr_err(TEST_MODULE_NAME ": %s - ch_id invalid.\n", __func__);
- return -EINVAL;
- }
-
- pr_info(TEST_MODULE_NAME ": %s: packet_length=%d", __func__,
- tch->packet_length);
-
- tch->config_msg.num_packets = 200;
- tch->config_msg.num_iterations = 1;
- tch->random_packet_size = 0;
-
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_a2_small_pkts(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_PERF;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
- tch->packet_length = 128;
-
- tch->config_msg.num_packets = 1000000;
- tch->config_msg.num_iterations = 1;
- tch->random_packet_size = 1;
-
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_modem_reset(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_MODEM_RESET;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
- tch->packet_length = 512;
- if (tch->ch_id == SDIO_RPC)
- tch->packet_length = 128;
- else if ((tch->ch_id == SDIO_RMNT) || (tch->ch_id == SDIO_DUN))
- tch->packet_length = MAX_XFER_SIZE;
-
- tch->config_msg.num_packets = 50000;
- tch->config_msg.num_iterations = 1;
-
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_a2_validation(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_A2_VALIDATION;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_LOOPBACK_CLIENT;
-
- if (tch->ch_id == SDIO_RMNT)
- tch->packet_length = RMNT_PACKET_SIZE;
- else if (tch->ch_id == SDIO_DUN)
- tch->packet_length = DUN_PACKET_SIZE;
- else
- tch->packet_length = MAX_XFER_SIZE;
-
- tch->config_msg.num_packets = 10000;
- tch->config_msg.num_iterations = 1;
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_smem_test(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static int set_params_lpm_test(struct test_channel *tch,
- enum sdio_test_case_type test,
- int timer_interval_ms)
-{
- static int first_time = 1;
- if (!tch) {
- pr_err(TEST_MODULE_NAME ": %s - NULL channel\n", __func__);
- return -EINVAL;
- }
-
- tch->is_used = 1;
- tch->test_type = test;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = test;
- tch->config_msg.num_packets = LPM_TEST_NUM_OF_PACKETS;
- tch->config_msg.num_iterations = 1;
- tch->timer_interval_ms = timer_interval_ms;
- tch->timeout_ms = 10000;
-
- tch->packet_length = 0;
- if (test != SDIO_TEST_LPM_RANDOM) {
- init_timer(&tch->timeout_timer);
- tch->timeout_timer.data = (unsigned long)tch;
- tch->timeout_timer.function = sdio_test_lpm_timeout_handler;
- tch->timeout_timer.expires = jiffies +
- msecs_to_jiffies(tch->timeout_ms);
- add_timer(&tch->timeout_timer);
- pr_info(TEST_MODULE_NAME ": %s - Initiated LPM TIMEOUT TIMER."
- "set to %d ms\n",
- __func__, tch->timeout_ms);
- }
-
- if (first_time) {
- pr_info(TEST_MODULE_NAME ": %s - wake_lock_init() called\n",
- __func__);
- wake_lock_init(&test_ctx->wake_lock,
- WAKE_LOCK_SUSPEND, TEST_MODULE_NAME);
- first_time = 0;
- }
-
- pr_info(TEST_MODULE_NAME ": %s - wake_lock() for the TEST is "
- "called channel %s. to prevent real sleeping\n",
- __func__, tch->name);
- wake_lock(&test_ctx->wake_lock);
-
- return 0;
-}
-
-static int set_params_8k_sender_no_lp(struct test_channel *tch)
-{
- if (!tch) {
- pr_err(TEST_MODULE_NAME ":NULL channel\n");
- return -EINVAL;
- }
- tch->is_used = 1;
- tch->test_type = SDIO_TEST_HOST_SENDER_NO_LP;
- tch->config_msg.signature = TEST_CONFIG_SIGNATURE;
- tch->config_msg.test_case = SDIO_TEST_HOST_SENDER_NO_LP;
- tch->config_msg.num_packets = 1000;
- tch->config_msg.num_iterations = 1;
-
- tch->packet_length = 512;
- if (tch->ch_id == SDIO_RPC)
- tch->packet_length = 128;
- tch->timer_interval_ms = 0;
-
- return 0;
-}
-
-static void set_pseudo_random_seed(void)
-{
- /* Set the seed accoring to the kernel command parameters if any or
- get a random value */
- if (seed != 0) {
- test_ctx->lpm_pseudo_random_seed = seed;
- } else {
- test_ctx->lpm_pseudo_random_seed =
- (unsigned int)(get_jiffies_64() & 0xFFFF);
- test_ctx->lpm_pseudo_random_seed =
- pseudo_random_seed(&test_ctx->lpm_pseudo_random_seed);
- }
-
- pr_info(TEST_MODULE_NAME ":%s: seed is %u",
- __func__, test_ctx->lpm_pseudo_random_seed);
-}
-
-/*
- for each channel
- 1. open channel
- 2. close channel
-*/
-static int close_channel_lpm_test(int channel_num)
-{
- int ret = 0;
- struct test_channel *tch = NULL;
- tch = test_ctx->test_ch_arr[channel_num];
-
- if (!tch) {
- pr_info(TEST_MODULE_NAME ":%s ch#%d is NULL\n",
- __func__, channel_num);
- return 0;
- }
-
- ret = open_sdio_ch(tch);
- if (ret) {
- pr_err(TEST_MODULE_NAME":%s open channel %s"
- " failed\n", __func__, tch->name);
- return ret;
- } else {
- pr_info(TEST_MODULE_NAME":%s open channel %s"
- " success\n", __func__, tch->name);
- }
- ret = close_sdio_ch(tch);
- if (ret) {
- pr_err(TEST_MODULE_NAME":%s close channel %s"
- " failed\n", __func__, tch->name);
- return ret;
- } else {
- pr_info(TEST_MODULE_NAME":%s close channel %s"
- " success\n", __func__, tch->name);
- }
-
- tch->is_used = 0;
-
- return ret;
-}
-
-/**
- * Write File.
- *
- * @note Trigger the test from user space by:
- * echo 1 > /dev/sdio_al_test
- *
- */
-ssize_t test_write(struct file *filp, const char __user *buf, size_t size,
- loff_t *f_pos)
-{
- sdio_al_test_initial_dev_and_chan(test_ctx);
-
- if (strict_strtol(buf, 10, &test_ctx->testcase))
- return -EINVAL;
-
- switch (test_ctx->testcase) {
- case 98:
- pr_info(TEST_MODULE_NAME " set runtime debug on");
- test_ctx->runtime_debug = 1;
- return size;
- case 99:
- pr_info(TEST_MODULE_NAME " set runtime debug off");
- test_ctx->runtime_debug = 0;
- return size;
- default:
- pr_info(TEST_MODULE_NAME ":Bad Test number = %d.\n",
- (int)test_ctx->testcase);
- return size;
- }
-
- return size;
-}
-
-/**
- * Test Channel Init.
- */
-int test_channel_init(char *name)
-{
- struct test_channel *test_ch;
- int ch_id = 0;
- int ret;
-
- pr_debug(TEST_MODULE_NAME ":%s.\n", __func__);
- pr_info(TEST_MODULE_NAME ": init test channel %s.\n", name);
-
- ch_id = channel_name_to_id(name);
- pr_debug(TEST_MODULE_NAME ":id = %d.\n", ch_id);
- if (test_ctx->test_ch_arr[ch_id] == NULL) {
- test_ch = kzalloc(sizeof(*test_ch), GFP_KERNEL);
- if (test_ch == NULL) {
- pr_err(TEST_MODULE_NAME ":kzalloc err for allocating "
- "test_ch %s.\n",
- name);
- return -ENOMEM;
- }
- test_ctx->test_ch_arr[ch_id] = test_ch;
-
- test_ch->ch_id = ch_id;
-
- strncpy(test_ch->name, name,
- strnlen(name, TEST_CH_NAME_SIZE)-SDIO_TEST_POSTFIX_SIZE);
-
- test_ch->buf_size = MAX_XFER_SIZE;
-
- test_ch->buf = kzalloc(test_ch->buf_size, GFP_KERNEL);
- if (test_ch->buf == NULL) {
- kfree(test_ch);
- test_ctx->test_ch = NULL;
- return -ENOMEM;
- }
-
- if (test_ch->ch_id == SDIO_SMEM) {
- test_ctx->smem_buf = kzalloc(SMEM_MAX_XFER_SIZE,
- GFP_KERNEL);
- if (test_ctx->smem_buf == NULL) {
- pr_err(TEST_MODULE_NAME ":%s: Unable to "
- "allocate smem buf\n",
- __func__);
- kfree(test_ch);
- test_ctx->test_ch = NULL;
- return -ENOMEM;
- }
-
-#ifdef CONFIG_MSM_SDIO_SMEM
- ret = platform_driver_register(&sdio_smem_client_drv);
- if (ret) {
- pr_err(TEST_MODULE_NAME ":%s: Unable to "
- "register sdio smem "
- "test client\n",
- __func__);
- return ret;
- }
-#endif
- } else {
- test_ch->workqueue =
- create_singlethread_workqueue(test_ch->name);
- test_ch->test_work.test_ch = test_ch;
- INIT_WORK(&test_ch->test_work.work, worker);
-
- init_waitqueue_head(&test_ch->wait_q);
- }
- } else {
- test_ch = test_ctx->test_ch_arr[ch_id];
- pr_info(TEST_MODULE_NAME ":%s: ch %s was detected again\n",
- __func__, test_ch->name);
- test_ch->card_removed = 0;
- if ((test_ch->is_used) &&
- (test_ch->test_type == SDIO_TEST_MODEM_RESET)) {
- if (test_ch->ch_id == SDIO_SMEM) {
-#ifdef CONFIG_MSM_SDIO_SMEM
- ret = add_sdio_smem();
- if (ret) {
- test_ch->ch_ready = false;
- return 0;
- }
-#endif
- } else {
- ret = open_sdio_ch(test_ch);
- if (ret) {
- pr_info(TEST_MODULE_NAME
- ":%s: open channel %s failed\n",
- __func__, test_ch->name);
- return 0;
- }
- ret = sdio_test_find_dev(test_ch);
-
- if (ret) {
- pr_err(TEST_MODULE_NAME ": %s - "
- "sdio_test_find_dev() returned "
- "with error", __func__);
- return -ENODEV;
- }
-
- test_ch->sdio_al_device =
- test_ch->ch->sdio_al_dev;
- }
- atomic_set(&test_ch->card_detected_event, 1);
- wake_up(&test_ch->wait_q);
- }
- }
-
- return 0;
-}
-
-static int sdio_test_channel_probe(struct platform_device *pdev)
-{
- if (!pdev)
- return -EIO;
- return test_channel_init((char *)pdev->name);
-}
-
-static int sdio_test_channel_remove(struct platform_device *pdev)
-{
- int ch_id;
-
- if (!pdev)
- return -EIO;
-
- ch_id = channel_name_to_id((char *)pdev->name);
- if (test_ctx->test_ch_arr[ch_id] == NULL)
- return 0;
-
- pr_info(TEST_MODULE_NAME "%s: remove ch %s\n",
- __func__, test_ctx->test_ch_arr[ch_id]->name);
-
- if ((ch_id == SDIO_SMEM) && (test_ctx->smem_pdev)) {
- platform_device_unregister(test_ctx->smem_pdev);
- test_ctx->smem_pdev = NULL;
- }
-
- test_ctx->test_ch_arr[ch_id]->ch_ready = 0;
- test_ctx->test_ch_arr[ch_id]->card_removed = 1;
-
- return 0;
-
-}
-
-static int sdio_test_channel_csvt_probe(struct platform_device *pdev)
-{
- int ret = 0;
-
- if (!pdev)
- return -ENODEV;
-
- test_ctx->csvt_app_pdev = platform_device_alloc("SDIO_CSVT_TEST_APP",
- -1);
- ret = platform_device_add(test_ctx->csvt_app_pdev);
- if (ret) {
- pr_err(MODULE_NAME ":platform_device_add failed, "
- "ret=%d\n", ret);
- return ret;
- }
-
- return sdio_test_channel_probe(pdev);
-}
-
-static int sdio_test_channel_csvt_remove(struct platform_device *pdev)
-{
- if (!pdev)
- return -ENODEV;
-
- platform_device_unregister(test_ctx->csvt_app_pdev);
-
- return sdio_test_channel_remove(pdev);
-}
-
-static struct platform_driver sdio_rpc_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_RPC_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_qmi_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_QMI_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_diag_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_DIAG_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_smem_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_SMEM_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_rmnt_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_RMNT_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_dun_drv = {
- .probe = sdio_test_channel_probe,
- .remove = sdio_test_channel_remove,
- .driver = {
- .name = "SDIO_DUN_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct platform_driver sdio_csvt_drv = {
- .probe = sdio_test_channel_csvt_probe,
- .remove = sdio_test_channel_csvt_remove,
- .driver = {
- .name = "SDIO_CSVT_TEST",
- .owner = THIS_MODULE,
- },
-};
-
-static struct class *test_class;
-
-const struct file_operations test_fops = {
- .owner = THIS_MODULE,
- .write = test_write,
-};
-
-/**
- * Module Init.
- */
-static int __init test_init(void)
-{
- int ret;
-
- pr_debug(TEST_MODULE_NAME ":test_init.\n");
-
- test_ctx = kzalloc(sizeof(struct test_context), GFP_KERNEL);
-
- if (test_ctx == NULL) {
- pr_err(TEST_MODULE_NAME ":kzalloc err.\n");
- return -ENOMEM;
- }
- test_ctx->test_ch = NULL;
- test_ctx->signature = TEST_SIGNATURE;
-
- test_ctx->name = "UNKNOWN";
-
- init_waitqueue_head(&test_ctx->wait_q);
-
-#ifdef CONFIG_DEBUG_FS
- sdio_al_test_debugfs_init();
-#endif
-
- test_class = class_create(THIS_MODULE, TEST_MODULE_NAME);
-
- ret = alloc_chrdev_region(&test_ctx->dev_num, 0, 1, TEST_MODULE_NAME);
- if (ret) {
- pr_err(TEST_MODULE_NAME "alloc_chrdev_region err.\n");
- return -ENODEV;
- }
-
- test_ctx->dev = device_create(test_class, NULL, test_ctx->dev_num,
- test_ctx, TEST_MODULE_NAME);
- if (IS_ERR(test_ctx->dev)) {
- pr_err(TEST_MODULE_NAME ":device_create err.\n");
- return -ENODEV;
- }
-
- test_ctx->cdev = cdev_alloc();
- if (test_ctx->cdev == NULL) {
- pr_err(TEST_MODULE_NAME ":cdev_alloc err.\n");
- return -ENODEV;
- }
- cdev_init(test_ctx->cdev, &test_fops);
- test_ctx->cdev->owner = THIS_MODULE;
-
- ret = cdev_add(test_ctx->cdev, test_ctx->dev_num, 1);
- if (ret)
- pr_err(TEST_MODULE_NAME ":cdev_add err=%d\n", -ret);
- else
- pr_debug(TEST_MODULE_NAME ":SDIO-AL-Test init OK..\n");
-
- platform_driver_register(&sdio_rpc_drv);
- platform_driver_register(&sdio_qmi_drv);
- platform_driver_register(&sdio_diag_drv);
- platform_driver_register(&sdio_smem_drv);
- platform_driver_register(&sdio_rmnt_drv);
- platform_driver_register(&sdio_dun_drv);
- platform_driver_register(&sdio_csvt_drv);
-
- return ret;
-}
-
-/**
- * Module Exit.
- */
-static void __exit test_exit(void)
-{
- int i;
-
- pr_debug(TEST_MODULE_NAME ":test_exit.\n");
-
- test_ctx->exit_flag = true;
-
- msleep(100); /* allow gracefully exit of the worker thread */
-
- cdev_del(test_ctx->cdev);
- device_destroy(test_class, test_ctx->dev_num);
- unregister_chrdev_region(test_ctx->dev_num, 1);
-
- platform_driver_unregister(&sdio_rpc_drv);
- platform_driver_unregister(&sdio_qmi_drv);
- platform_driver_unregister(&sdio_diag_drv);
- platform_driver_unregister(&sdio_smem_drv);
- platform_driver_unregister(&sdio_rmnt_drv);
- platform_driver_unregister(&sdio_dun_drv);
- platform_driver_unregister(&sdio_csvt_drv);
-
- for (i = 0; i < SDIO_MAX_CHANNELS; i++) {
- struct test_channel *tch = test_ctx->test_ch_arr[i];
- if (!tch)
- continue;
- kfree(tch->buf);
- kfree(tch);
- }
-
-#ifdef CONFIG_DEBUG_FS
- sdio_al_test_debugfs_cleanup();
-#endif
-
- kfree(test_ctx);
-
- pr_debug(TEST_MODULE_NAME ":test_exit complete.\n");
-}
-
-module_init(test_init);
-module_exit(test_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SDIO_AL Test");
-MODULE_AUTHOR("Amir Samuelov <amirs@codeaurora.org>");
-
-
diff --git a/arch/arm/mach-msm/sdio_cmux.c b/arch/arm/mach-msm/sdio_cmux.c
deleted file mode 100644
index 70935b2..0000000
--- a/arch/arm/mach-msm/sdio_cmux.c
+++ /dev/null
@@ -1,885 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#define DEBUG
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/termios.h>
-#include <linux/debugfs.h>
-#include <linux/moduleparam.h>
-
-#include <mach/sdio_al.h>
-#include <mach/sdio_cmux.h>
-
-#include "modem_notifier.h"
-
-#define MAX_WRITE_RETRY 5
-#define MAGIC_NO_V1 0x33FC
-
-static int msm_sdio_cmux_debug_mask;
-module_param_named(debug_mask, msm_sdio_cmux_debug_mask,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-enum cmd_type {
- DATA = 0,
- OPEN,
- CLOSE,
- STATUS,
- NUM_CMDS
-};
-
-#define DSR_POS 0x1
-#define CTS_POS 0x2
-#define RI_POS 0x4
-#define CD_POS 0x8
-
-struct sdio_cmux_ch {
- int lc_id;
-
- struct mutex lc_lock;
- wait_queue_head_t open_wait_queue;
- int is_remote_open;
- int is_local_open;
- int is_channel_reset;
-
- char local_status;
- char remote_status;
-
- struct mutex tx_lock;
- struct list_head tx_list;
-
- void *priv;
- void (*receive_cb)(void *, int, void *);
- void (*write_done)(void *, int, void *);
- void (*status_callback)(int, void *);
-} logical_ch[SDIO_CMUX_NUM_CHANNELS];
-
-struct sdio_cmux_hdr {
- uint16_t magic_no;
- uint8_t status; /* This field is reserved for commands other
- * than STATUS */
- uint8_t cmd;
- uint8_t pad_bytes;
- uint8_t lc_id;
- uint16_t pkt_len;
-};
-
-struct sdio_cmux_pkt {
- struct sdio_cmux_hdr *hdr;
- void *data;
-};
-
-struct sdio_cmux_list_elem {
- struct list_head list;
- struct sdio_cmux_pkt cmux_pkt;
-};
-
-#define logical_ch_is_local_open(x) \
- (logical_ch[(x)].is_local_open)
-
-#define logical_ch_is_remote_open(x) \
- (logical_ch[(x)].is_remote_open)
-
-static void sdio_cdemux_fn(struct work_struct *work);
-static DECLARE_WORK(sdio_cdemux_work, sdio_cdemux_fn);
-static struct workqueue_struct *sdio_cdemux_wq;
-
-static DEFINE_MUTEX(write_lock);
-static uint32_t bytes_to_write;
-static DEFINE_MUTEX(temp_rx_lock);
-static LIST_HEAD(temp_rx_list);
-
-static void sdio_cmux_fn(struct work_struct *work);
-static DECLARE_WORK(sdio_cmux_work, sdio_cmux_fn);
-static struct workqueue_struct *sdio_cmux_wq;
-
-static struct sdio_channel *sdio_qmi_chl;
-static uint32_t sdio_cmux_inited;
-
-static uint32_t abort_tx;
-static DEFINE_MUTEX(modem_reset_lock);
-
-static DEFINE_MUTEX(probe_lock);
-
-enum {
- MSM_SDIO_CMUX_DEBUG = 1U << 0,
- MSM_SDIO_CMUX_DUMP_BUFFER = 1U << 1,
-};
-
-static struct platform_device sdio_ctl_dev = {
- .name = "SDIO_CTL",
- .id = -1,
-};
-
-#if defined(DEBUG)
-#define D_DUMP_BUFFER(prestr, cnt, buf) \
-do { \
- if (msm_sdio_cmux_debug_mask & MSM_SDIO_CMUX_DUMP_BUFFER) { \
- int i; \
- pr_debug("%s", prestr); \
- for (i = 0; i < cnt; i++) \
- pr_info("%.2x", buf[i]); \
- pr_debug("\n"); \
- } \
-} while (0)
-
-#define D(x...) \
-do { \
- if (msm_sdio_cmux_debug_mask & MSM_SDIO_CMUX_DEBUG) \
- pr_debug(x); \
-} while (0)
-
-#else
-#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#define D(x...) do {} while (0)
-#endif
-
-static int sdio_cmux_ch_alloc(int id)
-{
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid lc_id - %d\n", __func__, id);
- return -EINVAL;
- }
-
- logical_ch[id].lc_id = id;
- mutex_init(&logical_ch[id].lc_lock);
- init_waitqueue_head(&logical_ch[id].open_wait_queue);
- logical_ch[id].is_remote_open = 0;
- logical_ch[id].is_local_open = 0;
- logical_ch[id].is_channel_reset = 0;
-
- INIT_LIST_HEAD(&logical_ch[id].tx_list);
- mutex_init(&logical_ch[id].tx_lock);
-
- logical_ch[id].priv = NULL;
- logical_ch[id].receive_cb = NULL;
- logical_ch[id].write_done = NULL;
- return 0;
-}
-
-static int sdio_cmux_ch_clear_and_signal(int id)
-{
- struct sdio_cmux_list_elem *list_elem;
-
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid lc_id - %d\n", __func__, id);
- return -EINVAL;
- }
-
- mutex_lock(&logical_ch[id].lc_lock);
- logical_ch[id].is_remote_open = 0;
- mutex_lock(&logical_ch[id].tx_lock);
- while (!list_empty(&logical_ch[id].tx_list)) {
- list_elem = list_first_entry(&logical_ch[id].tx_list,
- struct sdio_cmux_list_elem,
- list);
- list_del(&list_elem->list);
- kfree(list_elem->cmux_pkt.hdr);
- kfree(list_elem);
- }
- mutex_unlock(&logical_ch[id].tx_lock);
- if (logical_ch[id].receive_cb)
- logical_ch[id].receive_cb(NULL, 0, logical_ch[id].priv);
- if (logical_ch[id].write_done)
- logical_ch[id].write_done(NULL, 0, logical_ch[id].priv);
- mutex_unlock(&logical_ch[id].lc_lock);
- wake_up(&logical_ch[id].open_wait_queue);
- return 0;
-}
-
-static int sdio_cmux_write_cmd(const int id, enum cmd_type type)
-{
- int write_size = 0;
- void *write_data = NULL;
- struct sdio_cmux_list_elem *list_elem;
-
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid lc_id - %d\n", __func__, id);
- return -EINVAL;
- }
-
- if (type < 0 || type > NUM_CMDS) {
- pr_err("%s: Invalid cmd - %d\n", __func__, type);
- return -EINVAL;
- }
-
- write_size = sizeof(struct sdio_cmux_hdr);
- list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
- if (!list_elem) {
- pr_err("%s: list_elem alloc failed\n", __func__);
- return -ENOMEM;
- }
-
- write_data = kmalloc(write_size, GFP_KERNEL);
- if (!write_data) {
- pr_err("%s: write_data alloc failed\n", __func__);
- kfree(list_elem);
- return -ENOMEM;
- }
-
- list_elem->cmux_pkt.hdr = (struct sdio_cmux_hdr *)write_data;
- list_elem->cmux_pkt.data = NULL;
-
- list_elem->cmux_pkt.hdr->lc_id = (uint8_t)id;
- list_elem->cmux_pkt.hdr->pkt_len = (uint16_t)0;
- list_elem->cmux_pkt.hdr->cmd = (uint8_t)type;
- list_elem->cmux_pkt.hdr->status = (uint8_t)0;
- if (type == STATUS)
- list_elem->cmux_pkt.hdr->status = logical_ch[id].local_status;
- list_elem->cmux_pkt.hdr->pad_bytes = (uint8_t)0;
- list_elem->cmux_pkt.hdr->magic_no = (uint16_t)MAGIC_NO_V1;
-
- mutex_lock(&logical_ch[id].tx_lock);
- list_add_tail(&list_elem->list, &logical_ch[id].tx_list);
- mutex_unlock(&logical_ch[id].tx_lock);
-
- mutex_lock(&write_lock);
- bytes_to_write += write_size;
- mutex_unlock(&write_lock);
- queue_work(sdio_cmux_wq, &sdio_cmux_work);
-
- return 0;
-}
-
-int sdio_cmux_open(const int id,
- void (*receive_cb)(void *, int, void *),
- void (*write_done)(void *, int, void *),
- void (*status_callback)(int, void *),
- void *priv)
-{
- int r;
- struct sdio_cmux_list_elem *list_elem, *list_elem_tmp;
-
- if (!sdio_cmux_inited)
- return -ENODEV;
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid id - %d\n", __func__, id);
- return -EINVAL;
- }
-
- r = wait_event_timeout(logical_ch[id].open_wait_queue,
- logical_ch[id].is_remote_open, (1 * HZ));
- if (r < 0) {
- pr_err("ERROR %s: wait_event_timeout() failed for"
- " ch%d with rc %d\n", __func__, id, r);
- return r;
- }
- if (r == 0) {
- pr_err("ERROR %s: Wait Timed Out for ch%d\n", __func__, id);
- return -ETIMEDOUT;
- }
-
- mutex_lock(&logical_ch[id].lc_lock);
- if (!logical_ch[id].is_remote_open) {
- pr_err("%s: Remote ch%d not opened\n", __func__, id);
- mutex_unlock(&logical_ch[id].lc_lock);
- return -EINVAL;
- }
- if (logical_ch[id].is_local_open) {
- mutex_unlock(&logical_ch[id].lc_lock);
- return 0;
- }
- logical_ch[id].is_local_open = 1;
- logical_ch[id].priv = priv;
- logical_ch[id].receive_cb = receive_cb;
- logical_ch[id].write_done = write_done;
- logical_ch[id].status_callback = status_callback;
- if (logical_ch[id].receive_cb) {
- mutex_lock(&temp_rx_lock);
- list_for_each_entry_safe(list_elem, list_elem_tmp,
- &temp_rx_list, list) {
- if ((int)list_elem->cmux_pkt.hdr->lc_id == id) {
- logical_ch[id].receive_cb(
- list_elem->cmux_pkt.data,
- (int)list_elem->cmux_pkt.hdr->pkt_len,
- logical_ch[id].priv);
- list_del(&list_elem->list);
- kfree(list_elem->cmux_pkt.hdr);
- kfree(list_elem);
- }
- }
- mutex_unlock(&temp_rx_lock);
- }
- mutex_unlock(&logical_ch[id].lc_lock);
- sdio_cmux_write_cmd(id, OPEN);
- return 0;
-}
-EXPORT_SYMBOL(sdio_cmux_open);
-
-int sdio_cmux_close(int id)
-{
- struct sdio_cmux_ch *ch;
-
- if (!sdio_cmux_inited)
- return -ENODEV;
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid channel close\n", __func__);
- return -EINVAL;
- }
-
- ch = &logical_ch[id];
- mutex_lock(&ch->lc_lock);
- ch->receive_cb = NULL;
- mutex_lock(&ch->tx_lock);
- ch->write_done = NULL;
- mutex_unlock(&ch->tx_lock);
- ch->is_local_open = 0;
- ch->priv = NULL;
- mutex_unlock(&ch->lc_lock);
- sdio_cmux_write_cmd(ch->lc_id, CLOSE);
- return 0;
-}
-EXPORT_SYMBOL(sdio_cmux_close);
-
-int sdio_cmux_write_avail(int id)
-{
- int write_avail;
-
- mutex_lock(&logical_ch[id].lc_lock);
- if (logical_ch[id].is_channel_reset) {
- mutex_unlock(&logical_ch[id].lc_lock);
- return -ENETRESET;
- }
- mutex_unlock(&logical_ch[id].lc_lock);
- write_avail = sdio_write_avail(sdio_qmi_chl);
- return write_avail - bytes_to_write;
-}
-EXPORT_SYMBOL(sdio_cmux_write_avail);
-
-int sdio_cmux_write(int id, void *data, int len)
-{
- struct sdio_cmux_list_elem *list_elem;
- uint32_t write_size;
- void *write_data = NULL;
- struct sdio_cmux_ch *ch;
- int ret;
-
- if (!sdio_cmux_inited)
- return -ENODEV;
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS) {
- pr_err("%s: Invalid channel id %d\n", __func__, id);
- return -ENODEV;
- }
-
- ch = &logical_ch[id];
- if (len <= 0) {
- pr_err("%s: Invalid len %d bytes to write\n",
- __func__, len);
- return -EINVAL;
- }
-
- write_size = sizeof(struct sdio_cmux_hdr) + len;
- list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
- if (!list_elem) {
- pr_err("%s: list_elem alloc failed\n", __func__);
- return -ENOMEM;
- }
-
- write_data = kmalloc(write_size, GFP_KERNEL);
- if (!write_data) {
- pr_err("%s: write_data alloc failed\n", __func__);
- kfree(list_elem);
- return -ENOMEM;
- }
-
- list_elem->cmux_pkt.hdr = (struct sdio_cmux_hdr *)write_data;
- list_elem->cmux_pkt.data = (void *)((char *)write_data +
- sizeof(struct sdio_cmux_hdr));
- memcpy(list_elem->cmux_pkt.data, data, len);
-
- list_elem->cmux_pkt.hdr->lc_id = (uint8_t)ch->lc_id;
- list_elem->cmux_pkt.hdr->pkt_len = (uint16_t)len;
- list_elem->cmux_pkt.hdr->cmd = (uint8_t)DATA;
- list_elem->cmux_pkt.hdr->status = (uint8_t)0;
- list_elem->cmux_pkt.hdr->pad_bytes = (uint8_t)0;
- list_elem->cmux_pkt.hdr->magic_no = (uint16_t)MAGIC_NO_V1;
-
- mutex_lock(&ch->lc_lock);
- if (!ch->is_remote_open || !ch->is_local_open) {
- pr_err("%s: Local ch%d sending data before sending/receiving"
- " OPEN command\n", __func__, ch->lc_id);
- if (ch->is_channel_reset)
- ret = -ENETRESET;
- else
- ret = -ENODEV;
- mutex_unlock(&ch->lc_lock);
- kfree(write_data);
- kfree(list_elem);
- return ret;
- }
- mutex_lock(&ch->tx_lock);
- list_add_tail(&list_elem->list, &ch->tx_list);
- mutex_unlock(&ch->tx_lock);
- mutex_unlock(&ch->lc_lock);
-
- mutex_lock(&write_lock);
- bytes_to_write += write_size;
- mutex_unlock(&write_lock);
- queue_work(sdio_cmux_wq, &sdio_cmux_work);
-
- return len;
-}
-EXPORT_SYMBOL(sdio_cmux_write);
-
-int is_remote_open(int id)
-{
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS)
- return -ENODEV;
-
- return logical_ch_is_remote_open(id);
-}
-EXPORT_SYMBOL(is_remote_open);
-
-int sdio_cmux_is_channel_reset(int id)
-{
- int ret;
- if (id < 0 || id >= SDIO_CMUX_NUM_CHANNELS)
- return -ENODEV;
-
- mutex_lock(&logical_ch[id].lc_lock);
- ret = logical_ch[id].is_channel_reset;
- mutex_unlock(&logical_ch[id].lc_lock);
- return ret;
-}
-EXPORT_SYMBOL(sdio_cmux_is_channel_reset);
-
-int sdio_cmux_tiocmget(int id)
-{
- int ret = (logical_ch[id].remote_status & DSR_POS ? TIOCM_DSR : 0) |
- (logical_ch[id].remote_status & CTS_POS ? TIOCM_CTS : 0) |
- (logical_ch[id].remote_status & CD_POS ? TIOCM_CD : 0) |
- (logical_ch[id].remote_status & RI_POS ? TIOCM_RI : 0) |
- (logical_ch[id].local_status & CTS_POS ? TIOCM_RTS : 0) |
- (logical_ch[id].local_status & DSR_POS ? TIOCM_DTR : 0);
- return ret;
-}
-EXPORT_SYMBOL(sdio_cmux_tiocmget);
-
-int sdio_cmux_tiocmset(int id, unsigned int set, unsigned int clear)
-{
- if (set & TIOCM_DTR)
- logical_ch[id].local_status |= DSR_POS;
-
- if (set & TIOCM_RTS)
- logical_ch[id].local_status |= CTS_POS;
-
- if (clear & TIOCM_DTR)
- logical_ch[id].local_status &= ~DSR_POS;
-
- if (clear & TIOCM_RTS)
- logical_ch[id].local_status &= ~CTS_POS;
-
- sdio_cmux_write_cmd(id, STATUS);
- return 0;
-}
-EXPORT_SYMBOL(sdio_cmux_tiocmset);
-
-static int copy_packet(void *pkt, int size)
-{
- struct sdio_cmux_list_elem *list_elem = NULL;
- void *temp_pkt = NULL;
-
- list_elem = kmalloc(sizeof(struct sdio_cmux_list_elem), GFP_KERNEL);
- if (!list_elem) {
- pr_err("%s: list_elem alloc failed\n", __func__);
- return -ENOMEM;
- }
- temp_pkt = kmalloc(size, GFP_KERNEL);
- if (!temp_pkt) {
- pr_err("%s: temp_pkt alloc failed\n", __func__);
- kfree(list_elem);
- return -ENOMEM;
- }
-
- memcpy(temp_pkt, pkt, size);
- list_elem->cmux_pkt.hdr = temp_pkt;
- list_elem->cmux_pkt.data = (void *)((char *)temp_pkt +
- sizeof(struct sdio_cmux_hdr));
- mutex_lock(&temp_rx_lock);
- list_add_tail(&list_elem->list, &temp_rx_list);
- mutex_unlock(&temp_rx_lock);
- return 0;
-}
-
-static int process_cmux_pkt(void *pkt, int size)
-{
- struct sdio_cmux_hdr *mux_hdr;
- uint32_t id, data_size;
- void *data;
- char *dump_buf = (char *)pkt;
-
- D_DUMP_BUFFER("process_cmux_pkt:", size, dump_buf);
- mux_hdr = (struct sdio_cmux_hdr *)pkt;
- switch (mux_hdr->cmd) {
- case OPEN:
- id = (uint32_t)(mux_hdr->lc_id);
- D("%s: Received OPEN command for ch%d\n", __func__, id);
- mutex_lock(&logical_ch[id].lc_lock);
- logical_ch[id].is_remote_open = 1;
- if (logical_ch[id].is_channel_reset) {
- sdio_cmux_write_cmd(id, OPEN);
- logical_ch[id].is_channel_reset = 0;
- }
- mutex_unlock(&logical_ch[id].lc_lock);
- wake_up(&logical_ch[id].open_wait_queue);
- break;
-
- case CLOSE:
- id = (uint32_t)(mux_hdr->lc_id);
- D("%s: Received CLOSE command for ch%d\n", __func__, id);
- sdio_cmux_ch_clear_and_signal(id);
- break;
-
- case DATA:
- id = (uint32_t)(mux_hdr->lc_id);
- D("%s: Received DATA for ch%d\n", __func__, id);
- /*Channel is not locally open & if single packet received
- then drop it*/
- mutex_lock(&logical_ch[id].lc_lock);
- if (!logical_ch[id].is_remote_open) {
- mutex_unlock(&logical_ch[id].lc_lock);
- pr_err("%s: Remote Ch%d sent data before sending/"
- "receiving OPEN command\n", __func__, id);
- return -ENODEV;
- }
-
- data = (void *)((char *)pkt + sizeof(struct sdio_cmux_hdr));
- data_size = (int)(((struct sdio_cmux_hdr *)pkt)->pkt_len);
- if (logical_ch[id].receive_cb)
- logical_ch[id].receive_cb(data, data_size,
- logical_ch[id].priv);
- else
- copy_packet(pkt, size);
- mutex_unlock(&logical_ch[id].lc_lock);
- break;
-
- case STATUS:
- id = (uint32_t)(mux_hdr->lc_id);
- D("%s: Received STATUS command for ch%d\n", __func__, id);
- if (logical_ch[id].remote_status != mux_hdr->status) {
- mutex_lock(&logical_ch[id].lc_lock);
- logical_ch[id].remote_status = mux_hdr->status;
- mutex_unlock(&logical_ch[id].lc_lock);
- if (logical_ch[id].status_callback)
- logical_ch[id].status_callback(
- sdio_cmux_tiocmget(id),
- logical_ch[id].priv);
- }
- break;
- }
- return 0;
-}
-
-static void parse_cmux_data(void *data, int size)
-{
- int data_parsed = 0, pkt_size;
- char *temp_ptr;
-
- D("Entered %s\n", __func__);
- temp_ptr = (char *)data;
- while (data_parsed < size) {
- pkt_size = sizeof(struct sdio_cmux_hdr) +
- (int)(((struct sdio_cmux_hdr *)temp_ptr)->pkt_len);
- D("Parsed %d bytes, Current Pkt Size %d bytes,"
- " Total size %d bytes\n", data_parsed, pkt_size, size);
- process_cmux_pkt((void *)temp_ptr, pkt_size);
- data_parsed += pkt_size;
- temp_ptr += pkt_size;
- }
-
- kfree(data);
-}
-
-static void sdio_cdemux_fn(struct work_struct *work)
-{
- int r = 0, read_avail = 0;
- void *cmux_data;
-
- while (1) {
- read_avail = sdio_read_avail(sdio_qmi_chl);
- if (read_avail < 0) {
- pr_err("%s: sdio_read_avail failed with rc %d\n",
- __func__, read_avail);
- return;
- }
-
- if (read_avail == 0) {
- D("%s: Nothing to read\n", __func__);
- return;
- }
-
- D("%s: kmalloc %d bytes\n", __func__, read_avail);
- cmux_data = kmalloc(read_avail, GFP_KERNEL);
- if (!cmux_data) {
- pr_err("%s: kmalloc Failed\n", __func__);
- return;
- }
-
- D("%s: sdio_read %d bytes\n", __func__, read_avail);
- r = sdio_read(sdio_qmi_chl, cmux_data, read_avail);
- if (r < 0) {
- pr_err("%s: sdio_read failed with rc %d\n",
- __func__, r);
- kfree(cmux_data);
- return;
- }
-
- parse_cmux_data(cmux_data, read_avail);
- }
- return;
-}
-
-static void sdio_cmux_fn(struct work_struct *work)
-{
- int i, r = 0;
- void *write_data;
- uint32_t write_size, write_avail, write_retry = 0;
- int bytes_written;
- struct sdio_cmux_list_elem *list_elem = NULL;
- struct sdio_cmux_ch *ch;
-
- for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) {
- ch = &logical_ch[i];
- bytes_written = 0;
- mutex_lock(&ch->tx_lock);
- while (!list_empty(&ch->tx_list)) {
- list_elem = list_first_entry(&ch->tx_list,
- struct sdio_cmux_list_elem,
- list);
- list_del(&list_elem->list);
- mutex_unlock(&ch->tx_lock);
-
- write_data = (void *)list_elem->cmux_pkt.hdr;
- write_size = sizeof(struct sdio_cmux_hdr) +
- (uint32_t)list_elem->cmux_pkt.hdr->pkt_len;
-
- mutex_lock(&modem_reset_lock);
- while (!(abort_tx) &&
- ((write_avail = sdio_write_avail(sdio_qmi_chl))
- < write_size)) {
- mutex_unlock(&modem_reset_lock);
- pr_err("%s: sdio_write_avail %d bytes, "
- "write size %d bytes. Waiting...\n",
- __func__, write_avail, write_size);
- msleep(250);
- mutex_lock(&modem_reset_lock);
- }
- while (!(abort_tx) &&
- ((r = sdio_write(sdio_qmi_chl,
- write_data, write_size)) < 0)
- && (r != -ENODEV)
- && (write_retry++ < MAX_WRITE_RETRY)) {
- mutex_unlock(&modem_reset_lock);
- pr_err("%s: sdio_write failed with rc %d."
- "Retrying...", __func__, r);
- msleep(250);
- mutex_lock(&modem_reset_lock);
- }
- if (!r && !abort_tx) {
- D("%s: sdio_write_completed %dbytes\n",
- __func__, write_size);
- bytes_written += write_size;
- } else if (r == -ENODEV) {
- pr_err("%s: aborting_tx because sdio_write"
- " returned %d\n", __func__, r);
- r = 0;
- abort_tx = 1;
- }
- mutex_unlock(&modem_reset_lock);
- kfree(list_elem->cmux_pkt.hdr);
- kfree(list_elem);
- mutex_lock(&write_lock);
- bytes_to_write -= write_size;
- mutex_unlock(&write_lock);
- mutex_lock(&ch->tx_lock);
- }
- if (ch->write_done)
- ch->write_done(NULL, bytes_written, ch->priv);
- mutex_unlock(&ch->tx_lock);
- }
- return;
-}
-
-static void sdio_qmi_chl_notify(void *priv, unsigned event)
-{
- if (event == SDIO_EVENT_DATA_READ_AVAIL) {
- D("%s: Received SDIO_EVENT_DATA_READ_AVAIL\n", __func__);
- queue_work(sdio_cdemux_wq, &sdio_cdemux_work);
- }
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-static int debug_tbl(char *buf, int max)
-{
- int i = 0;
- int j;
-
- for (j = 0; j < SDIO_CMUX_NUM_CHANNELS; ++j) {
- i += scnprintf(buf + i, max - i,
- "ch%02d local open=%s remote open=%s\n",
- j, logical_ch_is_local_open(j) ? "Y" : "N",
- logical_ch_is_remote_open(j) ? "Y" : "N");
- }
-
- return i;
-}
-
-#define DEBUG_BUFMAX 4096
-static char debug_buffer[DEBUG_BUFMAX];
-
-static ssize_t debug_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- int (*fill)(char *buf, int max) = file->private_data;
- int bsize = fill(debug_buffer, DEBUG_BUFMAX);
- return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
-}
-
-static int debug_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-
-static const struct file_operations debug_ops = {
- .read = debug_read,
- .open = debug_open,
-};
-
-static void debug_create(const char *name, mode_t mode,
- struct dentry *dent,
- int (*fill)(char *buf, int max))
-{
- debugfs_create_file(name, mode, dent, fill, &debug_ops);
-}
-
-#endif
-
-static int sdio_cmux_probe(struct platform_device *pdev)
-{
- int i, r;
-
- mutex_lock(&probe_lock);
- D("%s Begins\n", __func__);
- if (sdio_cmux_inited) {
- mutex_lock(&modem_reset_lock);
- r = sdio_open("SDIO_QMI", &sdio_qmi_chl, NULL,
- sdio_qmi_chl_notify);
- if (r < 0) {
- mutex_unlock(&modem_reset_lock);
- pr_err("%s: sdio_open() failed\n", __func__);
- goto error0;
- }
- abort_tx = 0;
- mutex_unlock(&modem_reset_lock);
- mutex_unlock(&probe_lock);
- return 0;
- }
-
- for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i)
- sdio_cmux_ch_alloc(i);
- INIT_LIST_HEAD(&temp_rx_list);
-
- sdio_cmux_wq = create_singlethread_workqueue("sdio_cmux");
- if (IS_ERR(sdio_cmux_wq)) {
- pr_err("%s: create_singlethread_workqueue() ENOMEM\n",
- __func__);
- r = -ENOMEM;
- goto error0;
- }
-
- sdio_cdemux_wq = create_singlethread_workqueue("sdio_cdemux");
- if (IS_ERR(sdio_cdemux_wq)) {
- pr_err("%s: create_singlethread_workqueue() ENOMEM\n",
- __func__);
- r = -ENOMEM;
- goto error1;
- }
-
- r = sdio_open("SDIO_QMI", &sdio_qmi_chl, NULL, sdio_qmi_chl_notify);
- if (r < 0) {
- pr_err("%s: sdio_open() failed\n", __func__);
- goto error2;
- }
-
- platform_device_register(&sdio_ctl_dev);
- sdio_cmux_inited = 1;
- D("SDIO Control MUX Driver Initialized.\n");
- mutex_unlock(&probe_lock);
- return 0;
-
-error2:
- destroy_workqueue(sdio_cdemux_wq);
-error1:
- destroy_workqueue(sdio_cmux_wq);
-error0:
- mutex_unlock(&probe_lock);
- return r;
-}
-
-static int sdio_cmux_remove(struct platform_device *pdev)
-{
- int i;
-
- mutex_lock(&modem_reset_lock);
- abort_tx = 1;
-
- for (i = 0; i < SDIO_CMUX_NUM_CHANNELS; ++i) {
- mutex_lock(&logical_ch[i].lc_lock);
- logical_ch[i].is_channel_reset = 1;
- mutex_unlock(&logical_ch[i].lc_lock);
- sdio_cmux_ch_clear_and_signal(i);
- }
- sdio_qmi_chl = NULL;
- mutex_unlock(&modem_reset_lock);
-
- return 0;
-}
-
-static struct platform_driver sdio_cmux_driver = {
- .probe = sdio_cmux_probe,
- .remove = sdio_cmux_remove,
- .driver = {
- .name = "SDIO_QMI",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sdio_cmux_init(void)
-{
-#ifdef CONFIG_DEBUG_FS
- struct dentry *dent;
-
- dent = debugfs_create_dir("sdio_cmux", 0);
- if (!IS_ERR(dent))
- debug_create("tbl", 0444, dent, debug_tbl);
-#endif
-
- msm_sdio_cmux_debug_mask = 0;
- return platform_driver_register(&sdio_cmux_driver);
-}
-
-module_init(sdio_cmux_init);
-MODULE_DESCRIPTION("MSM SDIO Control MUX");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_ctl.c b/arch/arm/mach-msm/sdio_ctl.c
deleted file mode 100644
index cacdce9..0000000
--- a/arch/arm/mach-msm/sdio_ctl.c
+++ /dev/null
@@ -1,575 +0,0 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/*
- * SDIO Control Driver -- Provides a binary SDIO muxed control port
- * interface.
- */
-
-#include <linux/cdev.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/workqueue.h>
-#include <linux/poll.h>
-#include <asm/ioctls.h>
-#include <linux/platform_device.h>
-#include <mach/msm_smd.h>
-#include <mach/sdio_al.h>
-#include <mach/sdio_cmux.h>
-#include "modem_notifier.h"
-#include <linux/slab.h>
-
-#define MAX_WRITE_RETRY 5
-#define MAGIC_NO_V1 0x33FC
-#define NUM_SDIO_CTL_PORTS 10
-#define DEVICE_NAME "sdioctl"
-#define MAX_BUF_SIZE 2048
-#define DEBUG
-
-static int msm_sdio_ctl_debug_mask;
-module_param_named(debug_mask, msm_sdio_ctl_debug_mask,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-struct sdio_ctl_dev {
- int id;
- char name[9];
- struct cdev cdev;
- struct device *devicep;
- struct mutex dev_lock;
- int ref_count;
-
- struct mutex rx_lock;
- uint32_t read_avail;
- struct list_head rx_list;
-
- wait_queue_head_t read_wait_queue;
- wait_queue_head_t write_wait_queue;
-} *sdio_ctl_devp[NUM_SDIO_CTL_PORTS];
-
-struct sdio_ctl_pkt {
- int data_size;
- void *data;
-};
-
-struct sdio_ctl_list_elem {
- struct list_head list;
- struct sdio_ctl_pkt ctl_pkt;
-};
-
-struct class *sdio_ctl_classp;
-static dev_t sdio_ctl_number;
-static uint32_t sdio_ctl_inited;
-
-enum {
- MSM_SDIO_CTL_DEBUG = 1U << 0,
- MSM_SDIO_CTL_DUMP_BUFFER = 1U << 1,
-};
-
-#if defined(DEBUG)
-#define D_DUMP_BUFFER(prestr, cnt, buf) \
-do { \
- if (msm_sdio_ctl_debug_mask & MSM_SDIO_CTL_DUMP_BUFFER) { \
- int i; \
- pr_info("%s", prestr); \
- for (i = 0; i < cnt; i++) \
- pr_info("%.2x", buf[i]); \
- pr_info("\n"); \
- } \
-} while (0)
-
-#define D(x...) \
-do { \
- if (msm_sdio_ctl_debug_mask & MSM_SDIO_CTL_DEBUG) \
- pr_info(x); \
-} while (0)
-
-#else
-#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#define D(x...) do {} while (0)
-#endif
-
-static uint32_t cmux_ch_id[] = {
- SDIO_CMUX_DATA_CTL_0,
- SDIO_CMUX_DATA_CTL_1,
- SDIO_CMUX_DATA_CTL_2,
- SDIO_CMUX_DATA_CTL_3,
- SDIO_CMUX_DATA_CTL_4,
- SDIO_CMUX_DATA_CTL_5,
- SDIO_CMUX_DATA_CTL_6,
- SDIO_CMUX_DATA_CTL_7,
- SDIO_CMUX_USB_CTL_0,
- SDIO_CMUX_CSVT_CTL_0
-};
-
-static int get_ctl_dev_index(int id)
-{
- int dev_index;
- for (dev_index = 0; dev_index < NUM_SDIO_CTL_PORTS; dev_index++) {
- if (cmux_ch_id[dev_index] == id)
- return dev_index;
- }
- return -ENODEV;
-}
-
-static void sdio_ctl_receive_cb(void *data, int size, void *priv)
-{
- struct sdio_ctl_list_elem *list_elem = NULL;
- int id = ((struct sdio_ctl_dev *)(priv))->id;
- int dev_index;
-
- if (id < 0 || id > cmux_ch_id[NUM_SDIO_CTL_PORTS - 1])
- return;
- dev_index = get_ctl_dev_index(id);
- if (dev_index < 0) {
- pr_err("%s: Ch%d is not exported to user-space\n",
- __func__, id);
- return;
- }
-
- if (!data || size <= 0) {
- wake_up(&sdio_ctl_devp[dev_index]->read_wait_queue);
- return;
- }
-
- list_elem = kmalloc(sizeof(struct sdio_ctl_list_elem), GFP_KERNEL);
- if (!list_elem) {
- pr_err("%s: list_elem alloc failed\n", __func__);
- return;
- }
-
- list_elem->ctl_pkt.data = kmalloc(size, GFP_KERNEL);
- if (!list_elem->ctl_pkt.data) {
- pr_err("%s: list_elem->data alloc failed\n", __func__);
- kfree(list_elem);
- return;
- }
- memcpy(list_elem->ctl_pkt.data, data, size);
- list_elem->ctl_pkt.data_size = size;
- mutex_lock(&sdio_ctl_devp[dev_index]->rx_lock);
- list_add_tail(&list_elem->list, &sdio_ctl_devp[dev_index]->rx_list);
- sdio_ctl_devp[dev_index]->read_avail += size;
- mutex_unlock(&sdio_ctl_devp[dev_index]->rx_lock);
- wake_up(&sdio_ctl_devp[dev_index]->read_wait_queue);
-}
-
-static void sdio_ctl_write_done(void *data, int size, void *priv)
-{
- int id = ((struct sdio_ctl_dev *)(priv))->id;
- int dev_index;
- if (id < 0 || id > cmux_ch_id[NUM_SDIO_CTL_PORTS - 1])
- return;
-
- dev_index = get_ctl_dev_index(id);
- if (dev_index < 0) {
- pr_err("%s: Ch%d is not exported to user-space\n",
- __func__, id);
- return;
- }
- wake_up(&sdio_ctl_devp[dev_index]->write_wait_queue);
-}
-
-static long sdio_ctl_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ret;
- struct sdio_ctl_dev *sdio_ctl_devp;
-
- sdio_ctl_devp = file->private_data;
- if (!sdio_ctl_devp)
- return -ENODEV;
-
- switch (cmd) {
- case TIOCMGET:
- ret = sdio_cmux_tiocmget(sdio_ctl_devp->id);
- break;
- case TIOCMSET:
- ret = sdio_cmux_tiocmset(sdio_ctl_devp->id, arg, ~arg);
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static unsigned int sdio_ctl_poll(struct file *file, poll_table *wait)
-{
- struct sdio_ctl_dev *sdio_ctl_devp;
- unsigned int mask = 0;
-
- sdio_ctl_devp = file->private_data;
- if (!sdio_ctl_devp) {
- pr_err("%s: on a NULL device\n", __func__);
- return POLLERR;
- }
-
- poll_wait(file, &sdio_ctl_devp->read_wait_queue, wait);
- mutex_lock(&sdio_ctl_devp->rx_lock);
- if (sdio_cmux_is_channel_reset(sdio_ctl_devp->id)) {
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- pr_err("%s notifying reset for sdio_ctl_dev id:%d\n",
- __func__, sdio_ctl_devp->id);
- return POLLERR;
- }
-
- if (sdio_ctl_devp->read_avail > 0)
- mask |= POLLIN | POLLRDNORM;
-
- mutex_unlock(&sdio_ctl_devp->rx_lock);
-
- return mask;
-}
-
-ssize_t sdio_ctl_read(struct file *file,
- char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int r = 0, id, bytes_to_read;
- struct sdio_ctl_dev *sdio_ctl_devp;
- struct sdio_ctl_list_elem *list_elem = NULL;
-
- sdio_ctl_devp = file->private_data;
-
- if (!sdio_ctl_devp)
- return -ENODEV;
-
- D("%s: read from ch%d\n", __func__, sdio_ctl_devp->id);
-
- id = sdio_ctl_devp->id;
- mutex_lock(&sdio_ctl_devp->rx_lock);
- while (sdio_ctl_devp->read_avail <= 0) {
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- r = wait_event_interruptible(sdio_ctl_devp->read_wait_queue,
- sdio_ctl_devp->read_avail > 0 ||
- !is_remote_open(id));
- if (sdio_cmux_is_channel_reset(id))
- return -ENETRESET;
-
- if (!is_remote_open(id))
- return -ENODEV;
-
- if (r < 0) {
- /* qualify error message */
- /* we get this anytime a signal comes in */
- if (r != -ERESTARTSYS)
- pr_err("ERROR:%s: wait_event_interruptible "
- "ret %i\n", __func__, r);
- return r;
- }
- mutex_lock(&sdio_ctl_devp->rx_lock);
- }
-
- if (list_empty(&sdio_ctl_devp->rx_list)) {
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- D("%s: Nothing in ch%d's rx_list\n", __func__,
- sdio_ctl_devp->id);
- return -EAGAIN;
- }
-
- list_elem = list_first_entry(&sdio_ctl_devp->rx_list,
- struct sdio_ctl_list_elem, list);
- bytes_to_read = (uint32_t)(list_elem->ctl_pkt.data_size);
- if (bytes_to_read > count) {
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- pr_err("%s: Packet size %d > buf size %d\n", __func__,
- bytes_to_read, count);
- return -ENOMEM;
- }
-
- if (copy_to_user(buf, list_elem->ctl_pkt.data, bytes_to_read)) {
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- pr_err("%s: copy_to_user failed for ch%d\n", __func__,
- sdio_ctl_devp->id);
- return -EFAULT;
- }
- sdio_ctl_devp->read_avail -= bytes_to_read;
- list_del(&list_elem->list);
- kfree(list_elem->ctl_pkt.data);
- kfree(list_elem);
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- D("%s: Returning %d bytes to ch%d\n", __func__,
- bytes_to_read, sdio_ctl_devp->id);
- return bytes_to_read;
-}
-
-
-ssize_t sdio_ctl_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int r = 0, id;
- char *temp_buf;
- struct sdio_ctl_dev *sdio_ctl_devp;
-
- if (count <= 0)
- return -EINVAL;
-
- sdio_ctl_devp = file->private_data;
- if (!sdio_ctl_devp)
- return -ENODEV;
-
- D("%s: writing %i bytes on ch%d\n",
- __func__, count, sdio_ctl_devp->id);
- id = sdio_ctl_devp->id;
- mutex_lock(&sdio_ctl_devp->dev_lock);
- while (sdio_cmux_write_avail(id) < count) {
- mutex_unlock(&sdio_ctl_devp->dev_lock);
- r = wait_event_interruptible(sdio_ctl_devp->write_wait_queue,
- sdio_cmux_write_avail(id) >= count
- || !is_remote_open(id));
-
- if (sdio_cmux_is_channel_reset(id))
- return -ENETRESET;
-
- if (!is_remote_open(id))
- return -ENODEV;
-
- if (r < 0) {
- /* qualify error message */
- /* we get this anytime a signal comes in */
- if (r != -ERESTARTSYS)
- pr_err("ERROR:%s: wait_event_interruptible "
- "ret %i\n", __func__, r);
- return r;
- }
- mutex_lock(&sdio_ctl_devp->dev_lock);
- }
-
- temp_buf = kmalloc(count, GFP_KERNEL);
- if (!temp_buf) {
- mutex_unlock(&sdio_ctl_devp->dev_lock);
- pr_err("%s: temp_buf alloc failed\n", __func__);
- return -ENOMEM;
- }
-
- if (copy_from_user(temp_buf, buf, count)) {
- mutex_unlock(&sdio_ctl_devp->dev_lock);
- pr_err("%s: copy_from_user failed\n", __func__);
- kfree(temp_buf);
- return -EFAULT;
- }
-
- r = sdio_cmux_write(id, (void *)temp_buf, count);
- kfree(temp_buf);
- mutex_unlock(&sdio_ctl_devp->dev_lock);
- return r;
-}
-
-
-int sdio_ctl_open(struct inode *inode, struct file *file)
-{
- int r = 0;
- struct sdio_ctl_dev *sdio_ctl_devp;
-
- if (!sdio_ctl_inited)
- return -EIO;
-
- sdio_ctl_devp = container_of(inode->i_cdev, struct sdio_ctl_dev, cdev);
-
- if (!sdio_ctl_devp)
- return -ENODEV;
-
- D("%s called on sdioctl%d device\n", __func__, sdio_ctl_devp->id);
- r = sdio_cmux_open(sdio_ctl_devp->id, sdio_ctl_receive_cb,
- sdio_ctl_write_done, NULL,
- sdio_ctl_devp);
- if (r < 0) {
- pr_err("ERROR %s: sdio_cmux_open failed with rc %d\n",
- __func__, r);
- return r;
- }
-
- mutex_lock(&sdio_ctl_devp->dev_lock);
- sdio_ctl_devp->ref_count++;
- mutex_unlock(&sdio_ctl_devp->dev_lock);
-
- file->private_data = sdio_ctl_devp;
- return 0;
-}
-
-int sdio_ctl_release(struct inode *inode, struct file *file)
-{
- struct sdio_ctl_dev *sdio_ctl_devp;
- struct sdio_ctl_list_elem *list_elem = NULL;
-
- sdio_ctl_devp = file->private_data;
- if (!sdio_ctl_devp)
- return -EINVAL;
-
- D("%s called on sdioctl%d device\n", __func__, sdio_ctl_devp->id);
-
- mutex_lock(&sdio_ctl_devp->dev_lock);
- if (sdio_ctl_devp->ref_count > 0) {
- sdio_ctl_devp->ref_count--;
- if (!sdio_ctl_devp->ref_count) {
- mutex_lock(&sdio_ctl_devp->rx_lock);
- while (!list_empty(&sdio_ctl_devp->rx_list)) {
- list_elem = list_first_entry(
- &sdio_ctl_devp->rx_list,
- struct sdio_ctl_list_elem,
- list);
- list_del(&list_elem->list);
- kfree(list_elem->ctl_pkt.data);
- kfree(list_elem);
- }
- sdio_ctl_devp->read_avail = 0;
- mutex_unlock(&sdio_ctl_devp->rx_lock);
- sdio_cmux_close(sdio_ctl_devp->id);
- }
- }
- mutex_unlock(&sdio_ctl_devp->dev_lock);
-
- file->private_data = NULL;
- return 0;
-}
-
-static const struct file_operations sdio_ctl_fops = {
- .owner = THIS_MODULE,
- .open = sdio_ctl_open,
- .release = sdio_ctl_release,
- .read = sdio_ctl_read,
- .write = sdio_ctl_write,
- .poll = sdio_ctl_poll,
- .unlocked_ioctl = sdio_ctl_ioctl,
-};
-
-static int sdio_ctl_probe(struct platform_device *pdev)
-{
- int i;
- int r;
-
- pr_info("%s Begins\n", __func__);
- for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
- sdio_ctl_devp[i] = kzalloc(sizeof(struct sdio_ctl_dev),
- GFP_KERNEL);
- if (IS_ERR(sdio_ctl_devp[i])) {
- pr_err("ERROR:%s kmalloc() ENOMEM\n", __func__);
- r = -ENOMEM;
- goto error0;
- }
-
- sdio_ctl_devp[i]->id = cmux_ch_id[i];
- sdio_ctl_devp[i]->ref_count = 0;
-
- mutex_init(&sdio_ctl_devp[i]->dev_lock);
- init_waitqueue_head(&sdio_ctl_devp[i]->read_wait_queue);
- init_waitqueue_head(&sdio_ctl_devp[i]->write_wait_queue);
- mutex_init(&sdio_ctl_devp[i]->rx_lock);
- INIT_LIST_HEAD(&sdio_ctl_devp[i]->rx_list);
- sdio_ctl_devp[i]->read_avail = 0;
- }
-
- r = alloc_chrdev_region(&sdio_ctl_number, 0, NUM_SDIO_CTL_PORTS,
- DEVICE_NAME);
- if (IS_ERR_VALUE(r)) {
- pr_err("ERROR:%s: alloc_chrdev_region() ret %i.\n",
- __func__, r);
- goto error0;
- }
-
- sdio_ctl_classp = class_create(THIS_MODULE, DEVICE_NAME);
- if (IS_ERR(sdio_ctl_classp)) {
- pr_err("ERROR:%s: class_create() ENOMEM\n", __func__);
- r = -ENOMEM;
- goto error1;
- }
-
- for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
- cdev_init(&sdio_ctl_devp[i]->cdev, &sdio_ctl_fops);
- sdio_ctl_devp[i]->cdev.owner = THIS_MODULE;
-
- r = cdev_add(&sdio_ctl_devp[i]->cdev, (sdio_ctl_number + i),
- 1);
-
- if (IS_ERR_VALUE(r)) {
- pr_err("%s: cdev_add() ret %i\n", __func__, r);
- kfree(sdio_ctl_devp[i]);
- goto error2;
- }
-
- sdio_ctl_devp[i]->devicep =
- device_create(sdio_ctl_classp, NULL,
- (sdio_ctl_number + i), NULL,
- DEVICE_NAME "%d", cmux_ch_id[i]);
-
- if (IS_ERR(sdio_ctl_devp[i]->devicep)) {
- pr_err("%s: device_create() ENOMEM\n", __func__);
- r = -ENOMEM;
- cdev_del(&sdio_ctl_devp[i]->cdev);
- kfree(sdio_ctl_devp[i]);
- goto error2;
- }
- }
-
- sdio_ctl_inited = 1;
- D("SDIO Control Port Driver Initialized.\n");
- return 0;
-
-error2:
- while (--i >= 0) {
- cdev_del(&sdio_ctl_devp[i]->cdev);
- device_destroy(sdio_ctl_classp,
- MKDEV(MAJOR(sdio_ctl_number), i));
- }
-
- class_destroy(sdio_ctl_classp);
- i = NUM_SDIO_CTL_PORTS;
-error1:
- unregister_chrdev_region(MAJOR(sdio_ctl_number), NUM_SDIO_CTL_PORTS);
-error0:
- while (--i >= 0)
- kfree(sdio_ctl_devp[i]);
- return r;
-}
-
-static int sdio_ctl_remove(struct platform_device *pdev)
-{
- int i;
-
- for (i = 0; i < NUM_SDIO_CTL_PORTS; ++i) {
- cdev_del(&sdio_ctl_devp[i]->cdev);
- kfree(sdio_ctl_devp[i]);
- device_destroy(sdio_ctl_classp,
- MKDEV(MAJOR(sdio_ctl_number), i));
- }
- class_destroy(sdio_ctl_classp);
- unregister_chrdev_region(MAJOR(sdio_ctl_number), NUM_SDIO_CTL_PORTS);
-
- return 0;
-}
-
-static struct platform_driver sdio_ctl_driver = {
- .probe = sdio_ctl_probe,
- .remove = sdio_ctl_remove,
- .driver = {
- .name = "SDIO_CTL",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sdio_ctl_init(void)
-{
- msm_sdio_ctl_debug_mask = 0;
- return platform_driver_register(&sdio_ctl_driver);
-}
-
-module_init(sdio_ctl_init);
-MODULE_DESCRIPTION("MSM SDIO Control Port");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_dmux.c b/arch/arm/mach-msm/sdio_dmux.c
deleted file mode 100644
index c6d665d..0000000
--- a/arch/arm/mach-msm/sdio_dmux.c
+++ /dev/null
@@ -1,925 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-/*
- * SDIO DMUX module.
- */
-
-#define DEBUG
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/wakelock.h>
-#include <linux/debugfs.h>
-#include <linux/smp.h>
-#include <linux/cpumask.h>
-
-#include <mach/sdio_al.h>
-#include <mach/sdio_dmux.h>
-
-#define SDIO_CH_LOCAL_OPEN 0x1
-#define SDIO_CH_REMOTE_OPEN 0x2
-#define SDIO_CH_IN_RESET 0x4
-
-#define SDIO_MUX_HDR_MAGIC_NO 0x33fc
-
-#define SDIO_MUX_HDR_CMD_DATA 0
-#define SDIO_MUX_HDR_CMD_OPEN 1
-#define SDIO_MUX_HDR_CMD_CLOSE 2
-
-#define LOW_WATERMARK 2
-#define HIGH_WATERMARK 4
-
-static int msm_sdio_dmux_debug_enable;
-module_param_named(debug_enable, msm_sdio_dmux_debug_enable,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#if defined(DEBUG)
-static uint32_t sdio_dmux_read_cnt;
-static uint32_t sdio_dmux_write_cnt;
-static uint32_t sdio_dmux_write_cpy_cnt;
-static uint32_t sdio_dmux_write_cpy_bytes;
-
-#define DBG(x...) do { \
- if (msm_sdio_dmux_debug_enable) \
- pr_debug(x); \
- } while (0)
-
-#define DBG_INC_READ_CNT(x) do { \
- sdio_dmux_read_cnt += (x); \
- if (msm_sdio_dmux_debug_enable) \
- pr_debug("%s: total read bytes %u\n", \
- __func__, sdio_dmux_read_cnt); \
- } while (0)
-
-#define DBG_INC_WRITE_CNT(x) do { \
- sdio_dmux_write_cnt += (x); \
- if (msm_sdio_dmux_debug_enable) \
- pr_debug("%s: total written bytes %u\n", \
- __func__, sdio_dmux_write_cnt); \
- } while (0)
-
-#define DBG_INC_WRITE_CPY(x) do { \
- sdio_dmux_write_cpy_bytes += (x); \
- sdio_dmux_write_cpy_cnt++; \
- if (msm_sdio_dmux_debug_enable) \
- pr_debug("%s: total write copy cnt %u, bytes %u\n", \
- __func__, sdio_dmux_write_cpy_cnt, \
- sdio_dmux_write_cpy_bytes); \
- } while (0)
-#else
-#define DBG(x...) do { } while (0)
-#define DBG_INC_READ_CNT(x...) do { } while (0)
-#define DBG_INC_WRITE_CNT(x...) do { } while (0)
-#define DBG_INC_WRITE_CPY(x...) do { } while (0)
-#endif
-
-struct sdio_ch_info {
- uint32_t status;
- void (*receive_cb)(void *, struct sk_buff *);
- void (*write_done)(void *, struct sk_buff *);
- void *priv;
- spinlock_t lock;
- int num_tx_pkts;
- int use_wm;
-};
-
-static struct sk_buff_head sdio_mux_write_pool;
-static spinlock_t sdio_mux_write_lock;
-
-static struct sdio_channel *sdio_mux_ch;
-static struct sdio_ch_info sdio_ch[SDIO_DMUX_NUM_CHANNELS];
-struct wake_lock sdio_mux_ch_wakelock;
-static int sdio_mux_initialized;
-static int fatal_error;
-
-struct sdio_mux_hdr {
- uint16_t magic_num;
- uint8_t reserved;
- uint8_t cmd;
- uint8_t pad_len;
- uint8_t ch_id;
- uint16_t pkt_len;
-};
-
-struct sdio_partial_pkt_info {
- uint32_t valid;
- struct sk_buff *skb;
- struct sdio_mux_hdr *hdr;
-};
-
-static void sdio_mux_read_data(struct work_struct *work);
-static void sdio_mux_write_data(struct work_struct *work);
-static void sdio_mux_send_open_cmd(uint32_t id);
-
-static DEFINE_MUTEX(sdio_mux_lock);
-static DECLARE_WORK(work_sdio_mux_read, sdio_mux_read_data);
-static DECLARE_WORK(work_sdio_mux_write, sdio_mux_write_data);
-static DECLARE_DELAYED_WORK(delayed_work_sdio_mux_write, sdio_mux_write_data);
-
-static struct workqueue_struct *sdio_mux_workqueue;
-static struct sdio_partial_pkt_info sdio_partial_pkt;
-
-#define sdio_ch_is_open(x) \
- (sdio_ch[(x)].status == (SDIO_CH_LOCAL_OPEN | SDIO_CH_REMOTE_OPEN))
-
-#define sdio_ch_is_local_open(x) \
- (sdio_ch[(x)].status & SDIO_CH_LOCAL_OPEN)
-
-#define sdio_ch_is_remote_open(x) \
- (sdio_ch[(x)].status & SDIO_CH_REMOTE_OPEN)
-
-#define sdio_ch_is_in_reset(x) \
- (sdio_ch[(x)].status & SDIO_CH_IN_RESET)
-
-static inline void skb_set_data(struct sk_buff *skb,
- unsigned char *data,
- unsigned int len)
-{
- /* panic if tail > end */
- skb->data = data;
- skb->tail = skb->data + len;
- skb->len = len;
- skb->truesize = len + sizeof(struct sk_buff);
-}
-
-static void sdio_mux_save_partial_pkt(struct sdio_mux_hdr *hdr,
- struct sk_buff *skb_mux)
-{
- struct sk_buff *skb;
-
- /* i think we can avoid cloning here */
- skb = skb_clone(skb_mux, GFP_KERNEL);
- if (!skb) {
- pr_err("%s: cannot clone skb\n", __func__);
- return;
- }
-
- /* protect? */
- skb_set_data(skb, (unsigned char *)hdr,
- skb->tail - (unsigned char *)hdr);
- sdio_partial_pkt.skb = skb;
- sdio_partial_pkt.valid = 1;
- DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
- skb->head, skb->data, skb->tail, skb->end, skb->len);
- return;
-}
-
-static void *handle_sdio_mux_data(struct sdio_mux_hdr *hdr,
- struct sk_buff *skb_mux)
-{
- struct sk_buff *skb;
- void *rp = (void *)hdr;
- unsigned long flags;
-
- /* protect? */
- rp += sizeof(*hdr);
- if (rp < (void *)skb_mux->tail)
- rp += (hdr->pkt_len + hdr->pad_len);
-
- if (rp > (void *)skb_mux->tail) {
- /* partial packet */
- sdio_mux_save_partial_pkt(hdr, skb_mux);
- goto packet_done;
- }
-
- DBG("%s: hdr %p next %p tail %p pkt_size %d\n",
- __func__, hdr, rp, skb_mux->tail, hdr->pkt_len + hdr->pad_len);
-
- skb = skb_clone(skb_mux, GFP_KERNEL);
- if (!skb) {
- pr_err("%s: cannot clone skb\n", __func__);
- goto packet_done;
- }
-
- skb_set_data(skb, (unsigned char *)(hdr + 1), hdr->pkt_len);
- DBG("%s: head %p data %p tail %p end %p len %d\n",
- __func__, skb->head, skb->data, skb->tail, skb->end, skb->len);
-
- /* probably we should check channel status */
- /* discard packet early if local side not open */
- spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
- if (sdio_ch[hdr->ch_id].receive_cb)
- sdio_ch[hdr->ch_id].receive_cb(sdio_ch[hdr->ch_id].priv, skb);
- else
- dev_kfree_skb_any(skb);
- spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
-
-packet_done:
- return rp;
-}
-
-static void *handle_sdio_mux_command(struct sdio_mux_hdr *hdr,
- struct sk_buff *skb_mux)
-{
- void *rp;
- unsigned long flags;
- int send_open = 0;
-
- DBG("%s: cmd %d ch %d\n", __func__, hdr->cmd, hdr->ch_id);
- switch (hdr->cmd) {
- case SDIO_MUX_HDR_CMD_DATA:
- rp = handle_sdio_mux_data(hdr, skb_mux);
- break;
- case SDIO_MUX_HDR_CMD_OPEN:
- spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
- sdio_ch[hdr->ch_id].status |= SDIO_CH_REMOTE_OPEN;
- sdio_ch[hdr->ch_id].num_tx_pkts = 0;
-
- if (sdio_ch_is_in_reset(hdr->ch_id)) {
- DBG("%s: in reset - sending open cmd\n", __func__);
- sdio_ch[hdr->ch_id].status &= ~SDIO_CH_IN_RESET;
- send_open = 1;
- }
-
- /* notify client so it can update its status */
- if (sdio_ch[hdr->ch_id].receive_cb)
- sdio_ch[hdr->ch_id].receive_cb(
- sdio_ch[hdr->ch_id].priv, NULL);
-
- if (sdio_ch[hdr->ch_id].write_done)
- sdio_ch[hdr->ch_id].write_done(
- sdio_ch[hdr->ch_id].priv, NULL);
- spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
- rp = hdr + 1;
- if (send_open)
- sdio_mux_send_open_cmd(hdr->ch_id);
-
- break;
- case SDIO_MUX_HDR_CMD_CLOSE:
- /* probably should drop pending write */
- spin_lock_irqsave(&sdio_ch[hdr->ch_id].lock, flags);
- sdio_ch[hdr->ch_id].status &= ~SDIO_CH_REMOTE_OPEN;
- spin_unlock_irqrestore(&sdio_ch[hdr->ch_id].lock, flags);
- rp = hdr + 1;
- break;
- default:
- rp = hdr + 1;
- }
-
- return rp;
-}
-
-static void *handle_sdio_partial_pkt(struct sk_buff *skb_mux)
-{
- struct sk_buff *p_skb;
- struct sdio_mux_hdr *p_hdr;
- void *ptr, *rp = skb_mux->data;
-
- /* protoect? */
- if (sdio_partial_pkt.valid) {
- p_skb = sdio_partial_pkt.skb;
-
- ptr = skb_push(skb_mux, p_skb->len);
- memcpy(ptr, p_skb->data, p_skb->len);
- sdio_partial_pkt.skb = NULL;
- sdio_partial_pkt.valid = 0;
- dev_kfree_skb_any(p_skb);
-
- DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
- skb_mux->head, skb_mux->data, skb_mux->tail,
- skb_mux->end, skb_mux->len);
-
- p_hdr = (struct sdio_mux_hdr *)skb_mux->data;
- rp = handle_sdio_mux_command(p_hdr, skb_mux);
- }
- return rp;
-}
-
-static void sdio_mux_read_data(struct work_struct *work)
-{
- struct sk_buff *skb_mux;
- void *ptr = 0;
- int sz, rc, len = 0;
- struct sdio_mux_hdr *hdr;
- static int workqueue_pinned;
-
- if (!workqueue_pinned) {
- struct cpumask cpus;
-
- cpumask_clear(&cpus);
- cpumask_set_cpu(0, &cpus);
-
- if (sched_setaffinity(current->pid, &cpus))
- pr_err("%s: sdio_dmux set CPU affinity failed\n",
- __func__);
- workqueue_pinned = 1;
- }
-
- DBG("%s: reading\n", __func__);
- /* should probably have a separate read lock */
- mutex_lock(&sdio_mux_lock);
- sz = sdio_read_avail(sdio_mux_ch);
- DBG("%s: read avail %d\n", __func__, sz);
- if (sz <= 0) {
- if (sz)
- pr_err("%s: read avail failed %d\n", __func__, sz);
- mutex_unlock(&sdio_mux_lock);
- return;
- }
-
- /* net_ip_aling is probably not required */
- if (sdio_partial_pkt.valid)
- len = sdio_partial_pkt.skb->len;
-
- /* If allocation fails attempt to get a smaller chunk of mem */
- do {
- skb_mux = __dev_alloc_skb(sz + NET_IP_ALIGN + len, GFP_KERNEL);
- if (skb_mux)
- break;
-
- pr_err("%s: cannot allocate skb of size:%d + "
- "%d (NET_SKB_PAD)\n", __func__,
- sz + NET_IP_ALIGN + len, NET_SKB_PAD);
- /* the skb structure adds NET_SKB_PAD bytes to the memory
- * request, which may push the actual request above PAGE_SIZE
- * in that case, we need to iterate one more time to make sure
- * we get the memory request under PAGE_SIZE
- */
- if (sz + NET_IP_ALIGN + len + NET_SKB_PAD <= PAGE_SIZE) {
- pr_err("%s: allocation failed\n", __func__);
- mutex_unlock(&sdio_mux_lock);
- return;
- }
- sz /= 2;
- } while (1);
-
- skb_reserve(skb_mux, NET_IP_ALIGN + len);
- ptr = skb_put(skb_mux, sz);
-
- /* half second wakelock is fine? */
- wake_lock_timeout(&sdio_mux_ch_wakelock, HZ / 2);
- rc = sdio_read(sdio_mux_ch, ptr, sz);
- DBG("%s: read %d\n", __func__, rc);
- if (rc) {
- pr_err("%s: sdio read failed %d\n", __func__, rc);
- dev_kfree_skb_any(skb_mux);
- mutex_unlock(&sdio_mux_lock);
- queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
- return;
- }
- mutex_unlock(&sdio_mux_lock);
-
- DBG_INC_READ_CNT(sz);
- DBG("%s: head %p data %p tail %p end %p len %d\n", __func__,
- skb_mux->head, skb_mux->data, skb_mux->tail,
- skb_mux->end, skb_mux->len);
-
- /* move to a separate function */
- /* probably do skb_pull instead of pointer adjustment */
- hdr = handle_sdio_partial_pkt(skb_mux);
- while ((void *)hdr < (void *)skb_mux->tail) {
-
- if (((void *)hdr + sizeof(*hdr)) > (void *)skb_mux->tail) {
- /* handle partial header */
- sdio_mux_save_partial_pkt(hdr, skb_mux);
- break;
- }
-
- if (hdr->magic_num != SDIO_MUX_HDR_MAGIC_NO) {
- pr_err("%s: packet error\n", __func__);
- break;
- }
-
- hdr = handle_sdio_mux_command(hdr, skb_mux);
- }
- dev_kfree_skb_any(skb_mux);
-
- DBG("%s: read done\n", __func__);
- queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
-}
-
-static int sdio_mux_write(struct sk_buff *skb)
-{
- int rc, sz;
-
- mutex_lock(&sdio_mux_lock);
- sz = sdio_write_avail(sdio_mux_ch);
- DBG("%s: avail %d len %d\n", __func__, sz, skb->len);
- if (skb->len <= sz) {
- rc = sdio_write(sdio_mux_ch, skb->data, skb->len);
- DBG("%s: write returned %d\n", __func__, rc);
- if (rc == 0)
- DBG_INC_WRITE_CNT(skb->len);
- } else
- rc = -ENOMEM;
-
- mutex_unlock(&sdio_mux_lock);
- return rc;
-}
-
-static int sdio_mux_write_cmd(void *data, uint32_t len)
-{
- int avail, rc;
- for (;;) {
- mutex_lock(&sdio_mux_lock);
- avail = sdio_write_avail(sdio_mux_ch);
- DBG("%s: avail %d len %d\n", __func__, avail, len);
- if (avail >= len) {
- rc = sdio_write(sdio_mux_ch, data, len);
- DBG("%s: write returned %d\n", __func__, rc);
- if (!rc) {
- DBG_INC_WRITE_CNT(len);
- break;
- }
- }
- mutex_unlock(&sdio_mux_lock);
- msleep(250);
- }
- mutex_unlock(&sdio_mux_lock);
- return 0;
-}
-
-static void sdio_mux_send_open_cmd(uint32_t id)
-{
- struct sdio_mux_hdr hdr = {
- .magic_num = SDIO_MUX_HDR_MAGIC_NO,
- .cmd = SDIO_MUX_HDR_CMD_OPEN,
- .reserved = 0,
- .ch_id = id,
- .pkt_len = 0,
- .pad_len = 0
- };
-
- sdio_mux_write_cmd((void *)&hdr, sizeof(hdr));
-}
-
-static void sdio_mux_write_data(struct work_struct *work)
-{
- int rc, reschedule = 0;
- int notify = 0;
- struct sk_buff *skb;
- unsigned long flags;
- int avail;
- int ch_id;
-
- spin_lock_irqsave(&sdio_mux_write_lock, flags);
- while ((skb = __skb_dequeue(&sdio_mux_write_pool))) {
- ch_id = ((struct sdio_mux_hdr *)skb->data)->ch_id;
-
- avail = sdio_write_avail(sdio_mux_ch);
- if (avail < skb->len) {
- /* we may have to wait for write avail
- * notification from sdio al
- */
- DBG("%s: sdio_write_avail(%d) < skb->len(%d)\n",
- __func__, avail, skb->len);
-
- reschedule = 1;
- break;
- }
- spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
- rc = sdio_mux_write(skb);
- spin_lock_irqsave(&sdio_mux_write_lock, flags);
- if (rc == 0) {
-
- spin_lock(&sdio_ch[ch_id].lock);
- sdio_ch[ch_id].num_tx_pkts--;
- spin_unlock(&sdio_ch[ch_id].lock);
-
- if (sdio_ch[ch_id].write_done)
- sdio_ch[ch_id].write_done(
- sdio_ch[ch_id].priv, skb);
- else
- dev_kfree_skb_any(skb);
- } else if (rc == -EAGAIN || rc == -ENOMEM) {
- /* recoverable error - retry again later */
- reschedule = 1;
- break;
- } else if (rc == -ENODEV) {
- /*
- * sdio_al suffered some kind of fatal error
- * prevent future writes and clean up pending ones
- */
- fatal_error = 1;
- do {
- ch_id = ((struct sdio_mux_hdr *)
- skb->data)->ch_id;
- spin_lock(&sdio_ch[ch_id].lock);
- sdio_ch[ch_id].num_tx_pkts--;
- spin_unlock(&sdio_ch[ch_id].lock);
- dev_kfree_skb_any(skb);
- } while ((skb = __skb_dequeue(&sdio_mux_write_pool)));
- spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
- return;
- } else {
- /* unknown error condition - drop the
- * skb and reschedule for the
- * other skb's
- */
- pr_err("%s: sdio_mux_write error %d"
- " for ch %d, skb=%p\n",
- __func__, rc, ch_id, skb);
- notify = 1;
- break;
- }
- }
-
- if (reschedule) {
- if (sdio_ch_is_in_reset(ch_id)) {
- notify = 1;
- } else {
- __skb_queue_head(&sdio_mux_write_pool, skb);
- queue_delayed_work(sdio_mux_workqueue,
- &delayed_work_sdio_mux_write,
- msecs_to_jiffies(250)
- );
- }
- }
-
- if (notify) {
- spin_lock(&sdio_ch[ch_id].lock);
- sdio_ch[ch_id].num_tx_pkts--;
- spin_unlock(&sdio_ch[ch_id].lock);
-
- if (sdio_ch[ch_id].write_done)
- sdio_ch[ch_id].write_done(
- sdio_ch[ch_id].priv, skb);
- else
- dev_kfree_skb_any(skb);
- }
- spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
-}
-
-int msm_sdio_is_channel_in_reset(uint32_t id)
-{
- int rc = 0;
-
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
-
- if (sdio_ch_is_in_reset(id))
- rc = 1;
-
- return rc;
-}
-
-int msm_sdio_dmux_write(uint32_t id, struct sk_buff *skb)
-{
- int rc = 0;
- struct sdio_mux_hdr *hdr;
- unsigned long flags;
- struct sk_buff *new_skb;
-
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
- if (!skb)
- return -EINVAL;
- if (!sdio_mux_initialized)
- return -ENODEV;
- if (fatal_error)
- return -ENODEV;
-
- DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len);
- spin_lock_irqsave(&sdio_ch[id].lock, flags);
- if (sdio_ch_is_in_reset(id)) {
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
- pr_err("%s: port is in reset: %d\n", __func__,
- sdio_ch[id].status);
- return -ENETRESET;
- }
- if (!sdio_ch_is_local_open(id)) {
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
- pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
- return -ENODEV;
- }
- if (sdio_ch[id].use_wm &&
- (sdio_ch[id].num_tx_pkts >= HIGH_WATERMARK)) {
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
- pr_err("%s: watermark exceeded: %d\n", __func__, id);
- return -EAGAIN;
- }
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
- spin_lock_irqsave(&sdio_mux_write_lock, flags);
- /* if skb do not have any tailroom for padding,
- copy the skb into a new expanded skb */
- if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) {
- /* revisit, probably dev_alloc_skb and memcpy is effecient */
- new_skb = skb_copy_expand(skb, skb_headroom(skb),
- 4 - (skb->len & 0x3), GFP_ATOMIC);
- if (new_skb == NULL) {
- pr_err("%s: cannot allocate skb\n", __func__);
- rc = -ENOMEM;
- goto write_done;
- }
- dev_kfree_skb_any(skb);
- skb = new_skb;
- DBG_INC_WRITE_CPY(skb->len);
- }
-
- hdr = (struct sdio_mux_hdr *)skb_push(skb, sizeof(struct sdio_mux_hdr));
-
- /* caller should allocate for hdr and padding
- hdr is fine, padding is tricky */
- hdr->magic_num = SDIO_MUX_HDR_MAGIC_NO;
- hdr->cmd = SDIO_MUX_HDR_CMD_DATA;
- hdr->reserved = 0;
- hdr->ch_id = id;
- hdr->pkt_len = skb->len - sizeof(struct sdio_mux_hdr);
- if (skb->len & 0x3)
- skb_put(skb, 4 - (skb->len & 0x3));
-
- hdr->pad_len = skb->len - (sizeof(struct sdio_mux_hdr) + hdr->pkt_len);
-
- DBG("%s: data %p, tail %p skb len %d pkt len %d pad len %d\n",
- __func__, skb->data, skb->tail, skb->len,
- hdr->pkt_len, hdr->pad_len);
- __skb_queue_tail(&sdio_mux_write_pool, skb);
-
- spin_lock(&sdio_ch[id].lock);
- sdio_ch[id].num_tx_pkts++;
- spin_unlock(&sdio_ch[id].lock);
-
- queue_work(sdio_mux_workqueue, &work_sdio_mux_write);
-
-write_done:
- spin_unlock_irqrestore(&sdio_mux_write_lock, flags);
- return rc;
-}
-
-int msm_sdio_dmux_open(uint32_t id, void *priv,
- void (*receive_cb)(void *, struct sk_buff *),
- void (*write_done)(void *, struct sk_buff *))
-{
- unsigned long flags;
-
- DBG("%s: opening ch %d\n", __func__, id);
- if (!sdio_mux_initialized)
- return -ENODEV;
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
-
- spin_lock_irqsave(&sdio_ch[id].lock, flags);
- if (sdio_ch_is_local_open(id)) {
- pr_info("%s: Already opened %d\n", __func__, id);
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
- goto open_done;
- }
-
- sdio_ch[id].receive_cb = receive_cb;
- sdio_ch[id].write_done = write_done;
- sdio_ch[id].priv = priv;
- sdio_ch[id].status |= SDIO_CH_LOCAL_OPEN;
- sdio_ch[id].num_tx_pkts = 0;
- sdio_ch[id].use_wm = 0;
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
- sdio_mux_send_open_cmd(id);
-
-open_done:
- pr_info("%s: opened ch %d\n", __func__, id);
- return 0;
-}
-
-int msm_sdio_dmux_close(uint32_t id)
-{
- struct sdio_mux_hdr hdr;
- unsigned long flags;
-
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
- DBG("%s: closing ch %d\n", __func__, id);
- if (!sdio_mux_initialized)
- return -ENODEV;
- spin_lock_irqsave(&sdio_ch[id].lock, flags);
-
- sdio_ch[id].receive_cb = NULL;
- sdio_ch[id].priv = NULL;
- sdio_ch[id].status &= ~SDIO_CH_LOCAL_OPEN;
- sdio_ch[id].status &= ~SDIO_CH_IN_RESET;
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
- hdr.magic_num = SDIO_MUX_HDR_MAGIC_NO;
- hdr.cmd = SDIO_MUX_HDR_CMD_CLOSE;
- hdr.reserved = 0;
- hdr.ch_id = id;
- hdr.pkt_len = 0;
- hdr.pad_len = 0;
-
- sdio_mux_write_cmd((void *)&hdr, sizeof(hdr));
-
- pr_info("%s: closed ch %d\n", __func__, id);
- return 0;
-}
-
-static void sdio_mux_notify(void *_dev, unsigned event)
-{
- DBG("%s: event %d notified\n", __func__, event);
-
- /* write avail may not be enouogh for a packet, but should be fine */
- if ((event == SDIO_EVENT_DATA_WRITE_AVAIL) &&
- sdio_write_avail(sdio_mux_ch))
- queue_work(sdio_mux_workqueue, &work_sdio_mux_write);
-
- if ((event == SDIO_EVENT_DATA_READ_AVAIL) &&
- sdio_read_avail(sdio_mux_ch))
- queue_work(sdio_mux_workqueue, &work_sdio_mux_read);
-}
-
-int msm_sdio_dmux_is_ch_full(uint32_t id)
-{
- unsigned long flags;
- int ret;
-
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
-
- spin_lock_irqsave(&sdio_ch[id].lock, flags);
- sdio_ch[id].use_wm = 1;
- ret = sdio_ch[id].num_tx_pkts >= HIGH_WATERMARK;
- DBG("%s: ch %d num tx pkts=%d, HWM=%d\n", __func__,
- id, sdio_ch[id].num_tx_pkts, ret);
- if (!sdio_ch_is_local_open(id)) {
- ret = -ENODEV;
- pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
- }
- spin_unlock_irqrestore(&sdio_ch[id].lock, flags);
-
- return ret;
-}
-
-int msm_sdio_dmux_is_ch_low(uint32_t id)
-{
- int ret;
-
- if (id >= SDIO_DMUX_NUM_CHANNELS)
- return -EINVAL;
-
- sdio_ch[id].use_wm = 1;
- ret = sdio_ch[id].num_tx_pkts <= LOW_WATERMARK;
- DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__,
- id, sdio_ch[id].num_tx_pkts, ret);
- if (!sdio_ch_is_local_open(id)) {
- ret = -ENODEV;
- pr_err("%s: port not open: %d\n", __func__, sdio_ch[id].status);
- }
-
- return ret;
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-static int debug_tbl(char *buf, int max)
-{
- int i = 0;
- int j;
-
- for (j = 0; j < SDIO_DMUX_NUM_CHANNELS; ++j) {
- i += scnprintf(buf + i, max - i,
- "ch%02d local open=%s remote open=%s\n",
- j, sdio_ch_is_local_open(j) ? "Y" : "N",
- sdio_ch_is_remote_open(j) ? "Y" : "N");
- }
-
- return i;
-}
-
-#define DEBUG_BUFMAX 4096
-static char debug_buffer[DEBUG_BUFMAX];
-
-static ssize_t debug_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- int (*fill)(char *buf, int max) = file->private_data;
- int bsize = fill(debug_buffer, DEBUG_BUFMAX);
- return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
-}
-
-static int debug_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-
-static const struct file_operations debug_ops = {
- .read = debug_read,
- .open = debug_open,
-};
-
-static void debug_create(const char *name, mode_t mode,
- struct dentry *dent,
- int (*fill)(char *buf, int max))
-{
- debugfs_create_file(name, mode, dent, fill, &debug_ops);
-}
-
-#endif
-
-static int sdio_dmux_probe(struct platform_device *pdev)
-{
- int rc;
-
- DBG("%s probe called\n", __func__);
-
- if (!sdio_mux_initialized) {
- sdio_mux_workqueue = create_singlethread_workqueue("sdio_dmux");
- if (!sdio_mux_workqueue)
- return -ENOMEM;
-
- skb_queue_head_init(&sdio_mux_write_pool);
- spin_lock_init(&sdio_mux_write_lock);
-
- for (rc = 0; rc < SDIO_DMUX_NUM_CHANNELS; ++rc)
- spin_lock_init(&sdio_ch[rc].lock);
-
-
- wake_lock_init(&sdio_mux_ch_wakelock, WAKE_LOCK_SUSPEND,
- "sdio_dmux");
- }
-
- rc = sdio_open("SDIO_RMNT", &sdio_mux_ch, NULL, sdio_mux_notify);
- if (rc < 0) {
- pr_err("%s: sido open failed %d\n", __func__, rc);
- wake_lock_destroy(&sdio_mux_ch_wakelock);
- destroy_workqueue(sdio_mux_workqueue);
- sdio_mux_initialized = 0;
- return rc;
- }
-
- fatal_error = 0;
- sdio_mux_initialized = 1;
- return 0;
-}
-
-static int sdio_dmux_remove(struct platform_device *pdev)
-{
- int i;
- unsigned long ch_lock_flags;
- unsigned long write_lock_flags;
- struct sk_buff *skb;
-
- DBG("%s remove called\n", __func__);
- if (!sdio_mux_initialized)
- return 0;
-
- /* set reset state for any open channels */
- for (i = 0; i < SDIO_DMUX_NUM_CHANNELS; ++i) {
- spin_lock_irqsave(&sdio_ch[i].lock, ch_lock_flags);
- if (sdio_ch_is_open(i)) {
- sdio_ch[i].status |= SDIO_CH_IN_RESET;
- sdio_ch[i].status &= ~SDIO_CH_REMOTE_OPEN;
-
- /* notify client so it can update its status */
- if (sdio_ch[i].receive_cb)
- sdio_ch[i].receive_cb(
- sdio_ch[i].priv, NULL);
- }
- spin_unlock_irqrestore(&sdio_ch[i].lock, ch_lock_flags);
- }
-
- /* cancel any pending writes */
- spin_lock_irqsave(&sdio_mux_write_lock, write_lock_flags);
- while ((skb = __skb_dequeue(&sdio_mux_write_pool))) {
- i = ((struct sdio_mux_hdr *)skb->data)->ch_id;
- if (sdio_ch[i].write_done)
- sdio_ch[i].write_done(
- sdio_ch[i].priv, skb);
- else
- dev_kfree_skb_any(skb);
- }
- spin_unlock_irqrestore(&sdio_mux_write_lock,
- write_lock_flags);
-
- return 0;
-}
-
-static struct platform_driver sdio_dmux_driver = {
- .probe = sdio_dmux_probe,
- .remove = sdio_dmux_remove,
- .driver = {
- .name = "SDIO_RMNT",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sdio_dmux_init(void)
-{
-#ifdef CONFIG_DEBUG_FS
- struct dentry *dent;
-
- dent = debugfs_create_dir("sdio_dmux", 0);
- if (!IS_ERR(dent))
- debug_create("tbl", 0444, dent, debug_tbl);
-#endif
- return platform_driver_register(&sdio_dmux_driver);
-}
-
-module_init(sdio_dmux_init);
-MODULE_DESCRIPTION("MSM SDIO DMUX");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_smem.c b/arch/arm/mach-msm/sdio_smem.c
deleted file mode 100644
index edc0d23..0000000
--- a/arch/arm/mach-msm/sdio_smem.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/module.h>
-#include <mach/sdio_al.h>
-#include <mach/sdio_smem.h>
-
-static void sdio_smem_read(struct work_struct *work);
-
-static struct sdio_channel *channel;
-static struct workqueue_struct *workq;
-static DECLARE_WORK(work_read, sdio_smem_read);
-static DECLARE_WAIT_QUEUE_HEAD(waitq);
-static int bytes_avail;
-static int sdio_ch_opened;
-
-static void sdio_smem_release(struct device *dev)
-{
- pr_debug("sdio smem released\n");
-}
-
-static struct sdio_smem_client client;
-
-static void sdio_smem_read(struct work_struct *work)
-{
- int err;
- int read_avail;
- char *data = client.buf;
-
- if (!sdio_ch_opened)
- return;
-
- read_avail = sdio_read_avail(channel);
- if (read_avail > bytes_avail ||
- read_avail < 0) {
- pr_err("Error: read_avail=%d bytes_avail=%d\n",
- read_avail, bytes_avail);
- goto read_err;
- }
-
- if (read_avail == 0)
- return;
-
- err = sdio_read(channel,
- &data[client.size - bytes_avail],
- read_avail);
- if (err) {
- pr_err("sdio_read error (%d)", err);
- goto read_err;
- }
-
- bytes_avail -= read_avail;
- pr_debug("read %d bytes (bytes_avail = %d)\n",
- read_avail, bytes_avail);
-
- if (!bytes_avail) {
- bytes_avail = client.size;
- err = client.cb_func(SDIO_SMEM_EVENT_READ_DONE);
- }
- if (err)
- pr_err("error (%d) on callback\n", err);
-
- return;
-
-read_err:
- if (sdio_ch_opened)
- client.cb_func(SDIO_SMEM_EVENT_READ_ERR);
- return;
-}
-
-static void sdio_smem_notify(void *priv, unsigned event)
-{
- pr_debug("%d event received\n", event);
-
- if (event == SDIO_EVENT_DATA_READ_AVAIL ||
- event == SDIO_EVENT_DATA_WRITE_AVAIL)
- queue_work(workq, &work_read);
-}
-
-int sdio_smem_register_client(void)
-{
- int err = 0;
-
- if (!client.buf || !client.size || !client.cb_func)
- return -EINVAL;
-
- pr_debug("buf = %p\n", client.buf);
- pr_debug("size = 0x%x\n", client.size);
-
- bytes_avail = client.size;
- workq = create_singlethread_workqueue("sdio_smem");
- if (!workq)
- return -ENOMEM;
-
- sdio_ch_opened = 1;
- err = sdio_open("SDIO_SMEM", &channel, NULL, sdio_smem_notify);
- if (err) {
- sdio_ch_opened = 0;
- pr_err("sdio_open error (%d)\n", err);
- destroy_workqueue(workq);
- return err;
- }
- pr_debug("SDIO SMEM channel opened\n");
- return err;
-}
-
-int sdio_smem_unregister_client(void)
-{
- int err = 0;
-
- sdio_ch_opened = 0;
- err = sdio_close(channel);
- if (err) {
- pr_err("sdio_close error (%d)\n", err);
- return err;
- }
- pr_debug("SDIO SMEM channel closed\n");
- flush_workqueue(workq);
- destroy_workqueue(workq);
- bytes_avail = 0;
- client.buf = NULL;
- client.cb_func = NULL;
- client.size = 0;
-
- return 0;
-}
-
-static int sdio_smem_probe(struct platform_device *pdev)
-{
- client.plat_dev.name = "SDIO_SMEM_CLIENT";
- client.plat_dev.id = -1;
- client.plat_dev.dev.release = sdio_smem_release;
-
- return platform_device_register(&client.plat_dev);
-}
-
-static int sdio_smem_remove(struct platform_device *pdev)
-{
- platform_device_unregister(&client.plat_dev);
- memset(&client, 0, sizeof(client));
- sdio_ch_opened = 0;
- return 0;
-}
-static struct platform_driver sdio_smem_drv = {
- .probe = sdio_smem_probe,
- .remove = sdio_smem_remove,
- .driver = {
- .name = "SDIO_SMEM",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init sdio_smem_init(void)
-{
- return platform_driver_register(&sdio_smem_drv);
-};
-
-module_init(sdio_smem_init);
-
-MODULE_DESCRIPTION("SDIO SMEM");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sdio_tty.c b/arch/arm/mach-msm/sdio_tty.c
deleted file mode 100644
index c4b7673..0000000
--- a/arch/arm/mach-msm/sdio_tty.c
+++ /dev/null
@@ -1,824 +0,0 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <mach/sdio_al.h>
-
-#define INPUT_SPEED 4800
-#define OUTPUT_SPEED 4800
-#define SDIO_TTY_MODULE_NAME "sdio_tty"
-#define SDIO_TTY_MAX_PACKET_SIZE 4096
-#define MAX_SDIO_TTY_DRV 1
-#define MAX_SDIO_TTY_DEVS 2
-#define MAX_SDIO_TTY_DEV_NAME_SIZE 25
-
-/* Configurations per channel device */
-/* CSVT */
-#define SDIO_TTY_CSVT_DEV "sdio_tty_csvt_0"
-#define SDIO_TTY_CSVT_TEST_DEV "sdio_tty_csvt_test_0"
-#define SDIO_TTY_CH_CSVT "SDIO_CSVT"
-
-enum sdio_tty_state {
- TTY_INITIAL = 0,
- TTY_REGISTERED = 1,
- TTY_OPENED = 2,
- TTY_CLOSED = 3,
-};
-
-enum sdio_tty_devices {
- SDIO_CSVT,
- SDIO_CSVT_TEST_APP,
-};
-
-static const struct platform_device_id sdio_tty_id_table[] = {
- { "SDIO_CSVT", SDIO_CSVT },
- { "SDIO_CSVT_TEST_APP", SDIO_CSVT_TEST_APP },
- { },
-};
-MODULE_DEVICE_TABLE(platform, sdio_tty_id_table);
-
-struct sdio_tty {
- struct sdio_channel *ch;
- char *sdio_ch_name;
- char tty_dev_name[MAX_SDIO_TTY_DEV_NAME_SIZE];
- int device_id;
- struct workqueue_struct *workq;
- struct work_struct work_read;
- wait_queue_head_t waitq;
- struct tty_driver *tty_drv;
- struct tty_struct *tty_str;
- int debug_msg_on;
- char *read_buf;
- enum sdio_tty_state sdio_tty_state;
- int is_sdio_open;
- int tty_open_count;
- int total_rx;
- int total_tx;
-};
-
-static struct sdio_tty *sdio_tty[MAX_SDIO_TTY_DEVS];
-
-#ifdef CONFIG_DEBUG_FS
-struct dentry *sdio_tty_debug_root;
-struct dentry *sdio_tty_debug_info;
-#endif
-
-#define DEBUG_MSG(sdio_tty_drv, x...) if (sdio_tty_drv->debug_msg_on) pr_info(x)
-
-/*
- * Enable sdio_tty debug messages
- * By default the sdio_tty debug messages are turned off
- */
-static int csvt_debug_msg_on;
-module_param(csvt_debug_msg_on, int, 0);
-
-static void sdio_tty_read(struct work_struct *work)
-{
- int ret = 0;
- int read_avail = 0;
- int left = 0;
- int total_push = 0;
- int num_push = 0;
- struct sdio_tty *sdio_tty_drv = NULL;
-
- sdio_tty_drv = container_of(work, struct sdio_tty, work_read);
-
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty", __func__);
- return ;
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
- return;
- }
-
- if (!sdio_tty_drv->read_buf) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL read_buf for dev %s",
- __func__, sdio_tty_drv->tty_dev_name);
- return;
- }
-
- /* Read the data from the SDIO channel as long as there is available
- data */
- while (1) {
- if (test_bit(TTY_THROTTLED, &sdio_tty_drv->tty_str->flags)) {
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
- ": %s: TTY_THROTTLED bit is set for "
- "dev %s, exit", __func__,
- sdio_tty_drv->tty_dev_name);
- return;
- }
-
- total_push = 0;
- read_avail = sdio_read_avail(sdio_tty_drv->ch);
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
- ": %s: read_avail is %d for dev %s", __func__,
- read_avail, sdio_tty_drv->tty_dev_name);
-
- if (read_avail == 0) {
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
- ": %s: read_avail is 0 for dev %s",
- __func__, sdio_tty_drv->tty_dev_name);
- return;
- }
-
- if (read_avail > SDIO_TTY_MAX_PACKET_SIZE) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: read_avail(%d) is "
- "bigger than SDIO_TTY_MAX_PACKET_SIZE(%d) "
- "for dev %s", __func__, read_avail,
- SDIO_TTY_MAX_PACKET_SIZE,
- sdio_tty_drv->tty_dev_name);
- return;
- }
-
- ret = sdio_read(sdio_tty_drv->ch,
- sdio_tty_drv->read_buf,
- read_avail);
- if (ret < 0) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_read error(%d) "
- "for dev %s", __func__, ret,
- sdio_tty_drv->tty_dev_name);
- return;
- }
-
- left = read_avail;
- do {
- num_push = tty_insert_flip_string(
- sdio_tty_drv->tty_str,
- sdio_tty_drv->read_buf+total_push,
- left);
- total_push += num_push;
- left -= num_push;
- tty_flip_buffer_push(sdio_tty_drv->tty_str);
- } while (left != 0);
-
- if (total_push != read_avail) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: failed, total_push"
- "(%d) != read_avail(%d) for dev %s\n",
- __func__, total_push, read_avail,
- sdio_tty_drv->tty_dev_name);
- }
-
- tty_flip_buffer_push(sdio_tty_drv->tty_str);
- sdio_tty_drv->total_rx += read_avail;
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Rx: %d, "
- "Total Rx = %d bytes for dev %s", __func__,
- read_avail, sdio_tty_drv->total_rx,
- sdio_tty_drv->tty_dev_name);
- }
-}
-
-/**
- * sdio_tty_write_room
- *
- * This is the write_room function of the tty driver.
- *
- * @tty: pointer to tty struct.
- * @return free bytes for write.
- *
- */
-static int sdio_tty_write_room(struct tty_struct *tty)
-{
- int write_avail = 0;
- struct sdio_tty *sdio_tty_drv = NULL;
-
- if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
- return -ENODEV;
- }
- sdio_tty_drv = tty->driver_data;
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return -ENODEV;
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
- return -EPERM;
- }
-
- write_avail = sdio_write_avail(sdio_tty_drv->ch);
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: write_avail=%d "
- "for dev %s", __func__, write_avail,
- sdio_tty_drv->tty_dev_name);
-
- return write_avail;
-}
-
-/**
- * sdio_tty_write_callback
- * this is the write callback of the tty driver.
- *
- * @tty: pointer to tty struct.
- * @buf: buffer to write from.
- * @count: number of bytes to write.
- * @return bytes written or negative value on error.
- *
- * if destination buffer has not enough room for the incoming
- * data, writes the possible amount of bytes .
- */
-static int sdio_tty_write_callback(struct tty_struct *tty,
- const unsigned char *buf, int count)
-{
- int write_avail = 0;
- int len = count;
- int ret = 0;
- struct sdio_tty *sdio_tty_drv = NULL;
-
- if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
- return -ENODEV;
- }
- sdio_tty_drv = tty->driver_data;
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return -ENODEV;
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
- return -EPERM;
- }
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Write Callback "
- "called with %d bytes for dev %s\n", __func__, count,
- sdio_tty_drv->tty_dev_name);
- write_avail = sdio_write_avail(sdio_tty_drv->ch);
- if (write_avail == 0) {
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
- "write_avail is 0 for dev %s\n",
- __func__, sdio_tty_drv->tty_dev_name);
- return 0;
- }
- if (write_avail > SDIO_TTY_MAX_PACKET_SIZE) {
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
- "write_avail(%d) is bigger than max packet "
- "size(%d) for dev %s, setting to "
- "max_packet_size\n", __func__, write_avail,
- SDIO_TTY_MAX_PACKET_SIZE,
- sdio_tty_drv->tty_dev_name);
- write_avail = SDIO_TTY_MAX_PACKET_SIZE;
- }
- if (write_avail < count) {
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: "
- "write_avail(%d) is smaller than required(%d) "
- "for dev %s, writing only %d bytes\n",
- __func__, write_avail, count,
- sdio_tty_drv->tty_dev_name, write_avail);
- len = write_avail;
- }
- ret = sdio_write(sdio_tty_drv->ch, buf, len);
- if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_write failed for "
- "dev %s, ret=%d\n", __func__,
- sdio_tty_drv->tty_dev_name, ret);
- return 0;
- }
-
- sdio_tty_drv->total_tx += len;
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Tx: %d, "
- "Total Tx = %d for dev %s", __func__, len,
- sdio_tty_drv->total_tx, sdio_tty_drv->tty_dev_name);
- return len;
-}
-
-static void sdio_tty_notify(void *priv, unsigned event)
-{
- struct sdio_tty *sdio_tty_drv = priv;
-
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
- return;
- }
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: event %d "
- "received for dev %s\n", __func__, event,
- sdio_tty_drv->tty_dev_name);
-
- if (event == SDIO_EVENT_DATA_READ_AVAIL)
- queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
-}
-
-/**
- * sdio_tty_open
- * This is the open callback of the tty driver. it opens
- * the sdio channel, and creates the workqueue.
- *
- * @tty: a pointer to the tty struct.
- * @file: file descriptor.
- * @return 0 on success or negative value on error.
- */
-static int sdio_tty_open(struct tty_struct *tty, struct file *file)
-{
- int ret = 0;
- int i = 0;
- struct sdio_tty *sdio_tty_drv = NULL;
-
- if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
- return -ENODEV;
- }
-
- for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
- if (sdio_tty[i] == NULL)
- continue;
- if (!strncmp(sdio_tty[i]->tty_dev_name, tty->name,
- MAX_SDIO_TTY_DEV_NAME_SIZE)) {
- sdio_tty_drv = sdio_tty[i];
- break;
- }
- }
-
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return -ENODEV;
- }
-
- sdio_tty_drv->tty_open_count++;
- if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) is already open",
- __func__, sdio_tty_drv->tty_dev_name);
- return -EBUSY;
- }
-
- tty->driver_data = sdio_tty_drv;
-
- sdio_tty_drv->tty_str = tty;
- sdio_tty_drv->tty_str->low_latency = 1;
- sdio_tty_drv->tty_str->icanon = 0;
- set_bit(TTY_NO_WRITE_SPLIT, &sdio_tty_drv->tty_str->flags);
-
- sdio_tty_drv->read_buf = kzalloc(SDIO_TTY_MAX_PACKET_SIZE, GFP_KERNEL);
- if (sdio_tty_drv->read_buf == NULL) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate read_buf "
- "for dev %s", __func__, sdio_tty_drv->tty_dev_name);
- return -ENOMEM;
- }
-
- sdio_tty_drv->workq = create_singlethread_workqueue("sdio_tty_read");
- if (!sdio_tty_drv->workq) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to create workq "
- "for dev %s", __func__, sdio_tty_drv->tty_dev_name);
- return -ENOMEM;
- }
-
- if (!sdio_tty_drv->is_sdio_open) {
- ret = sdio_open(sdio_tty_drv->sdio_ch_name, &sdio_tty_drv->ch,
- sdio_tty_drv, sdio_tty_notify);
- if (ret < 0) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_open err=%d "
- "for dev %s\n", __func__, ret,
- sdio_tty_drv->tty_dev_name);
- destroy_workqueue(sdio_tty_drv->workq);
- return ret;
- }
-
- pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel(%s) "
- "opened\n", __func__, sdio_tty_drv->sdio_ch_name);
-
- sdio_tty_drv->is_sdio_open = 1;
- } else {
- /* If SDIO channel is already open try to read the data
- * from the modem
- */
- queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
-
- }
-
- sdio_tty_drv->sdio_tty_state = TTY_OPENED;
-
- pr_info(SDIO_TTY_MODULE_NAME ": %s: TTY device(%s) opened\n",
- __func__, sdio_tty_drv->tty_dev_name);
-
- return ret;
-}
-
-/**
- * sdio_tty_close
- * This is the close callback of the tty driver. it requests
- * the main thread to exit, and waits for notification of it.
- * it also de-allocates the buffers, and unregisters the tty
- * driver and device.
- *
- * @tty: a pointer to the tty struct.
- * @file: file descriptor.
- * @return None.
- */
-static void sdio_tty_close(struct tty_struct *tty, struct file *file)
-{
- struct sdio_tty *sdio_tty_drv = NULL;
-
- if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
- return;
- }
- sdio_tty_drv = tty->driver_data;
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return;
- }
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: trying to close a "
- "TTY device that was not opened\n", __func__);
- return;
- }
- if (--sdio_tty_drv->tty_open_count != 0)
- return;
-
- flush_workqueue(sdio_tty_drv->workq);
- destroy_workqueue(sdio_tty_drv->workq);
-
- kfree(sdio_tty_drv->read_buf);
- sdio_tty_drv->read_buf = NULL;
-
- sdio_tty_drv->sdio_tty_state = TTY_CLOSED;
-
- pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY device(%s) closed\n",
- __func__, sdio_tty_drv->tty_dev_name);
-}
-
-static void sdio_tty_unthrottle(struct tty_struct *tty)
-{
- struct sdio_tty *sdio_tty_drv = NULL;
-
- if (!tty) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL tty", __func__);
- return;
- }
- sdio_tty_drv = tty->driver_data;
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return;
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_OPENED) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_state = %d",
- __func__, sdio_tty_drv->sdio_tty_state);
- return;
- }
-
- queue_work(sdio_tty_drv->workq, &sdio_tty_drv->work_read);
- return;
-}
-
-static const struct tty_operations sdio_tty_ops = {
- .open = sdio_tty_open,
- .close = sdio_tty_close,
- .write = sdio_tty_write_callback,
- .write_room = sdio_tty_write_room,
- .unthrottle = sdio_tty_unthrottle,
-};
-
-int sdio_tty_init_tty(char *tty_name, char *sdio_ch_name,
- enum sdio_tty_devices device_id, int debug_msg_on)
-{
- int ret = 0;
- int i = 0;
- struct device *tty_dev = NULL;
- struct sdio_tty *sdio_tty_drv = NULL;
-
- sdio_tty_drv = kzalloc(sizeof(struct sdio_tty), GFP_KERNEL);
- if (sdio_tty_drv == NULL) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: failed to allocate sdio_tty "
- "for dev %s", __func__, tty_name);
- return -ENOMEM;
- }
-
- for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
- if (sdio_tty[i] == NULL) {
- sdio_tty[i] = sdio_tty_drv;
- break;
- }
- }
-
- if (i == MAX_SDIO_TTY_DEVS) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: tty dev(%s) creation failed,"
- " max limit(%d) reached.", __func__, tty_name,
- MAX_SDIO_TTY_DEVS);
- kfree(sdio_tty_drv);
- return -ENODEV;
- }
-
- snprintf(sdio_tty_drv->tty_dev_name, MAX_SDIO_TTY_DEV_NAME_SIZE,
- "%s%d", tty_name, 0);
- sdio_tty_drv->sdio_ch_name = sdio_ch_name;
- sdio_tty_drv->device_id = device_id;
- pr_info(SDIO_TTY_MODULE_NAME ": %s: dev=%s, id=%d, channel=%s\n",
- __func__, sdio_tty_drv->tty_dev_name, sdio_tty_drv->device_id,
- sdio_tty_drv->sdio_ch_name);
-
- INIT_WORK(&sdio_tty_drv->work_read, sdio_tty_read);
-
- sdio_tty_drv->tty_drv = alloc_tty_driver(MAX_SDIO_TTY_DRV);
-
- if (!sdio_tty_drv->tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s - tty_drv is NULL for dev %s",
- __func__, sdio_tty_drv->tty_dev_name);
- kfree(sdio_tty_drv);
- return -ENODEV;
- }
-
- sdio_tty_drv->tty_drv->name = tty_name;
- sdio_tty_drv->tty_drv->owner = THIS_MODULE;
- sdio_tty_drv->tty_drv->driver_name = "SDIO_tty";
- /* uses dynamically assigned dev_t values */
- sdio_tty_drv->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
- sdio_tty_drv->tty_drv->subtype = SERIAL_TYPE_NORMAL;
- sdio_tty_drv->tty_drv->flags = TTY_DRIVER_REAL_RAW
- | TTY_DRIVER_DYNAMIC_DEV
- | TTY_DRIVER_RESET_TERMIOS;
-
- /* initializing the tty driver */
- sdio_tty_drv->tty_drv->init_termios = tty_std_termios;
- sdio_tty_drv->tty_drv->init_termios.c_cflag =
- B4800 | CS8 | CREAD | HUPCL | CLOCAL;
- sdio_tty_drv->tty_drv->init_termios.c_ispeed = INPUT_SPEED;
- sdio_tty_drv->tty_drv->init_termios.c_ospeed = OUTPUT_SPEED;
-
- tty_set_operations(sdio_tty_drv->tty_drv, &sdio_tty_ops);
-
- ret = tty_register_driver(sdio_tty_drv->tty_drv);
- if (ret) {
- put_tty_driver(sdio_tty_drv->tty_drv);
- pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_driver() "
- "failed for dev %s\n", __func__,
- sdio_tty_drv->tty_dev_name);
-
- sdio_tty_drv->tty_drv = NULL;
- kfree(sdio_tty_drv);
- return -ENODEV;
- }
-
- tty_dev = tty_register_device(sdio_tty_drv->tty_drv, 0, NULL);
- if (IS_ERR(tty_dev)) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: tty_register_device() "
- "failed for dev %s\n", __func__,
- sdio_tty_drv->tty_dev_name);
- tty_unregister_driver(sdio_tty_drv->tty_drv);
- put_tty_driver(sdio_tty_drv->tty_drv);
- kfree(sdio_tty_drv);
- return -ENODEV;
- }
-
- sdio_tty_drv->sdio_tty_state = TTY_REGISTERED;
- if (debug_msg_on) {
- pr_info(SDIO_TTY_MODULE_NAME ": %s: turn on debug msg for %s",
- __func__, sdio_tty_drv->tty_dev_name);
- sdio_tty_drv->debug_msg_on = debug_msg_on;
- }
- return 0;
-}
-
-int sdio_tty_uninit_tty(void *sdio_tty_handle)
-{
- int ret = 0;
- int i = 0;
- struct sdio_tty *sdio_tty_drv = sdio_tty_handle;
-
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return -ENODEV;
- }
- if (sdio_tty_drv->sdio_tty_state == TTY_OPENED) {
- flush_workqueue(sdio_tty_drv->workq);
- destroy_workqueue(sdio_tty_drv->workq);
-
- kfree(sdio_tty_drv->read_buf);
- sdio_tty_drv->read_buf = NULL;
- }
-
- if (sdio_tty_drv->sdio_tty_state != TTY_INITIAL) {
- tty_unregister_device(sdio_tty_drv->tty_drv, 0);
-
- ret = tty_unregister_driver(sdio_tty_drv->tty_drv);
- if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: "
- "tty_unregister_driver() failed for dev %s\n",
- __func__, sdio_tty_drv->tty_dev_name);
- }
- put_tty_driver(sdio_tty_drv->tty_drv);
- sdio_tty_drv->sdio_tty_state = TTY_INITIAL;
- sdio_tty_drv->tty_drv = NULL;
- }
-
- for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
- if (sdio_tty[i] == NULL)
- continue;
- if (sdio_tty[i]->device_id == sdio_tty_drv->device_id) {
- sdio_tty[i] = NULL;
- break;
- }
- }
-
- DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Freeing sdio_tty "
- "structure, dev=%s", __func__,
- sdio_tty_drv->tty_dev_name);
- kfree(sdio_tty_drv);
-
- return 0;
-}
-
-static int sdio_tty_probe(struct platform_device *pdev)
-{
- const struct platform_device_id *id = platform_get_device_id(pdev);
- enum sdio_tty_devices device_id = id->driver_data;
- char *device_name = NULL;
- char *channel_name = NULL;
- int debug_msg_on = 0;
- int ret = 0;
-
- pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
-
- switch (device_id) {
- case SDIO_CSVT:
- device_name = SDIO_TTY_CSVT_DEV;
- channel_name = SDIO_TTY_CH_CSVT;
- debug_msg_on = csvt_debug_msg_on;
- break;
- case SDIO_CSVT_TEST_APP:
- device_name = SDIO_TTY_CSVT_TEST_DEV;
- channel_name = SDIO_TTY_CH_CSVT;
- debug_msg_on = csvt_debug_msg_on;
- break;
- default:
- pr_err(SDIO_TTY_MODULE_NAME ": %s Invalid device:%s, id:%d",
- __func__, pdev->name, device_id);
- ret = -ENODEV;
- break;
- }
-
- if (device_name) {
- ret = sdio_tty_init_tty(device_name, channel_name,
- device_id, debug_msg_on);
- if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_init_tty "
- "failed for dev:%s", __func__, device_name);
- }
- }
- return ret;
-}
-
-static int sdio_tty_remove(struct platform_device *pdev)
-{
- const struct platform_device_id *id = platform_get_device_id(pdev);
- enum sdio_tty_devices device_id = id->driver_data;
- struct sdio_tty *sdio_tty_drv = NULL;
- int i = 0;
- int ret = 0;
-
- pr_debug(SDIO_TTY_MODULE_NAME ": %s for %s", __func__, pdev->name);
-
- for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
- if (sdio_tty[i] == NULL)
- continue;
- if (sdio_tty[i]->device_id == device_id) {
- sdio_tty_drv = sdio_tty[i];
- break;
- }
- }
-
- if (!sdio_tty_drv) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: NULL sdio_tty_drv",
- __func__);
- return -ENODEV;
- }
-
- ret = sdio_tty_uninit_tty(sdio_tty_drv);
- if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: sdio_tty_uninit_tty "
- "failed for %s", __func__, pdev->name);
- }
- return ret;
-}
-
-static struct platform_driver sdio_tty_pdrv = {
- .probe = sdio_tty_probe,
- .remove = sdio_tty_remove,
- .id_table = sdio_tty_id_table,
- .driver = {
- .name = "SDIO_TTY",
- .owner = THIS_MODULE,
- },
-};
-
-#ifdef CONFIG_DEBUG_FS
-void sdio_tty_print_info(void)
-{
- int i = 0;
-
- for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
- if (sdio_tty[i] == NULL)
- continue;
- pr_info(SDIO_TTY_MODULE_NAME ": %s: Total Rx=%d, Tx = %d "
- "for dev %s", __func__, sdio_tty[i]->total_rx,
- sdio_tty[i]->total_tx, sdio_tty[i]->tty_dev_name);
- }
-}
-
-static int tty_debug_info_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t tty_debug_info_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- sdio_tty_print_info();
- return count;
-}
-
-const struct file_operations tty_debug_info_ops = {
- .open = tty_debug_info_open,
- .write = tty_debug_info_write,
-};
-#endif
-
-/*
- * Module Init.
- *
- * Register SDIO TTY driver.
- *
- */
-static int __init sdio_tty_init(void)
-{
- int ret = 0;
-
- ret = platform_driver_register(&sdio_tty_pdrv);
- if (ret) {
- pr_err(SDIO_TTY_MODULE_NAME ": %s: platform_driver_register "
- "failed", __func__);
- }
-#ifdef CONFIG_DEBUG_FS
- else {
- sdio_tty_debug_root = debugfs_create_dir("sdio_tty", NULL);
- if (sdio_tty_debug_root) {
- sdio_tty_debug_info = debugfs_create_file(
- "sdio_tty_debug",
- S_IRUGO | S_IWUGO,
- sdio_tty_debug_root,
- NULL,
- &tty_debug_info_ops);
- }
- }
-#endif
- return ret;
-};
-
-/*
- * Module Exit.
- *
- * Unregister SDIO TTY driver.
- *
- */
-static void __exit sdio_tty_exit(void)
-{
-#ifdef CONFIG_DEBUG_FS
- debugfs_remove(sdio_tty_debug_info);
- debugfs_remove(sdio_tty_debug_root);
-#endif
- platform_driver_unregister(&sdio_tty_pdrv);
-}
-
-module_init(sdio_tty_init);
-module_exit(sdio_tty_exit);
-
-MODULE_DESCRIPTION("SDIO TTY");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Maya Erez <merez@codeaurora.org>");
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index b850cec..feb30c1 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -715,12 +715,12 @@
if (error)
goto out_unregister;
+ klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
- klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);
error = driver_create_file(drv, &driver_attr_uevent);
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 8e68acd..0be61e8 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -91,7 +91,7 @@
int n = -1, err = 0;
VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
- (void __user *)start, len));
+ (void __user *)start, len));
if (err)
goto bail;
VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
@@ -162,8 +162,8 @@
{
struct fastrpc_apps *me = &gfa;
- if (buf->handle) {
- if (buf->virt) {
+ if (!IS_ERR_OR_NULL(buf->handle)) {
+ if (!IS_ERR_OR_NULL(buf->virt)) {
ion_unmap_kernel(me->iclient, buf->handle);
buf->virt = 0;
}
@@ -183,8 +183,8 @@
VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
if (err)
goto bail;
- buf->virt = 0;
- VERIFY(err, 0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
+ buf->virt = ion_map_kernel(clnt, buf->handle);
+ VERIFY(err, 0 == IS_ERR_OR_NULL(buf->virt));
if (err)
goto bail;
VERIFY(err, 0 != (sg = ion_sg_table(clnt, buf->handle)));
@@ -296,6 +296,9 @@
list[i].num = 0;
list[i].pgidx = 0;
len = pra[i].buf.len;
+ VERIFY(err, len >= 0);
+ if (err)
+ goto bail;
if (!len)
continue;
buf = pra[i].buf.pv;
@@ -622,27 +625,28 @@
static int get_dev(struct fastrpc_apps *me, struct fastrpc_device **rdev)
{
struct hlist_head *head;
- struct fastrpc_device *dev = 0;
- struct hlist_node *n;
+ struct fastrpc_device *dev = 0, *devfree = 0;
+ struct hlist_node *pos, *n;
uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
int err = 0;
spin_lock(&me->hlock);
head = &me->htbl[h];
- hlist_for_each_entry(dev, n, head, hn) {
+ hlist_for_each_entry_safe(dev, pos, n, head, hn) {
if (dev->tgid == current->tgid) {
hlist_del(&dev->hn);
+ devfree = dev;
break;
}
}
spin_unlock(&me->hlock);
- VERIFY(err, dev != 0);
+ VERIFY(err, devfree != 0);
if (err)
goto bail;
- *rdev = dev;
+ *rdev = devfree;
bail:
if (err) {
- free_dev(dev);
+ free_dev(devfree);
err = alloc_dev(rdev);
}
return err;
@@ -767,22 +771,23 @@
struct fastrpc_apps *me = &gfa;
uint32_t h = hash_32(current->tgid, RPC_HASH_BITS);
struct hlist_head *head;
- struct hlist_node *pos;
- struct fastrpc_device *dev;
+ struct hlist_node *pos, *n;
+ struct fastrpc_device *dev, *devfree;
rnext:
- dev = 0;
+ devfree = dev = 0;
spin_lock(&me->hlock);
head = &me->htbl[h];
- hlist_for_each_entry(dev, pos, head, hn) {
+ hlist_for_each_entry_safe(dev, pos, n, head, hn) {
if (dev->tgid == current->tgid) {
hlist_del(&dev->hn);
+ devfree = dev;
break;
}
}
spin_unlock(&me->hlock);
- if (dev) {
- free_dev(dev);
+ if (devfree) {
+ free_dev(devfree);
goto rnext;
}
return;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 682d876..c7b3253 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -95,6 +95,11 @@
if (recv_pkt_cmd_code != DCI_PKT_RSP_CODE)
cmd_code_len = 4; /* delayed response */
write_len = (int)(*(uint16_t *)(buf+2)) - cmd_code_len;
+ if (write_len <= 0) {
+ pr_err("diag: Invalid length in %s, write_len: %d",
+ __func__, write_len);
+ return;
+ }
pr_debug("diag: len = %d\n", write_len);
/* look up DCI client with tag */
for (i = 0; i < dci_max_reg; i++) {
@@ -149,7 +154,7 @@
{
uint16_t event_id, event_id_packet, length, temp_len;
uint8_t *event_mask_ptr, byte_mask, payload_len, payload_len_field;
- uint8_t timestamp[8], bit_index, timestamp_len;
+ uint8_t timestamp[8] = {0}, bit_index, timestamp_len;
uint8_t event_data[MAX_EVENT_SIZE];
unsigned int byte_index, total_event_len, i;
struct diag_dci_client_tbl *entry;
@@ -243,17 +248,23 @@
void extract_dci_log(unsigned char *buf)
{
- uint16_t log_code, item_num;
+ uint16_t log_code, item_num, log_length;
uint8_t equip_id, *log_mask_ptr, byte_mask;
unsigned int i, byte_index, byte_offset = 0;
struct diag_dci_client_tbl *entry;
+ log_length = *(uint16_t *)(buf + 2);
log_code = *(uint16_t *)(buf + 6);
equip_id = LOG_GET_EQUIP_ID(log_code);
item_num = LOG_GET_ITEM_NUM(log_code);
byte_index = item_num/8 + 2;
byte_mask = 0x01 << (item_num % 8);
+ if (log_length > USHRT_MAX - 4) {
+ pr_err("diag: Integer overflow in %s, log_len:%d",
+ __func__, log_length);
+ return;
+ }
byte_offset = (equip_id * 514) + byte_index;
if (byte_offset >= DCI_LOG_MASK_SIZE) {
pr_err("diag: Invalid byte_offset %d in dci log\n",
@@ -287,8 +298,8 @@
*(int *)(entry->dci_data+entry->data_len) =
DCI_LOG_TYPE;
memcpy(entry->dci_data + entry->data_len + 4,
- buf + 4, *(uint16_t *)(buf + 2));
- entry->data_len += 4 + *(uint16_t *)(buf + 2);
+ buf + 4, log_length);
+ entry->data_len += 4 + log_length;
}
mutex_unlock(&dci_health_mutex);
}
@@ -661,6 +672,22 @@
return ret;
}
+int diag_dci_find_client_index_health(int client_id)
+{
+ int i, ret = DCI_CLIENT_INDEX_INVALID;
+
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ if (driver->dci_client_tbl[i].client != NULL) {
+ if (driver->dci_client_tbl[i].client_id ==
+ client_id) {
+ ret = i;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
int diag_dci_find_client_index(int client_id)
{
int i, ret = DCI_CLIENT_INDEX_INVALID;
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 260cdf3..2c1e7ae 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -46,6 +46,7 @@
};
struct diag_dci_client_tbl {
+ int client_id;
struct task_struct *client;
uint16_t list; /* bit mask */
int signal_type;
@@ -62,6 +63,7 @@
/* This is used for DCI health stats */
struct diag_dci_health_stats {
+ int client_id;
int dropped_logs;
int dropped_events;
int received_logs;
@@ -96,6 +98,7 @@
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index);
void extract_dci_pkt_rsp(unsigned char *buf);
+int diag_dci_find_client_index_health(int client_id);
int diag_dci_find_client_index(int client_id);
/* DCI Log streaming functions */
void create_dci_log_mask_tbl(unsigned char *tbl_buf);
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index e5385fc..deb4d9c 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -29,14 +29,14 @@
{
char *buf;
int ret;
-
+ unsigned int buf_size;
buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
if (!buf) {
pr_err("diag: %s, Error allocating memory\n", __func__);
return -ENOMEM;
}
-
- ret = scnprintf(buf, DEBUG_BUF_SIZE,
+ buf_size = ksize(buf);
+ ret = scnprintf(buf, buf_size,
"modem ch: 0x%x\n"
"lpass ch: 0x%x\n"
"riva ch: 0x%x\n"
@@ -81,7 +81,7 @@
driver->logging_mode);
#ifdef CONFIG_DIAG_OVER_USB
- ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
+ ret += scnprintf(buf+ret, buf_size-ret,
"usb_connected: %d\n",
driver->usb_connected);
#endif
@@ -96,6 +96,7 @@
{
char *buf;
int ret;
+ unsigned int buf_size;
buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
if (!buf) {
@@ -103,7 +104,8 @@
return -ENOMEM;
}
- ret = scnprintf(buf, DEBUG_BUF_SIZE,
+ buf_size = ksize(buf);
+ ret = scnprintf(buf, buf_size,
"Pending status for work_stucts:\n"
"diag_drain_work: %d\n"
"Modem data diag_read_smd_work: %d\n"
@@ -151,7 +153,7 @@
diag_notify_update_smd_work)));
#ifdef CONFIG_DIAG_OVER_USB
- ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
+ ret += scnprintf(buf+ret, buf_size-ret,
"diag_proc_hdlc_work: %d\n"
"diag_read_work: %d\n",
work_pending(&(driver->diag_proc_hdlc_work)),
@@ -169,10 +171,11 @@
char *buf;
int ret = 0;
int i;
- int bytes_remaining;
- int bytes_in_buffer = 0;
- int bytes_written;
- int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
+ unsigned int bytes_remaining;
+ unsigned int bytes_in_buffer = 0;
+ unsigned int bytes_written;
+ unsigned int buf_size;
+ buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
if (diag_dbgfs_table_index >= diag_max_reg) {
/* Done. Reset to prepare for future requests */
@@ -185,7 +188,7 @@
pr_err("diag: %s, Error allocating memory\n", __func__);
return -ENOMEM;
}
-
+ buf_size = ksize(buf);
bytes_remaining = buf_size;
if (diag_dbgfs_table_index == 0) {
@@ -194,6 +197,7 @@
"WCNSS: %d, APPS: %d\n",
MODEM_DATA, LPASS_DATA, WCNSS_DATA, APPS_DATA);
bytes_in_buffer += bytes_written;
+ bytes_remaining -= bytes_written;
}
for (i = diag_dbgfs_table_index; i < diag_max_reg; i++) {
@@ -236,13 +240,15 @@
char *buf;
int ret;
int i;
- int bytes_remaining;
- int bytes_in_buffer = 0;
- int bytes_written;
- int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
+ unsigned int bytes_remaining;
+ unsigned int bytes_in_buffer = 0;
+ unsigned int bytes_written;
+ unsigned int buf_size;
int bytes_hsic_inited = 45;
int bytes_hsic_not_inited = 410;
+ buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
+
if (diag_dbgfs_finished) {
diag_dbgfs_finished = 0;
return 0;
@@ -254,6 +260,7 @@
return -ENOMEM;
}
+ buf_size = ksize(buf);
bytes_remaining = buf_size;
/* Only one smux for now */
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index b92666c..a7763cd 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -47,6 +47,7 @@
MODULE_LICENSE("GPL v2");
MODULE_VERSION("1.0");
+#define MIN_SIZ_ALLOW 4
#define INIT 1
#define EXIT -1
struct diagchar_dev *driver;
@@ -976,6 +977,8 @@
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
if (driver->dci_client_tbl[i].client == NULL) {
driver->dci_client_tbl[i].client = current;
+ driver->dci_client_tbl[i].client_id =
+ driver->dci_client_id;
driver->dci_client_tbl[i].list =
dci_params->list;
driver->dci_client_tbl[i].signal_type =
@@ -1056,7 +1059,7 @@
sizeof(struct diag_dci_health_stats)))
return -EFAULT;
mutex_lock(&dci_health_mutex);
- i = diag_dci_find_client_index(current->tgid);
+ i = diag_dci_find_client_index_health(stats.client_id);
if (i != DCI_CLIENT_INDEX_INVALID) {
dci_params = &(driver->dci_client_tbl[i]);
stats.dropped_logs = dci_params->dropped_logs;
@@ -1391,6 +1394,10 @@
index = 0;
/* Get the packet type F3/log/event/Pkt response */
err = copy_from_user((&pkt_type), buf, 4);
+ if (err) {
+ pr_alert("diag: copy failed for pkt_type\n");
+ return -EAGAIN;
+ }
/* First 4 bytes indicate the type of payload - ignore these */
if (count < 4) {
pr_err("diag: Client sending short data\n");
@@ -1431,8 +1438,9 @@
return err;
}
if (pkt_type == CALLBACK_DATA_TYPE) {
- if (payload_size > itemsize) {
- pr_err("diag: Dropping packet, packet payload size crosses 4KB limit. Current payload size %d\n",
+ if (payload_size > itemsize ||
+ payload_size <= MIN_SIZ_ALLOW) {
+ pr_err("diag: Dropping packet, invalid packet size. Current payload size %d\n",
payload_size);
driver->dropped_count++;
return -EBADMSG;
@@ -1577,6 +1585,11 @@
remote_proc = diag_get_remote(*(int *)user_space_data);
if (remote_proc) {
+ if (payload_size <= MIN_SIZ_ALLOW) {
+ pr_err("diag: Integer underflow in %s, payload size: %d",
+ __func__, payload_size);
+ return -EBADMSG;
+ }
token_offset = 4;
payload_size -= 4;
buf += 4;
diff --git a/drivers/char/diag/diagchar_hdlc.c b/drivers/char/diag/diagchar_hdlc.c
index 2369c4d..f78a0fe 100644
--- a/drivers/char/diag/diagchar_hdlc.c
+++ b/drivers/char/diag/diagchar_hdlc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, 2012-2013, The Linux Foundation.
+/* Copyright (c) 2008-2009, 2012-2014, The Linux Foundation.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -176,8 +176,8 @@
int msg_start;
if (hdlc && hdlc->src_ptr && hdlc->dest_ptr &&
- (hdlc->src_size - hdlc->src_idx > 0) &&
- (hdlc->dest_size - hdlc->dest_idx > 0)) {
+ (hdlc->src_size > hdlc->src_idx) &&
+ (hdlc->dest_size > hdlc->dest_idx)) {
msg_start = (hdlc->src_idx == 0) ? 1 : 0;
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c
index bd339e2..576811b 100644
--- a/drivers/char/diag/diagmem.c
+++ b/drivers/char/diag/diagmem.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/mempool.h>
#include <linux/mutex.h>
+#include <linux/ratelimit.h>
#include <asm/atomic.h>
#include "diagchar.h"
#include "diagfwd_bridge.h"
@@ -223,7 +224,7 @@
atomic_add(-1, (atomic_t *)
&diag_hsic[index].count_hsic_pool);
} else
- pr_err("diag: Attempt to free up DIAG driver HSIC mempool which is already free %d, ch = %d",
+ pr_err_ratelimited("diag: Attempt to free up DIAG driver HSIC mempool which is already free %d, ch = %d",
diag_hsic[index].count_hsic_pool, index);
} else if (pool_type == POOL_TYPE_HSIC_WRITE ||
pool_type == POOL_TYPE_HSIC_2_WRITE) {
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index aaf42d1..9a54e69 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -449,7 +449,7 @@
rc = 1;
#endif
if (rc == 1) {
- cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
+ cancel_delayed_work_sync(&msm_rotator_dev->imem_clk_work);
if (msm_rotator_dev->imem_clk_state != CLK_EN
&& msm_rotator_dev->imem_clk) {
clk_prepare_enable(msm_rotator_dev->imem_clk);
@@ -1347,12 +1347,10 @@
msm_rotator_dev->processing = 1;
iowrite32(0x1, MSM_ROTATOR_START);
- mutex_unlock(&msm_rotator_dev->rotator_lock);
/* End of Pass-1 */
wait_event(msm_rotator_dev->wq,
(msm_rotator_dev->processing == 0));
/* Beginning of Pass-2 */
- mutex_lock(&msm_rotator_dev->rotator_lock);
status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
if ((status & 0x03) != 0x01) {
pr_err("%s(): AXI Bus Error, issuing SW_RESET\n",
@@ -2028,7 +2026,7 @@
msm_rotator_wait_for_fence(commit_info->acq_fen);
commit_info->acq_fen = NULL;
- cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
+ cancel_delayed_work_sync(&msm_rotator_dev->rot_clk_work);
if (msm_rotator_dev->rot_clk_state != CLK_EN) {
enable_rot_clks();
msm_rotator_dev->rot_clk_state = CLK_EN;
@@ -2140,10 +2138,8 @@
msm_rotator_dev->processing = 1;
iowrite32(0x1, MSM_ROTATOR_START);
- mutex_unlock(&msm_rotator_dev->rotator_lock);
wait_event(msm_rotator_dev->wq,
(msm_rotator_dev->processing == 0));
- mutex_lock(&msm_rotator_dev->rotator_lock);
status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
if ((status & 0x03) != 0x01) {
pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index f81fc67..21d4759 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -231,7 +231,6 @@
#define A3XX_PC_PERFCOUNTER1_SELECT 0xC49
#define A3XX_PC_PERFCOUNTER2_SELECT 0xC4A
#define A3XX_PC_PERFCOUNTER3_SELECT 0xC4B
-#define A3XX_GRAS_TSE_DEBUG_ECO 0xC81
#define A3XX_GRAS_PERFCOUNTER0_SELECT 0xC88
#define A3XX_GRAS_PERFCOUNTER1_SELECT 0xC89
#define A3XX_GRAS_PERFCOUNTER2_SELECT 0xC8A
@@ -269,10 +268,6 @@
#define A3XX_HLSQ_PERFCOUNTER3_SELECT 0xE03
#define A3XX_HLSQ_PERFCOUNTER4_SELECT 0xE04
#define A3XX_HLSQ_PERFCOUNTER5_SELECT 0xE05
-#define A3XX_RB_DEBUG_ECO_CONTROLS_ADDR 0xCC1
-#define A3XX_RB_PERFCOUNTER0_SELECT 0xCC6
-#define A3XX_RB_PERFCOUNTER1_SELECT 0xCC7
-#define A3XX_RB_FRAME_BUFFER_DIMENSION 0xCE0
#define A3XX_VFD_PERFCOUNTER0_SELECT 0xE44
#define A3XX_VFD_PERFCOUNTER1_SELECT 0xE45
#define A3XX_VPC_VPC_DEBUG_RAM_SEL 0xE61
@@ -304,9 +299,6 @@
#define A3XX_GRAS_CL_CLIP_CNTL 0x2040
#define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
#define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048
-#define A3XX_GRAS_CL_VPORT_XSCALE 0x2049
-#define A3XX_GRAS_CL_VPORT_YOFFSET 0x204A
-#define A3XX_GRAS_CL_VPORT_YSCALE 0x204B
#define A3XX_GRAS_CL_VPORT_ZOFFSET 0x204C
#define A3XX_GRAS_CL_VPORT_ZSCALE 0x204D
#define A3XX_GRAS_SU_POINT_MINMAX 0x2068
@@ -322,75 +314,30 @@
#define A3XX_RB_MODE_CONTROL 0x20C0
#define A3XX_RB_RENDER_CONTROL 0x20C1
#define A3XX_RB_MSAA_CONTROL 0x20C2
-#define A3XX_RB_ALPHA_REFERENCE 0x20C3
#define A3XX_RB_MRT_CONTROL0 0x20C4
#define A3XX_RB_MRT_BUF_INFO0 0x20C5
-#define A3XX_RB_MRT_BUF_BASE0 0x20C6
#define A3XX_RB_MRT_BLEND_CONTROL0 0x20C7
-#define A3XX_RB_MRT_CONTROL1 0x20C8
-#define A3XX_RB_MRT_BUF_INFO1 0x20C9
-#define A3XX_RB_MRT_BUF_BASE1 0x20CA
#define A3XX_RB_MRT_BLEND_CONTROL1 0x20CB
-#define A3XX_RB_MRT_CONTROL2 0x20CC
-#define A3XX_RB_MRT_BUF_INFO2 0x20CD
-#define A3XX_RB_MRT_BUF_BASE2 0x20CE
#define A3XX_RB_MRT_BLEND_CONTROL2 0x20CF
-#define A3XX_RB_MRT_CONTROL3 0x20D0
-#define A3XX_RB_MRT_BUF_INFO3 0x20D1
-#define A3XX_RB_MRT_BUF_BASE3 0x20D2
#define A3XX_RB_MRT_BLEND_CONTROL3 0x20D3
#define A3XX_RB_BLEND_RED 0x20E4
-#define A3XX_RB_BLEND_GREEN 0x20E5
-#define A3XX_RB_BLEND_BLUE 0x20E6
-#define A3XX_RB_BLEND_ALPHA 0x20E7
-#define A3XX_RB_CLEAR_COLOR_DW0 0x20E8
-#define A3XX_RB_CLEAR_COLOR_DW1 0x20E9
-#define A3XX_RB_CLEAR_COLOR_DW2 0x20EA
-#define A3XX_RB_CLEAR_COLOR_DW3 0x20EB
#define A3XX_RB_COPY_CONTROL 0x20EC
-#define A3XX_RB_COPY_DEST_BASE 0x20ED
-#define A3XX_RB_COPY_DEST_PITCH 0x20EE
#define A3XX_RB_COPY_DEST_INFO 0x20EF
#define A3XX_RB_DEPTH_CONTROL 0x2100
-#define A3XX_RB_DEPTH_CLEAR 0x2101
-#define A3XX_RB_DEPTH_BUF_INFO 0x2102
-#define A3XX_RB_DEPTH_BUF_PITCH 0x2103
#define A3XX_RB_STENCIL_CONTROL 0x2104
-#define A3XX_RB_STENCIL_CLEAR 0x2105
-#define A3XX_RB_STENCIL_BUF_INFO 0x2106
-#define A3XX_RB_STENCIL_BUF_PITCH 0x2107
-#define A3XX_RB_STENCIL_REF_MASK 0x2108
-#define A3XX_RB_STENCIL_REF_MASK_BF 0x2109
-#define A3XX_RB_LRZ_VSC_CONTROL 0x210C
-#define A3XX_RB_WINDOW_OFFSET 0x210E
-#define A3XX_RB_SAMPLE_COUNT_CONTROL 0x2110
-#define A3XX_RB_SAMPLE_COUNT_ADDR 0x2111
-#define A3XX_RB_Z_CLAMP_MIN 0x2114
-#define A3XX_RB_Z_CLAMP_MAX 0x2115
#define A3XX_PC_VSTREAM_CONTROL 0x21E4
#define A3XX_PC_VERTEX_REUSE_BLOCK_CNTL 0x21EA
#define A3XX_PC_PRIM_VTX_CNTL 0x21EC
#define A3XX_PC_RESTART_INDEX 0x21ED
#define A3XX_HLSQ_CONTROL_0_REG 0x2200
-#define A3XX_HLSQ_CONTROL_1_REG 0x2201
-#define A3XX_HLSQ_CONTROL_2_REG 0x2202
-#define A3XX_HLSQ_CONTROL_3_REG 0x2203
#define A3XX_HLSQ_VS_CONTROL_REG 0x2204
-#define A3XX_HLSQ_FS_CONTROL_REG 0x2205
-#define A3XX_HLSQ_CONST_VSPRESV_RANGE_REG 0x2206
#define A3XX_HLSQ_CONST_FSPRESV_RANGE_REG 0x2207
#define A3XX_HLSQ_CL_NDRANGE_0_REG 0x220A
-#define A3XX_HLSQ_CL_NDRANGE_1_REG 0x220B
#define A3XX_HLSQ_CL_NDRANGE_2_REG 0x220C
-#define A3XX_HLSQ_CL_NDRANGE_3_REG 0x220D
-#define A3XX_HLSQ_CL_NDRANGE_4_REG 0x220E
-#define A3XX_HLSQ_CL_NDRANGE_5_REG 0x220F
-#define A3XX_HLSQ_CL_NDRANGE_6_REG 0x2210
#define A3XX_HLSQ_CL_CONTROL_0_REG 0x2211
#define A3XX_HLSQ_CL_CONTROL_1_REG 0x2212
#define A3XX_HLSQ_CL_KERNEL_CONST_REG 0x2214
#define A3XX_HLSQ_CL_KERNEL_GROUP_X_REG 0x2215
-#define A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG 0x2216
#define A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG 0x2217
#define A3XX_HLSQ_CL_WG_OFFSET_REG 0x221A
#define A3XX_VFD_CONTROL_0 0x2240
@@ -407,21 +354,10 @@
#define A3XX_SP_VS_CTRL_REG0 0x22C4
#define A3XX_SP_VS_CTRL_REG1 0x22C5
#define A3XX_SP_VS_PARAM_REG 0x22C6
-#define A3XX_SP_VS_OUT_REG_0 0x22C7
-#define A3XX_SP_VS_OUT_REG_1 0x22C8
-#define A3XX_SP_VS_OUT_REG_2 0x22C9
-#define A3XX_SP_VS_OUT_REG_3 0x22CA
-#define A3XX_SP_VS_OUT_REG_4 0x22CB
-#define A3XX_SP_VS_OUT_REG_5 0x22CC
-#define A3XX_SP_VS_OUT_REG_6 0x22CD
#define A3XX_SP_VS_OUT_REG_7 0x22CE
#define A3XX_SP_VS_VPC_DST_REG_0 0x22D0
-#define A3XX_SP_VS_VPC_DST_REG_1 0x22D1
-#define A3XX_SP_VS_VPC_DST_REG_2 0x22D2
-#define A3XX_SP_VS_VPC_DST_REG_3 0x22D3
#define A3XX_SP_VS_OBJ_OFFSET_REG 0x22D4
#define A3XX_SP_VS_OBJ_START_REG 0x22D5
-#define A3XX_SP_VS_PVT_MEM_PARAM_REG 0x22D6
#define A3XX_SP_VS_PVT_MEM_ADDR_REG 0x22D7
#define A3XX_SP_VS_PVT_MEM_SIZE_REG 0x22D8
#define A3XX_SP_VS_LENGTH_REG 0x22DF
@@ -429,19 +365,13 @@
#define A3XX_SP_FS_CTRL_REG1 0x22E1
#define A3XX_SP_FS_OBJ_OFFSET_REG 0x22E2
#define A3XX_SP_FS_OBJ_START_REG 0x22E3
-#define A3XX_SP_FS_PVT_MEM_PARAM_REG 0x22E4
#define A3XX_SP_FS_PVT_MEM_ADDR_REG 0x22E5
#define A3XX_SP_FS_PVT_MEM_SIZE_REG 0x22E6
#define A3XX_SP_FS_FLAT_SHAD_MODE_REG_0 0x22E8
#define A3XX_SP_FS_FLAT_SHAD_MODE_REG_1 0x22E9
#define A3XX_SP_FS_OUTPUT_REG 0x22EC
#define A3XX_SP_FS_MRT_REG_0 0x22F0
-#define A3XX_SP_FS_MRT_REG_1 0x22F1
-#define A3XX_SP_FS_MRT_REG_2 0x22F2
-#define A3XX_SP_FS_MRT_REG_3 0x22F3
#define A3XX_SP_FS_IMAGE_OUTPUT_REG_0 0x22F4
-#define A3XX_SP_FS_IMAGE_OUTPUT_REG_1 0x22F5
-#define A3XX_SP_FS_IMAGE_OUTPUT_REG_2 0x22F6
#define A3XX_SP_FS_IMAGE_OUTPUT_REG_3 0x22F7
#define A3XX_SP_FS_LENGTH_REG 0x22FF
#define A3XX_TPL1_TP_VS_TEX_OFFSET 0x2340
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index c096b8c..a93fe14 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -292,7 +292,7 @@
*/
int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
- struct kgsl_perfcounter_read_group *reads, unsigned int count)
+ struct kgsl_perfcounter_read_group __user *reads, unsigned int count)
{
struct adreno_perfcounters *counters = adreno_dev->gpudev->perfcounters;
struct adreno_perfcount_group *group;
@@ -312,12 +312,6 @@
if (reads == NULL || count == 0 || count > 100)
return -EINVAL;
- /* verify valid inputs group ids and countables */
- for (i = 0; i < count; i++) {
- if (reads[i].groupid >= counters->group_count)
- return -EINVAL;
- }
-
list = kmalloc(sizeof(struct kgsl_perfcounter_read_group) * count,
GFP_KERNEL);
if (!list)
@@ -331,8 +325,15 @@
/* list iterator */
for (j = 0; j < count; j++) {
+
list[j].value = 0;
+ /* Verify that the group ID is within range */
+ if (list[j].groupid >= counters->group_count) {
+ ret = -EINVAL;
+ goto done;
+ }
+
group = &(counters->groups[list[j].groupid]);
/* group/counter iterator */
@@ -572,15 +573,13 @@
kgsl_mmu_unmap(pagetable, &device->memstore);
- kgsl_mmu_unmap(pagetable, &adreno_dev->pwron_fixup);
-
kgsl_mmu_unmap(pagetable, &device->mmu.setstate_memory);
}
static int adreno_setup_pt(struct kgsl_device *device,
struct kgsl_pagetable *pagetable)
{
- int result;
+ int result = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
@@ -596,13 +595,9 @@
if (result)
goto unmap_memptrs_desc;
- result = kgsl_mmu_map_global(pagetable, &adreno_dev->pwron_fixup);
- if (result)
- goto unmap_memstore_desc;
-
result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory);
if (result)
- goto unmap_pwron_fixup_desc;
+ goto unmap_memstore_desc;
/*
* Set the mpu end to the last "normal" global memory we use.
@@ -613,9 +608,6 @@
device->mmu.setstate_memory.size;
return result;
-unmap_pwron_fixup_desc:
- kgsl_mmu_unmap(pagetable, &adreno_dev->pwron_fixup);
-
unmap_memstore_desc:
kgsl_mmu_unmap(pagetable, &device->memstore);
@@ -1648,11 +1640,6 @@
kgsl_pwrctrl_enable(device);
/* Set up a2xx special case */
-
- /* Set the bit to indicate that we've just powered on */
- set_bit(ADRENO_DEVICE_PWRON, &adreno_dev->priv);
-
- /* Set up the MMU */
if (adreno_is_a2xx(adreno_dev)) {
/*
* the MH_CLNT_INTF_CTRL_CONFIG registers aren't present
@@ -3226,9 +3213,6 @@
if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr, size))
return &device->memstore;
- if (kgsl_gpuaddr_in_memdesc(&adreno_dev->pwron_fixup, gpuaddr, size))
- return &adreno_dev->pwron_fixup;
-
if (kgsl_gpuaddr_in_memdesc(&device->mmu.setstate_memory, gpuaddr,
size))
return &device->mmu.setstate_memory;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
old mode 100755
new mode 100644
index 314d4e9..59cf265
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -35,7 +35,6 @@
#define KGSL_CMD_FLAGS_PMODE 0x00000001
#define KGSL_CMD_FLAGS_INTERNAL_ISSUE 0x00000002
#define KGSL_CMD_FLAGS_GET_INT 0x00000004
-#define KGSL_CMD_FLAGS_PWRON_FIXUP 0x00000008
#define KGSL_CMD_FLAGS_EOF 0x00000100
/* Command identifiers */
@@ -46,7 +45,6 @@
#define KGSL_END_OF_IB_IDENTIFIER 0x2ABEDEAD
#define KGSL_END_OF_FRAME_IDENTIFIER 0x2E0F2E0F
#define KGSL_NOP_IB_IDENTIFIER 0x20F20F20
-#define KGSL_PWRON_FIXUP_IDENTIFIER 0x2AFAFAFA
#ifdef CONFIG_MSM_SCM
#define ADRENO_DEFAULT_PWRSCALE_POLICY (&kgsl_pwrscale_policy_tz)
@@ -82,7 +80,6 @@
struct adreno_device {
struct kgsl_device dev; /* Must be first field in this struct */
- unsigned long priv;
unsigned int chip_id;
enum adreno_gpurev gpurev;
unsigned long gmem_base;
@@ -115,8 +112,6 @@
struct ocmem_buf *ocmem_hdl;
unsigned int ocmem_base;
unsigned int gpu_cycles;
- struct kgsl_memdesc pwron_fixup;
- unsigned int pwron_fixup_dwords;
};
#define PERFCOUNTER_FLAG_NONE 0x0
@@ -157,17 +152,6 @@
unsigned int group_count;
};
-/**
- * enum adreno_device_flags - Private flags for the adreno_device
- * @ADRENO_DEVICE_PWRON - Set during init after a power collapse
- * @ADRENO_DEVICE_PWRON_FIXUP - Set if the target requires the shader fixup
- * after power collapse
- */
-enum adreno_device_flags {
- ADRENO_DEVICE_PWRON = 0,
- ADRENO_DEVICE_PWRON_FIXUP = 1,
-};
-
struct adreno_gpudev {
/*
* These registers are in a different location on A3XX, so define
@@ -326,8 +310,6 @@
int adreno_ft_init_sysfs(struct kgsl_device *device);
void adreno_ft_uninit_sysfs(struct kgsl_device *device);
-int adreno_a3xx_pwron_fixup_init(struct adreno_device *adreno_dev);
-
static inline int adreno_is_a200(struct adreno_device *adreno_dev)
{
return (adreno_dev->gpurev == ADRENO_REV_A200);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index af828df..a8cc524 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2497,270 +2497,6 @@
}
}
-static const unsigned int _a3xx_pwron_fixup_fs_instructions[] = {
- 0x00000000, 0x10000400, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x03000000,
-};
-
-/**
- * adreno_a3xx_pwron_fixup_init() - Initalize a special command buffer to run a
- * post-power collapse shader workaround
- * @adreno_dev: Pointer to a adreno_device struct
- *
- * A3xx targets require a CL Exec after recovery from power-collapse.
- * Construct the IB once at init time and keep it handy.
- *
- * Returns: 0 on success or negative on error
- */
-int adreno_a3xx_pwron_fixup_init(struct adreno_device *adreno_dev)
-{
- unsigned int *cmds;
- int count = sizeof(_a3xx_pwron_fixup_fs_instructions) >> 2;
- int ret;
- /* Return if the fixup is already in place */
- if (test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
- return 0;
-
- ret = kgsl_allocate_contiguous(&adreno_dev->pwron_fixup, PAGE_SIZE);
-
- if (ret)
- return ret;
- adreno_dev->pwron_fixup.flags |= KGSL_MEMFLAGS_GPUREADONLY;
- cmds = adreno_dev->pwron_fixup.hostptr;
-
- *cmds++ = cp_type0_packet(A3XX_UCHE_CACHE_INVALIDATE0_REG, 2);
- *cmds++ = 0x00000000;
- *cmds++ = 0x90000000;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type3_packet(CP_REG_RMW, 3);
- *cmds++ = A3XX_RBBM_CLOCK_CTL;
- *cmds++ = 0xFFFCFFFF;
- *cmds++ = 0x00010000;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
- *cmds++ = 0x1E000150;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
- *cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG) | (0x1 << 30);
- *cmds++ = 0x1E000150;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
- *cmds++ = 0x1E000150;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_1_REG, 1);
- *cmds++ = 0x00000040;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_2_REG, 1);
- *cmds++ = 0x80000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_3_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_VS_CONTROL_REG, 1);
- *cmds++ = 0x00000001;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_FS_CONTROL_REG, 1);
- *cmds++ = 0x00001002 | (count >> 3) << 24;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CONST_VSPRESV_RANGE_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CONST_FSPRESV_RANGE_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_0_REG, 1);
- *cmds++ = 0x00401101;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_1_REG, 1);
- *cmds++ = 0x00000400;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_2_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_3_REG, 1);
- *cmds++ = 0x00000001;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_4_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_5_REG, 1);
- *cmds++ = 0x00000001;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_6_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_0_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_1_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_CONST_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG, 1);
- *cmds++ = 0x00000010;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG, 1);
- *cmds++ = 0x00000001;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG, 1);
- *cmds++ = 0x00000001;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_WG_OFFSET_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_SP_CTRL_REG, 1);
- *cmds++ = 0x00040000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG0, 1);
- *cmds++ = 0x0000000A;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG1, 1);
- *cmds++ = 0x00000001;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_PARAM_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_0, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_1, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_2, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_3, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_4, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_5, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_6, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_7, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_0, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_1, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_2, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_3, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_OBJ_OFFSET_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_OBJ_START_REG, 1);
- *cmds++ = 0x00000004;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_PARAM_REG, 1);
- *cmds++ = 0x04008001;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_ADDR_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_SIZE_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_VS_LENGTH_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG0, 1);
- *cmds++ = 0x00B0400A | (count >> 3) << 24;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG1, 1);
- *cmds++ = 0x00300402;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_OBJ_OFFSET_REG, 1);
- *cmds++ = 0x00010000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_OBJ_START_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_PARAM_REG, 1);
- *cmds++ = 0x04008001;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_ADDR_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_SIZE_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_FLAT_SHAD_MODE_REG_0, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_FLAT_SHAD_MODE_REG_1, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_OUTPUT_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_0, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_1, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_2, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_3, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_0, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_1, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_2, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_3, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_SP_FS_LENGTH_REG, 1);
- *cmds++ = count >> 3;
- *cmds++ = cp_type0_packet(A3XX_RB_MODE_CONTROL, 1);
- *cmds++ = 0x00008000;
- *cmds++ = cp_type0_packet(A3XX_RB_RENDER_CONTROL, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MSAA_CONTROL, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_ALPHA_REFERENCE, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL0, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL1, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL2, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL3, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO0, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO1, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO2, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO3, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE0, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE1, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE2, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE3, 1);
- *cmds++ = 0x00000000;
-
- *cmds++ = cp_type0_packet(A3XX_RB_PERFCOUNTER0_SELECT, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_PERFCOUNTER1_SELECT, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_RB_FRAME_BUFFER_DIMENSION, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
-
- *cmds++ = cp_type3_packet(CP_LOAD_STATE, 2 + count);
- *cmds++ = (6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
- ((count >> 3) << CP_LOADSTATE_NUMOFUNITS_SHIFT);
- *cmds++ = 0x00000000;
- memcpy(cmds, _a3xx_pwron_fixup_fs_instructions, count << 2);
- cmds += count;
-
- *cmds++ = cp_type3_packet(CP_EXEC_CL, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_nop_packet(1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_0_REG, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
- *cmds++ = 0x1E000150;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
- *cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
- *cmds++ = 0x1E000050;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
- *cmds++ = cp_type3_packet(CP_REG_RMW, 3);
- *cmds++ = A3XX_RBBM_CLOCK_CTL;
- *cmds++ = 0xFFFCFFFF;
- *cmds++ = 0x00000000;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
-
- /*
- * Remember the number of dwords in the command buffer for when we
- * program the indirect buffer call in the ringbuffer
- */
- adreno_dev->pwron_fixup_dwords =
- (cmds - (unsigned int *)adreno_dev->pwron_fixup.hostptr);
-
- /* Mark the flag in ->priv to show that we have the fix */
- set_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv);
- return 0;
-}
-
static int a3xx_rb_init(struct adreno_device *adreno_dev,
struct adreno_ringbuffer *rb)
{
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index e6ec91d..a3fa312 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -177,8 +177,6 @@
/* Load a buffer with pre-fetch enabled */
#define CP_INDIRECT_BUFFER_PFE 0x3F
-#define CP_EXEC_CL 0x31
-
#define CP_LOADSTATE_DSTOFFSET_SHIFT 0x00000000
#define CP_LOADSTATE_STATESRC_SHIFT 0x00000010
#define CP_LOADSTATE_STATEBLOCKID_SHIFT 0x00000013
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index c2a0270..bc7a5c2 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -584,10 +584,6 @@
if (flags & KGSL_CMD_FLAGS_EOF)
total_sizedwords += 2;
- /* Add space for the power on shader fixup if we need it */
- if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP)
- total_sizedwords += 5;
-
ringcmds = adreno_ringbuffer_allocspace(rb, context, total_sizedwords);
if (!ringcmds)
return -ENOSPC;
@@ -595,18 +591,6 @@
rcmd_gpu = rb->buffer_desc.gpuaddr
+ sizeof(uint)*(rb->wptr-total_sizedwords);
- if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
- KGSL_PWRON_FIXUP_IDENTIFIER);
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
- CP_HDR_INDIRECT_BUFFER_PFD);
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
- adreno_dev->pwron_fixup.gpuaddr);
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
- adreno_dev->pwron_fixup_dwords);
- }
-
GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
@@ -1085,22 +1069,9 @@
} else
drawctxt->timestamp++;
- flags &= KGSL_CMD_FLAGS_EOF;
-
- /*
- * For some targets, we need to execute a dummy shader operation after a
- * power collapse
- */
-
- if (test_and_clear_bit(ADRENO_DEVICE_PWRON, &adreno_dev->priv) &&
- test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
- {
- flags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
- }
-
ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
drawctxt,
- flags,
+ (flags & KGSL_CMD_FLAGS_EOF),
&link[0], (cmds - link));
if (ret)
goto done;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 6375991..9acac1a 100755
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2949,7 +2949,7 @@
static inline bool
mmap_range_valid(unsigned long addr, unsigned long len)
{
- return (addr + len) > addr && (addr + len) < TASK_SIZE;
+ return ((ULONG_MAX - addr) > len) && ((addr + len) < TASK_SIZE);
}
static unsigned long
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index bf6ace7..17e6fa3 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -262,7 +262,7 @@
size = 1;
/* don't overflow */
- if ((gpuaddr + size) < gpuaddr)
+ if (size > UINT_MAX - gpuaddr)
return 0;
if (gpuaddr >= memdesc->gpuaddr &&
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
old mode 100755
new mode 100644
index de62c3a..2881e49
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -552,7 +552,6 @@
sglen_alloc = PAGE_ALIGN(size) >> PAGE_SHIFT;
- memdesc->size = size;
memdesc->pagetable = pagetable;
memdesc->ops = &kgsl_page_alloc_ops;
@@ -615,6 +614,14 @@
continue;
}
+ /*
+ * Update sglen and memdesc size,as requested allocation
+ * not served fully. So that they can be correctly freed
+ * in kgsl_sharedmem_free().
+ */
+ memdesc->sglen = sglen;
+ memdesc->size = (size - len);
+
KGSL_CORE_ERR(
"Out of memory: only allocated %dKB of %dKB requested\n",
(size - len) >> 10, size >> 10);
@@ -631,6 +638,7 @@
}
memdesc->sglen = sglen;
+ memdesc->size = size;
/*
* All memory that goes to the user has to be zeroed out before it gets
@@ -671,15 +679,15 @@
outer_cache_range_op_sg(memdesc->sg, memdesc->sglen,
KGSL_CACHE_OP_FLUSH);
- KGSL_STATS_ADD(size, kgsl_driver.stats.page_alloc,
- kgsl_driver.stats.page_alloc_max);
-
order = get_order(size);
if (order < 16)
kgsl_driver.stats.histogram[order]++;
done:
+ KGSL_STATS_ADD(memdesc->size, kgsl_driver.stats.page_alloc,
+ kgsl_driver.stats.page_alloc_max);
+
if ((memdesc->sglen_alloc * sizeof(struct page *)) > PAGE_SIZE)
vfree(pages);
else
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 6f9eb94..4f39838 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -139,7 +139,7 @@
unsigned int p;
for (p = 0; p < entity->num_pads; p++) {
- struct media_pad_desc pad;
+ struct media_pad_desc pad = {0};
media_device_kpad_to_upad(&entity->pads[p], &pad);
if (copy_to_user(&links.pads[p], &pad, sizeof(pad)))
return -EFAULT;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index af65e28..3423032 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -294,7 +294,7 @@
/* Get the handle of the shared fd */
svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
listener->ifd_data_fd);
- if (svc->ihandle == NULL) {
+ if (IS_ERR_OR_NULL(svc->ihandle)) {
pr_err("Ion client could not retrieve the handle\n");
return -ENOMEM;
}
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 079f396..11ef72d 100755
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -388,8 +388,6 @@
{
__be16 protocol = 0;
- skb->dev = dev;
-
switch (skb->data[0] & 0xf0) {
case 0x40:
protocol = htons(ETH_P_IP);
@@ -425,7 +423,6 @@
/*map urb to actual network iface based on mux id*/
unet_id = unet_offset + mux_id;
skb->dev = unet_list[unet_id]->net;
- entry->dev = unet_list[unet_id];
}
}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 807cdb4..5ad2f50 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -42,11 +42,13 @@
#endif
#define DEVICE "wcnss_wlan"
+#define CTRL_DEVICE "wcnss_ctrl"
#define VERSION "1.01"
#define WCNSS_PIL_DEVICE "wcnss"
/* module params */
#define WCNSS_CONFIG_UNSPECIFIED (-1)
+#define UINT32_MAX (0xFFFFFFFFU)
static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED;
module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
@@ -74,6 +76,16 @@
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
#define WCNSS_MAX_FRAME_SIZE (4*1024)
#define WCNSS_VERSION_LEN 30
+#define WCNSS_MAX_CMD_LEN (128)
+#define WCNSS_MIN_CMD_LEN (3)
+#define WCNSS_MIN_SERIAL_LEN (6)
+
+/* control messages from userspace */
+#define WCNSS_USR_CTRL_MSG_START 0x00000000
+#define WCNSS_USR_SERIAL_NUM (WCNSS_USR_CTRL_MSG_START + 1)
+#define WCNSS_USR_HAS_CAL_DATA (WCNSS_USR_CTRL_MSG_START + 2)
+
+#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x"
/* message types */
#define WCNSS_CTRL_MSG_START 0x01000000
@@ -86,6 +98,8 @@
#define WCNSS_CALDATA_DNLD_REQ (WCNSS_CTRL_MSG_START + 6)
#define WCNSS_CALDATA_DNLD_RSP (WCNSS_CTRL_MSG_START + 7)
+/* max 20mhz channel count */
+#define WCNSS_MAX_CH_NUM 45
#define VALID_VERSION(version) \
((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
@@ -249,13 +263,62 @@
int fw_cal_available;
int user_cal_read;
int user_cal_available;
- int user_cal_rcvd;
+ u32 user_cal_rcvd;
int user_cal_exp_size;
int device_opened;
+ int ctrl_device_opened;
+ char wlan_nv_macAddr[WLAN_MAC_ADDR_SIZE];
struct mutex dev_lock;
+ struct mutex ctrl_lock;
wait_queue_head_t read_wait;
+ u16 unsafe_ch_count;
+ u16 unsafe_ch_list[WCNSS_MAX_CH_NUM];
} *penv = NULL;
+static ssize_t wcnss_wlan_macaddr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ char macAddr[WLAN_MAC_ADDR_SIZE];
+
+ if (!penv)
+ return -ENODEV;
+
+ pr_debug("%s: Receive MAC Addr From user space: %s\n", __func__, buf);
+
+ if (WLAN_MAC_ADDR_SIZE != sscanf(buf, MAC_ADDRESS_STR,
+ (int *)&macAddr[0], (int *)&macAddr[1],
+ (int *)&macAddr[2], (int *)&macAddr[3],
+ (int *)&macAddr[4], (int *)&macAddr[5])) {
+
+ pr_err("%s: Failed to Copy MAC\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(penv->wlan_nv_macAddr, macAddr, sizeof(penv->wlan_nv_macAddr));
+
+ pr_info("%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
+ penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1],
+ penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3],
+ penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]);
+
+ return count;
+}
+
+static ssize_t wcnss_wlan_macaddr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (!penv)
+ return -ENODEV;
+
+ return scnprintf(buf, PAGE_SIZE, MAC_ADDRESS_STR,
+ penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1],
+ penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3],
+ penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]);
+}
+
+static DEVICE_ATTR(wcnss_mac_addr, S_IRUSR | S_IWUSR,
+ wcnss_wlan_macaddr_show, wcnss_wlan_macaddr_store);
+
static ssize_t wcnss_serial_number_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -372,8 +435,14 @@
if (ret)
goto remove_thermal;
+ ret = device_create_file(dev, &dev_attr_wcnss_mac_addr);
+ if (ret)
+ goto remove_version;
+
return 0;
+remove_version:
+ device_remove_file(dev, &dev_attr_wcnss_version);
remove_thermal:
device_remove_file(dev, &dev_attr_thermal_mitigation);
remove_serial:
@@ -388,6 +457,7 @@
device_remove_file(dev, &dev_attr_serial_number);
device_remove_file(dev, &dev_attr_thermal_mitigation);
device_remove_file(dev, &dev_attr_wcnss_version);
+ device_remove_file(dev, &dev_attr_wcnss_mac_addr);
}
}
static void wcnss_smd_notify_event(void *data, unsigned int event)
@@ -678,6 +748,20 @@
}
EXPORT_SYMBOL(wcnss_ssr_boot_notify);
+int wcnss_get_wlan_mac_address(char mac_addr[WLAN_MAC_ADDR_SIZE])
+{
+ if (!penv)
+ return -ENODEV;
+
+ memcpy(mac_addr, penv->wlan_nv_macAddr, WLAN_MAC_ADDR_SIZE);
+ pr_debug("%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
+ penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1],
+ penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3],
+ penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]);
+ return 0;
+}
+EXPORT_SYMBOL(wcnss_get_wlan_mac_address);
+
static int enable_wcnss_suspend_notify;
static int enable_wcnss_suspend_notify_set(const char *val,
@@ -793,6 +877,35 @@
return -ENODEV;
}
+int wcnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
+{
+ if (penv && unsafe_ch_list &&
+ (ch_count <= WCNSS_MAX_CH_NUM)) {
+ memcpy((char *)penv->unsafe_ch_list,
+ (char *)unsafe_ch_list, ch_count * sizeof(u16));
+ penv->unsafe_ch_count = ch_count;
+ return 0;
+ } else
+ return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_set_wlan_unsafe_channel);
+
+int wcnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 buffer_size,
+ u16 *ch_count)
+{
+ if (penv) {
+ if (buffer_size < penv->unsafe_ch_count * sizeof(u16))
+ return -ENODEV;
+ memcpy((char *)unsafe_ch_list,
+ (char *)penv->unsafe_ch_list,
+ penv->unsafe_ch_count * sizeof(u16));
+ *ch_count = penv->unsafe_ch_count;
+ return 0;
+ } else
+ return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_get_wlan_unsafe_channel);
+
static int wcnss_smd_tx(void *data, int len)
{
int ret = 0;
@@ -1288,6 +1401,80 @@
+static int wcnss_ctrl_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+
+ if (!penv || penv->ctrl_device_opened)
+ return -EFAULT;
+
+ penv->ctrl_device_opened = 1;
+
+ return rc;
+}
+
+
+void process_usr_ctrl_cmd(u8 *buf, size_t len)
+{
+ u16 cmd = buf[0] << 8 | buf[1];
+
+ switch (cmd) {
+
+ case WCNSS_USR_SERIAL_NUM:
+ if (WCNSS_MIN_SERIAL_LEN > len) {
+ pr_err("%s: Invalid serial number\n", __func__);
+ return;
+ }
+ penv->serial_number = buf[2] << 24 | buf[3] << 16
+ | buf[4] << 8 | buf[5];
+ break;
+
+ case WCNSS_USR_HAS_CAL_DATA:
+ if (1 < buf[2])
+ pr_err("%s: Invalid data for cal %d\n", __func__,
+ buf[2]);
+ has_calibrated_data = buf[2];
+ break;
+
+ default:
+ pr_err("%s: Invalid command %d\n", __func__, cmd);
+ break;
+ }
+}
+
+static ssize_t wcnss_ctrl_write(struct file *fp, const char __user
+ *user_buffer, size_t count, loff_t *position)
+{
+ int rc = 0;
+ u8 buf[WCNSS_MAX_CMD_LEN];
+
+ if (!penv || !penv->ctrl_device_opened || WCNSS_MAX_CMD_LEN < count
+ || WCNSS_MIN_CMD_LEN > count)
+ return -EFAULT;
+
+ mutex_lock(&penv->ctrl_lock);
+ rc = copy_from_user(buf, user_buffer, count);
+ if (0 == rc)
+ process_usr_ctrl_cmd(buf, count);
+
+ mutex_unlock(&penv->ctrl_lock);
+
+ return rc;
+}
+
+
+static const struct file_operations wcnss_ctrl_fops = {
+ .owner = THIS_MODULE,
+ .open = wcnss_ctrl_open,
+ .write = wcnss_ctrl_write,
+};
+
+static struct miscdevice wcnss_usr_ctrl = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = CTRL_DEVICE,
+ .fops = &wcnss_ctrl_fops,
+};
+
static int
wcnss_trigger_config(struct platform_device *pdev)
{
@@ -1390,19 +1577,17 @@
static int wcnss_node_open(struct inode *inode, struct file *file)
{
struct platform_device *pdev;
+ int rc = 0;
if (!penv)
return -EFAULT;
- /* first open is only to trigger WCNSS platform driver */
if (!penv->triggered) {
pr_info(DEVICE " triggered by userspace\n");
pdev = penv->pdev;
- return wcnss_trigger_config(pdev);
-
- } else if (penv->device_opened) {
- pr_info(DEVICE " already opened\n");
- return -EBUSY;
+ rc = wcnss_trigger_config(pdev);
+ if (rc)
+ return -EFAULT;
}
mutex_lock(&penv->dev_lock);
@@ -1413,7 +1598,7 @@
penv->device_opened = 1;
mutex_unlock(&penv->dev_lock);
- return 0;
+ return rc;
}
static ssize_t wcnss_wlan_read(struct file *fp, char __user
@@ -1458,7 +1643,7 @@
*user_buffer, size_t count, loff_t *position)
{
int rc = 0;
- int size = 0;
+ size_t size = 0;
if (!penv || !penv->device_opened || penv->user_cal_available)
return -EFAULT;
@@ -1466,7 +1651,7 @@
if (penv->user_cal_rcvd == 0 && count >= 4
&& !penv->user_cal_data) {
rc = copy_from_user((void *)&size, user_buffer, 4);
- if (size > MAX_CALIBRATED_DATA_SIZE) {
+ if (!size || size > MAX_CALIBRATED_DATA_SIZE) {
pr_err(DEVICE " invalid size to write %d\n", size);
return -EFAULT;
}
@@ -1485,7 +1670,8 @@
} else if (penv->user_cal_rcvd == 0 && count < 4)
return -EFAULT;
- if (MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
+ if ((UINT32_MAX - count < penv->user_cal_rcvd) ||
+ MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) {
pr_err(DEVICE " invalid size to write %d\n", count +
penv->user_cal_rcvd);
rc = -ENOMEM;
@@ -1545,6 +1731,7 @@
return -ENOENT;
mutex_init(&penv->dev_lock);
+ mutex_init(&penv->ctrl_lock);
init_waitqueue_head(&penv->read_wait);
/*
@@ -1557,6 +1744,9 @@
* place
*/
pr_info(DEVICE " probed in built-in mode\n");
+
+ misc_register(&wcnss_usr_ctrl);
+
return misc_register(&wcnss_misc);
}
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 61049d8..41da325 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1973,6 +1973,12 @@
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
spin_lock_irqsave(&uport->lock, flags);
+ if (msm_uport->is_shutdown) {
+ pr_err("%s:Clock OFF fail.UART port is closed\n", __func__);
+ spin_unlock_irqrestore(&uport->lock, flags);
+ return;
+ }
+
if (msm_uport->clk_state == MSM_HS_CLK_ON) {
msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF;
msm_uport->clk_req_off_state = CLK_REQ_OFF_START;
@@ -1998,6 +2004,13 @@
mutex_lock(&msm_uport->clk_mutex);
spin_lock_irqsave(&uport->lock, flags);
+ if (msm_uport->is_shutdown) {
+ pr_err("%s:Clock ON fail.UART port is closed\n", __func__);
+ spin_unlock_irqrestore(&uport->lock, flags);
+ mutex_unlock(&msm_uport->clk_mutex);
+ return;
+ }
+
switch (msm_uport->clk_state) {
case MSM_HS_CLK_OFF:
wake_lock(&msm_uport->dma_wake_lock);
@@ -2491,6 +2504,7 @@
uport->flags = UPF_BOOT_AUTOCONF;
uport->uartclk = 7372800;
msm_uport->imr_reg = 0x0;
+ msm_uport->is_shutdown = true;
msm_uport->clk = clk_get(&pdev->dev, "core_clk");
if (IS_ERR(msm_uport->clk))
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 7150752..0470194 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -640,12 +640,26 @@
return 0;
}
-static const struct vm_operations_struct uio_vm_ops = {
+static const struct vm_operations_struct uio_logical_vm_ops = {
.open = uio_vma_open,
.close = uio_vma_close,
.fault = uio_vma_fault,
};
+static int uio_mmap_logical(struct vm_area_struct *vma)
+{
+ vma->vm_flags |= VM_DONTEXPAND | VM_NODUMP;
+ vma->vm_ops = &uio_logical_vm_ops;
+ uio_vma_open(vma);
+ return 0;
+}
+
+static const struct vm_operations_struct uio_physical_vm_ops = {
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+ .access = generic_access_phys,
+#endif
+};
+
static int uio_mmap_physical(struct vm_area_struct *vma)
{
struct uio_device *idev = vma->vm_private_data;
@@ -658,8 +672,7 @@
if (vma->vm_end - vma->vm_start > mem->size)
return -EINVAL;
- vma->vm_flags |= VM_IO | VM_RESERVED;
-
+ vma->vm_ops = &uio_physical_vm_ops;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
/*
@@ -671,6 +684,7 @@
* So we just do the physical mmap without a page
* offset.
*/
+
return remap_pfn_range(vma,
vma->vm_start,
mem->addr >> PAGE_SHIFT,
@@ -678,14 +692,6 @@
vma->vm_page_prot);
}
-static int uio_mmap_logical(struct vm_area_struct *vma)
-{
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &uio_vm_ops;
- uio_vma_open(vma);
- return 0;
-}
-
static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
{
struct uio_listener *listener = filep->private_data;
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 612c1c7..1d8d91a 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -381,8 +381,6 @@
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
- vma->vm_flags |= VM_IO;
-
return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len);
}
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index 117be3d..e2729b9 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1239,11 +1239,7 @@
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */
- vma->vm_flags |= VM_IO;
-
return vm_iomap_memory(vma, fbdev->fb_phys, fbdev->fb_len);
-
- return 0;
}
static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata)
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index cfa0bbb..60cca2f 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2834,16 +2834,13 @@
pr_debug("%s: the right %d shifted xscale is %d.\n",
__func__, shift, xscale);
- if (src_h > dst_h) {
- yscale = src_h;
- yscale <<= shift;
- yscale /= dst_h;
- } else { /* upscale */
- yscale = dst_h;
- yscale <<= shift;
- yscale /= src_h;
- }
+ if (src_h > dst_h)
+ yscale = src_h;
+ else
+ yscale = dst_h;
+ yscale <<= shift;
+ yscale /= dst_h;
yscale *= src_w;
yscale /= hsync;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 62012b9..0d12194 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -91,6 +91,8 @@
#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT 11
#define VIDC_SM_ENC_EXT_CTRL_LONG_TERM_REF_ENABLE_BMSK 0x00000400
#define VIDC_SM_ENC_EXT_CTRL_LONG_TERM_REF_ENABLE_SHFT 10
+#define VIDC_SM_ENC_EXT_CTRL_PIC_ORDER_ENABLE_BMSK 0x200
+#define VIDC_SM_ENC_EXT_CTRL_PIC_ORDER_ENABLE_SHFT 9
#define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK 0x80
#define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT 7
#define VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK 0X100
@@ -482,7 +484,7 @@
*shared_mem, u32 hec_enable,
enum VIDC_SM_frame_skip frame_skip_mode,
u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
- u32 sps_pps_control, u32 closed_gop_enable,
+ u32 sps_pps_control, u32 pic_order_count, u32 closed_gop_enable,
u32 au_delim_enable, u32 vui_timing_info_enable,
u32 restrict_bitstream_enable, u32 ltr_enable)
{
@@ -505,6 +507,9 @@
VIDC_SETFIELD((sps_pps_control) ? 1 : 0,
VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_SHFT,
VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK) |
+ VIDC_SETFIELD((pic_order_count) ? 1 : 0,
+ VIDC_SM_ENC_EXT_CTRL_PIC_ORDER_ENABLE_SHFT,
+ VIDC_SM_ENC_EXT_CTRL_PIC_ORDER_ENABLE_BMSK) |
VIDC_SETFIELD(closed_gop_enable,
VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT,
VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK) |
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 5c0db51..84281a3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -106,8 +106,9 @@
struct ddl_buf_addr *shared_mem, u32 hec_enable,
enum VIDC_SM_frame_skip frame_skip_mode, u32 seq_hdr_in_band,
u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
- u32 closed_gop_enable, u32 au_delim_enable, u32 vui_timing_info_enable,
- u32 restrict_bitstream_enable, u32 ltr_enable);
+ u32 pic_order_count, u32 closed_gop_enable, u32 au_delim_enable,
+ u32 vui_timing_info_enable, u32 restrict_bitstream_enable,
+ u32 ltr_enable);
void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index d985c66..11cc1f4 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -600,6 +600,7 @@
const u32 recon_bufs = 4;
u32 h263_cpfc_enable = false;
u32 scaled_frame_rate, ltr_enable;
+ u32 pic_order_count = false;
ddl_vidc_encode_set_profile_level(ddl);
vidc_1080p_set_encode_frame_size(encoder->frame_size.width,
@@ -620,14 +621,17 @@
(DDL_FRAMERATE_SCALE(DDL_INITIAL_FRAME_RATE)
!= scaled_frame_rate))
h263_cpfc_enable = true;
+ if (encoder->codec.codec == VCD_CODEC_H264)
+ pic_order_count = true;
+
ltr_enable = DDL_IS_LTR_ENABLED(encoder);
DDL_MSG_HIGH("ltr_enable = %u", ltr_enable);
vidc_sm_set_extended_encoder_control(&ddl->shared_mem
[ddl->command_channel], hdr_ext_control,
r_cframe_skip, false, 0,
h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
- encoder->closed_gop, encoder->avc_delimiter_enable,
- encoder->vui_timinginfo_enable,
+ pic_order_count, encoder->closed_gop, encoder->
+ avc_delimiter_enable, encoder->vui_timinginfo_enable,
encoder->bitstream_restrict_enable, ltr_enable);
if (encoder->vui_timinginfo_enable) {
vidc_sm_set_h264_encoder_timing_info(
diff --git a/include/linux/qrng.h b/include/linux/qrng.h
new file mode 100755
index 0000000..8c09627
--- /dev/null
+++ b/include/linux/qrng.h
@@ -0,0 +1,12 @@
+#ifndef _QRNG_H_
+#define _QRNG_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define QRNG_IOC_MAGIC 0x100
+
+#define QRNG_IOCTL_RESET_BUS_BANDWIDTH\
+ _IO(QRNG_IOC_MAGIC, 1)
+
+#endif /* _QRNG_H_ */
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 2180dbb..5e0b71e 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -34,6 +34,7 @@
#define WCNSS_WLAN_IRQ_INVALID -1
#define HAVE_WCNSS_RESET_INTR 1
#define HAVE_WCNSS_CAL_DOWNLOAD 1
+#define WLAN_MAC_ADDR_SIZE (6)
struct device *wcnss_wlan_get_device(void);
struct resource *wcnss_wlan_get_memory_map(struct device *dev);
@@ -56,6 +57,7 @@
int free_riva_power_on_lock(char *driver_name);
unsigned int wcnss_get_serial_number(void);
void wcnss_flush_delayed_boot_votes(void);
+int wcnss_get_wlan_mac_address(char mac_addr[WLAN_MAC_ADDR_SIZE]);
void wcnss_allow_suspend(void);
void wcnss_prevent_suspend(void);
void wcnss_ssr_boot_notify(void);
@@ -65,7 +67,11 @@
int wcnss_prealloc_put(void *ptr);
int wcnss_device_ready(void);
int wcnss_wlan_iris_xo_mode(void);
-
+int wcnss_set_wlan_unsafe_channel(
+ u16 *unsafe_ch_list, u16 ch_count);
+int wcnss_get_wlan_unsafe_channel(
+ u16 *unsafe_ch_list, u16 buffer_size,
+ u16 *ch_count);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index fa7af91..1fdc2df 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -253,6 +253,14 @@
atomic_dec(&fl->users);
}
+extern void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info);
+
+int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
+ struct icmp6hdr *thdr, int len);
+
+struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
+ struct sock *sk, struct flowi6 *fl6);
+
extern int ip6_ra_control(struct sock *sk, int sel);
extern int ipv6_parse_hopopts(struct sk_buff *skb);
@@ -295,6 +303,18 @@
return __ipv6_addr_src_scope(__ipv6_addr_type(addr));
}
+static inline bool __ipv6_addr_needs_scope_id(int type)
+{
+ return type & IPV6_ADDR_LINKLOCAL ||
+ (type & IPV6_ADDR_MULTICAST &&
+ (type & (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)));
+}
+
+static inline __u32 ipv6_iface_scope_id(const struct in6_addr *addr, int iface)
+{
+ return __ipv6_addr_needs_scope_id(__ipv6_addr_type(addr)) ? iface : 0;
+}
+
static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
{
return memcmp(a1, a2, sizeof(struct in6_addr));
diff --git a/include/net/ping.h b/include/net/ping.h
index 682b5ae..c78c083 100644
--- a/include/net/ping.h
+++ b/include/net/ping.h
@@ -13,6 +13,7 @@
#ifndef _PING_H
#define _PING_H
+#include <net/icmp.h>
#include <net/netns/hash.h>
/* PING_HTABLE_SIZE must be power of 2 */
@@ -28,6 +29,19 @@
*/
#define GID_T_MAX (((gid_t)~0U) >> 1)
+/* Compatibility glue so we can support IPv6 when it's compiled as a module */
+struct pingv6_ops {
+ int (*ipv6_recv_error)(struct sock *sk, struct msghdr *msg, int len,
+ int *addr_len);
+ int (*datagram_recv_ctl)(struct sock *sk, struct msghdr *msg,
+ struct sk_buff *skb);
+ int (*icmpv6_err_convert)(u8 type, u8 code, int *err);
+ void (*ipv6_icmp_error)(struct sock *sk, struct sk_buff *skb, int err,
+ __be16 port, u32 info, u8 *payload);
+ int (*ipv6_chk_addr)(struct net *net, const struct in6_addr *addr,
+ struct net_device *dev, int strict);
+};
+
struct ping_table {
struct hlist_nulls_head hash[PING_HTABLE_SIZE];
rwlock_t lock;
@@ -39,10 +53,40 @@
};
extern struct proto ping_prot;
+extern struct ping_table ping_table;
+#if IS_ENABLED(CONFIG_IPV6)
+extern struct pingv6_ops pingv6_ops;
+#endif
+struct pingfakehdr {
+ struct icmphdr icmph;
+ struct iovec *iov;
+ sa_family_t family;
+ __wsum wcheck;
+};
-extern void ping_rcv(struct sk_buff *);
-extern void ping_err(struct sk_buff *, u32 info);
+int ping_get_port(struct sock *sk, unsigned short ident);
+void ping_hash(struct sock *sk);
+void ping_unhash(struct sock *sk);
+
+int ping_init_sock(struct sock *sk);
+void ping_close(struct sock *sk, long timeout);
+int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len);
+void ping_err(struct sk_buff *skb, int offset, u32 info);
+void ping_v4_err(struct sk_buff *skb, u32 info);
+int ping_getfrag(void *from, char *to, int offset, int fraglen, int odd,
+ struct sk_buff *);
+
+int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ size_t len, int noblock, int flags, int *addr_len);
+int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
+ void *user_icmph, size_t icmph_len);
+int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ size_t len);
+int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ size_t len);
+int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
+void ping_rcv(struct sk_buff *skb);
#ifdef CONFIG_PROC_FS
extern int __init ping_proc_init(void);
@@ -50,6 +94,7 @@
#endif
void __init ping_init(void);
-
+int __init pingv6_init(void);
+void pingv6_exit(void);
#endif /* _PING_H */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 269e99f..c3481e2 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -130,6 +130,8 @@
* valid RTT sample has been acquired,
* most likely due to retrans in 3WHS.
*/
+/* Number of full MSS to receive before Acking RFC2581 */
+#define TCP_DELACK_SEG 1
#define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes
* for local resources.
@@ -255,6 +257,10 @@
extern int sysctl_tcp_challenge_ack_limit;
extern atomic_long_t tcp_memory_allocated;
+
+/* sysctl variables for controlling various tcp parameters */
+extern int sysctl_tcp_delack_seg;
+extern int sysctl_tcp_use_userconfig;
extern struct percpu_counter tcp_sockets_allocated;
extern int tcp_memory_pressure;
@@ -346,6 +352,11 @@
extern ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags);
+/* sysctl master controller */
+extern int tcp_use_userconfig_sysctl_handler(struct ctl_table *, int,
+ void __user *, size_t *, loff_t *);
+extern int tcp_proc_delayed_ack_control(struct ctl_table *, int,
+ void __user *, size_t *, loff_t *);
static inline void tcp_dec_quickack_mode(struct sock *sk,
const unsigned int pkts)
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 6f1470f..73ea805 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -11,6 +11,7 @@
extern struct proto udpv6_prot;
extern struct proto udplitev6_prot;
extern struct proto tcpv6_prot;
+extern struct proto pingv6_prot;
struct flowi6;
@@ -23,6 +24,8 @@
extern void ipv6_frag_exit(void);
/* transport protocols */
+extern int pingv6_init(void);
+extern void pingv6_exit(void);
extern int rawv6_init(void);
extern void rawv6_exit(void);
extern int udpv6_init(void);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7ecbc70..d369e4c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1457,7 +1457,7 @@
head = p; id++;
}
- sprintf(hdev->name, "hci%d", id);
+ snprintf(hdev->name, sizeof(hdev->name), "hci%d", id);
hdev->id = id;
list_add(&hdev->list, head);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index de5ec03..2cdd9e3 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1564,7 +1564,7 @@
static const struct net_protocol icmp_protocol = {
.handler = icmp_rcv,
- .err_handler = ping_err,
+ .err_handler = ping_v4_err,
.no_policy = 1,
.netns_ok = 1,
};
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 424704a..4d62a9c 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -367,7 +367,7 @@
static inline void free_leaf(struct leaf *l)
{
- call_rcu_bh(&l->rcu, __leaf_free_rcu);
+ call_rcu(&l->rcu, __leaf_free_rcu);
}
static inline void free_leaf_info(struct leaf_info *leaf)
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 2cb2bf8..2e109ff 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -788,7 +788,7 @@
if (iph->protocol == IPPROTO_ICMP &&
iph->ihl >= 5 &&
pskb_may_pull(skb, (iph->ihl<<2)+8)) {
- ping_err(skb, icmp_hdr(skb)->un.gateway);
+ ping_v4_err(skb, icmp_hdr(skb)->un.gateway);
}
out:
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index e80db1e..bf075f9 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -33,7 +33,6 @@
#include <linux/netdevice.h>
#include <net/snmp.h>
#include <net/ip.h>
-#include <net/ipv6.h>
#include <net/icmp.h>
#include <net/protocol.h>
#include <linux/skbuff.h>
@@ -46,8 +45,18 @@
#include <net/inet_common.h>
#include <net/checksum.h>
+#if IS_ENABLED(CONFIG_IPV6)
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+#include <net/addrconf.h>
+#include <net/ipv6.h>
+#include <net/transp_v6.h>
+#endif
-static struct ping_table ping_table;
+
+struct ping_table ping_table;
+struct pingv6_ops pingv6_ops;
+EXPORT_SYMBOL_GPL(pingv6_ops);
static u16 ping_port_rover;
@@ -57,6 +66,7 @@
pr_debug("hash(%d) = %d\n", num, res);
return res;
}
+EXPORT_SYMBOL_GPL(ping_hash);
static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table,
struct net *net, unsigned num)
@@ -64,7 +74,7 @@
return &table->hash[ping_hashfn(net, num, PING_HTABLE_MASK)];
}
-static int ping_v4_get_port(struct sock *sk, unsigned short ident)
+int ping_get_port(struct sock *sk, unsigned short ident)
{
struct hlist_nulls_node *node;
struct hlist_nulls_head *hlist;
@@ -102,6 +112,10 @@
ping_portaddr_for_each_entry(sk2, node, hlist) {
isk2 = inet_sk(sk2);
+ /* BUG? Why is this reuse and not reuseaddr? ping.c
+ * doesn't turn off SO_REUSEADDR, and it doesn't expect
+ * that other ping processes can steal its packets.
+ */
if ((isk2->inet_num == ident) &&
(sk2 != sk) &&
(!sk2->sk_reuse || !sk->sk_reuse))
@@ -124,17 +138,18 @@
write_unlock_bh(&ping_table.lock);
return 1;
}
+EXPORT_SYMBOL_GPL(ping_get_port);
-static void ping_v4_hash(struct sock *sk)
+void ping_hash(struct sock *sk)
{
- pr_debug("ping_v4_hash(sk->port=%u)\n", inet_sk(sk)->inet_num);
+ pr_debug("ping_hash(sk->port=%u)\n", inet_sk(sk)->inet_num);
BUG(); /* "Please do not press this button again." */
}
-static void ping_v4_unhash(struct sock *sk)
+void ping_unhash(struct sock *sk)
{
struct inet_sock *isk = inet_sk(sk);
- pr_debug("ping_v4_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
+ pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
if (sk_hashed(sk)) {
write_lock_bh(&ping_table.lock);
hlist_nulls_del(&sk->sk_nulls_node);
@@ -145,31 +160,61 @@
write_unlock_bh(&ping_table.lock);
}
}
+EXPORT_SYMBOL_GPL(ping_unhash);
-static struct sock *ping_v4_lookup(struct net *net, __be32 saddr, __be32 daddr,
- u16 ident, int dif)
+static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
{
struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident);
struct sock *sk = NULL;
struct inet_sock *isk;
struct hlist_nulls_node *hnode;
+ int dif = skb->dev->ifindex;
- pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n",
- (int)ident, &daddr, dif);
+ if (skb->protocol == htons(ETH_P_IP)) {
+ pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n",
+ (int)ident, &ip_hdr(skb)->daddr, dif);
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ pr_debug("try to find: num = %d, daddr = %pI6c, dif = %d\n",
+ (int)ident, &ipv6_hdr(skb)->daddr, dif);
+#endif
+ }
+
read_lock_bh(&ping_table.lock);
ping_portaddr_for_each_entry(sk, hnode, hslot) {
isk = inet_sk(sk);
- pr_debug("found: %p: num = %d, daddr = %pI4, dif = %d\n", sk,
- (int)isk->inet_num, &isk->inet_rcv_saddr,
- sk->sk_bound_dev_if);
-
pr_debug("iterate\n");
if (isk->inet_num != ident)
continue;
- if (isk->inet_rcv_saddr && isk->inet_rcv_saddr != daddr)
- continue;
+
+ if (skb->protocol == htons(ETH_P_IP) &&
+ sk->sk_family == AF_INET) {
+ pr_debug("found: %p: num=%d, daddr=%pI4, dif=%d\n", sk,
+ (int) isk->inet_num, &isk->inet_rcv_saddr,
+ sk->sk_bound_dev_if);
+
+ if (isk->inet_rcv_saddr &&
+ isk->inet_rcv_saddr != ip_hdr(skb)->daddr)
+ continue;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (skb->protocol == htons(ETH_P_IPV6) &&
+ sk->sk_family == AF_INET6) {
+ struct ipv6_pinfo *np = inet6_sk(sk);
+
+ pr_debug("found: %p: num=%d, daddr=%pI6c, dif=%d\n", sk,
+ (int) isk->inet_num,
+ &inet6_sk(sk)->rcv_saddr,
+ sk->sk_bound_dev_if);
+
+ if (!ipv6_addr_any(&np->rcv_saddr) &&
+ !ipv6_addr_equal(&np->rcv_saddr,
+ &ipv6_hdr(skb)->daddr))
+ continue;
+#endif
+ }
+
if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
continue;
@@ -198,7 +243,7 @@
}
-static int ping_init_sock(struct sock *sk)
+int ping_init_sock(struct sock *sk)
{
struct net *net = sock_net(sk);
gid_t group = current_egid();
@@ -224,8 +269,9 @@
return -EACCES;
}
+EXPORT_SYMBOL_GPL(ping_init_sock);
-static void ping_close(struct sock *sk, long timeout)
+void ping_close(struct sock *sk, long timeout)
{
pr_debug("ping_close(sk=%p,sk->num=%u)\n",
inet_sk(sk), inet_sk(sk)->inet_num);
@@ -233,36 +279,122 @@
sk_common_release(sk);
}
+EXPORT_SYMBOL_GPL(ping_close);
+/* Checks the bind address and possibly modifies sk->sk_bound_dev_if. */
+int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
+ struct sockaddr *uaddr, int addr_len) {
+ struct net *net = sock_net(sk);
+ if (sk->sk_family == AF_INET) {
+ struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
+ int chk_addr_ret;
+
+ if (addr_len < sizeof(*addr))
+ return -EINVAL;
+
+ pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)\n",
+ sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port));
+
+ chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr);
+
+ if (addr->sin_addr.s_addr == htonl(INADDR_ANY))
+ chk_addr_ret = RTN_LOCAL;
+
+ if ((sysctl_ip_nonlocal_bind == 0 &&
+ isk->freebind == 0 && isk->transparent == 0 &&
+ chk_addr_ret != RTN_LOCAL) ||
+ chk_addr_ret == RTN_MULTICAST ||
+ chk_addr_ret == RTN_BROADCAST)
+ return -EADDRNOTAVAIL;
+
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (sk->sk_family == AF_INET6) {
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr;
+ int addr_type, scoped, has_addr;
+ struct net_device *dev = NULL;
+
+ if (addr_len < sizeof(*addr))
+ return -EINVAL;
+
+ pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n",
+ sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port));
+
+ addr_type = ipv6_addr_type(&addr->sin6_addr);
+ scoped = __ipv6_addr_needs_scope_id(addr_type);
+ if ((addr_type != IPV6_ADDR_ANY &&
+ !(addr_type & IPV6_ADDR_UNICAST)) ||
+ (scoped && !addr->sin6_scope_id))
+ return -EINVAL;
+
+ rcu_read_lock();
+ if (addr->sin6_scope_id) {
+ dev = dev_get_by_index_rcu(net, addr->sin6_scope_id);
+ if (!dev) {
+ rcu_read_unlock();
+ return -ENODEV;
+ }
+ }
+ has_addr = pingv6_ops.ipv6_chk_addr(net, &addr->sin6_addr, dev,
+ scoped);
+ rcu_read_unlock();
+
+ if (!(isk->freebind || isk->transparent || has_addr ||
+ addr_type == IPV6_ADDR_ANY))
+ return -EADDRNOTAVAIL;
+
+ if (scoped)
+ sk->sk_bound_dev_if = addr->sin6_scope_id;
+#endif
+ } else {
+ return -EAFNOSUPPORT;
+ }
+ return 0;
+}
+
+void ping_set_saddr(struct sock *sk, struct sockaddr *saddr)
+{
+ if (saddr->sa_family == AF_INET) {
+ struct inet_sock *isk = inet_sk(sk);
+ struct sockaddr_in *addr = (struct sockaddr_in *) saddr;
+ isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (saddr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *) saddr;
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ np->rcv_saddr = np->saddr = addr->sin6_addr;
+#endif
+ }
+}
+
+void ping_clear_saddr(struct sock *sk, int dif)
+{
+ sk->sk_bound_dev_if = dif;
+ if (sk->sk_family == AF_INET) {
+ struct inet_sock *isk = inet_sk(sk);
+ isk->inet_rcv_saddr = isk->inet_saddr = 0;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (sk->sk_family == AF_INET6) {
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ memset(&np->rcv_saddr, 0, sizeof(np->rcv_saddr));
+ memset(&np->saddr, 0, sizeof(np->saddr));
+#endif
+ }
+}
/*
* We need our own bind because there are no privileged id's == local ports.
* Moreover, we don't allow binding to multi- and broadcast addresses.
*/
-static int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
- struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
struct inet_sock *isk = inet_sk(sk);
unsigned short snum;
- int chk_addr_ret;
int err;
+ int dif = sk->sk_bound_dev_if;
- if (addr_len < sizeof(struct sockaddr_in))
- return -EINVAL;
-
- pr_debug("ping_v4_bind(sk=%p,sa_addr=%08x,sa_port=%d)\n",
- sk, addr->sin_addr.s_addr, ntohs(addr->sin_port));
-
- chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
- if (addr->sin_addr.s_addr == htonl(INADDR_ANY))
- chk_addr_ret = RTN_LOCAL;
-
- if ((sysctl_ip_nonlocal_bind == 0 &&
- isk->freebind == 0 && isk->transparent == 0 &&
- chk_addr_ret != RTN_LOCAL) ||
- chk_addr_ret == RTN_MULTICAST ||
- chk_addr_ret == RTN_BROADCAST)
- return -EADDRNOTAVAIL;
+ err = ping_check_bind_addr(sk, isk, uaddr, addr_len);
+ if (err)
+ return err;
lock_sock(sk);
@@ -271,42 +403,50 @@
goto out;
err = -EADDRINUSE;
- isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr;
- snum = ntohs(addr->sin_port);
- if (ping_v4_get_port(sk, snum) != 0) {
- isk->inet_saddr = isk->inet_rcv_saddr = 0;
+ ping_set_saddr(sk, uaddr);
+ snum = ntohs(((struct sockaddr_in *)uaddr)->sin_port);
+ if (ping_get_port(sk, snum) != 0) {
+ ping_clear_saddr(sk, dif);
goto out;
}
- pr_debug("after bind(): num = %d, daddr = %pI4, dif = %d\n",
+ pr_debug("after bind(): num = %d, dif = %d\n",
(int)isk->inet_num,
- &isk->inet_rcv_saddr,
(int)sk->sk_bound_dev_if);
err = 0;
- if (isk->inet_rcv_saddr)
+ if ((sk->sk_family == AF_INET && isk->inet_rcv_saddr) ||
+ (sk->sk_family == AF_INET6 &&
+ !ipv6_addr_any(&inet6_sk(sk)->rcv_saddr)))
sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
+
if (snum)
sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
isk->inet_sport = htons(isk->inet_num);
isk->inet_daddr = 0;
isk->inet_dport = 0;
+
+#if IS_ENABLED(CONFIG_IPV6)
+ if (sk->sk_family == AF_INET6)
+ memset(&inet6_sk(sk)->daddr, 0, sizeof(inet6_sk(sk)->daddr));
+#endif
+
sk_dst_reset(sk);
out:
release_sock(sk);
pr_debug("ping_v4_bind -> %d\n", err);
return err;
}
+EXPORT_SYMBOL_GPL(ping_bind);
/*
* Is this a supported type of ICMP message?
*/
-static inline int ping_supported(int type, int code)
+static inline int ping_supported(int family, int type, int code)
{
- if (type == ICMP_ECHO && code == 0)
- return 1;
- return 0;
+ return (family == AF_INET && type == ICMP_ECHO && code == 0) ||
+ (family == AF_INET6 && type == ICMPV6_ECHO_REQUEST && code == 0);
}
/*
@@ -314,30 +454,44 @@
* sort of error condition.
*/
-static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
-
-void ping_err(struct sk_buff *skb, u32 info)
+void ping_err(struct sk_buff *skb, int offset, u32 info)
{
- struct iphdr *iph = (struct iphdr *)skb->data;
- struct icmphdr *icmph = (struct icmphdr *)(skb->data+(iph->ihl<<2));
+ int family;
+ struct icmphdr *icmph;
struct inet_sock *inet_sock;
- int type = icmp_hdr(skb)->type;
- int code = icmp_hdr(skb)->code;
+ int type;
+ int code;
struct net *net = dev_net(skb->dev);
struct sock *sk;
int harderr;
int err;
+ if (skb->protocol == htons(ETH_P_IP)) {
+ struct iphdr *iph = (struct iphdr *)skb->data;
+ offset = iph->ihl << 2;
+ family = AF_INET;
+ type = icmp_hdr(skb)->type;
+ code = icmp_hdr(skb)->code;
+ icmph = (struct icmphdr *)(skb->data + offset);
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ family = AF_INET6;
+ type = icmp6_hdr(skb)->icmp6_type;
+ code = icmp6_hdr(skb)->icmp6_code;
+ icmph = (struct icmphdr *) (skb->data + offset);
+ } else {
+ BUG();
+ }
+
/* We assume the packet has already been checked by icmp_unreach */
- if (!ping_supported(icmph->type, icmph->code))
+ if (!ping_supported(family, icmph->type, icmph->code))
return;
- pr_debug("ping_err(type=%04x,code=%04x,id=%04x,seq=%04x)\n", type,
- code, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence));
+ pr_debug("ping_err(proto=0x%x,type=%d,code=%d,id=%04x,seq=%04x)\n",
+ skb->protocol, type, code, ntohs(icmph->un.echo.id),
+ ntohs(icmph->un.echo.sequence));
- sk = ping_v4_lookup(net, iph->daddr, iph->saddr,
- ntohs(icmph->un.echo.id), skb->dev->ifindex);
+ sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
if (sk == NULL) {
pr_debug("no socket, dropping\n");
return; /* No socket for error */
@@ -348,70 +502,85 @@
harderr = 0;
inet_sock = inet_sk(sk);
- switch (type) {
- default:
- case ICMP_TIME_EXCEEDED:
- err = EHOSTUNREACH;
- break;
- case ICMP_SOURCE_QUENCH:
- /* This is not a real error but ping wants to see it.
- * Report it with some fake errno. */
- err = EREMOTEIO;
- break;
- case ICMP_PARAMETERPROB:
- err = EPROTO;
- harderr = 1;
- break;
- case ICMP_DEST_UNREACH:
- if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
- if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) {
- err = EMSGSIZE;
- harderr = 1;
- break;
+ if (skb->protocol == htons(ETH_P_IP)) {
+ switch (type) {
+ default:
+ case ICMP_TIME_EXCEEDED:
+ err = EHOSTUNREACH;
+ break;
+ case ICMP_SOURCE_QUENCH:
+ /* This is not a real error but ping wants to see it.
+ * Report it with some fake errno. */
+ err = EREMOTEIO;
+ break;
+ case ICMP_PARAMETERPROB:
+ err = EPROTO;
+ harderr = 1;
+ break;
+ case ICMP_DEST_UNREACH:
+ if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
+ if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) {
+ err = EMSGSIZE;
+ harderr = 1;
+ break;
+ }
+ goto out;
}
- goto out;
+ err = EHOSTUNREACH;
+ if (code <= NR_ICMP_UNREACH) {
+ harderr = icmp_err_convert[code].fatal;
+ err = icmp_err_convert[code].errno;
+ }
+ break;
+ case ICMP_REDIRECT:
+ /* See ICMP_SOURCE_QUENCH */
+ err = EREMOTEIO;
+ break;
}
- err = EHOSTUNREACH;
- if (code <= NR_ICMP_UNREACH) {
- harderr = icmp_err_convert[code].fatal;
- err = icmp_err_convert[code].errno;
- }
- break;
- case ICMP_REDIRECT:
- /* See ICMP_SOURCE_QUENCH */
- err = EREMOTEIO;
- break;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ harderr = pingv6_ops.icmpv6_err_convert(type, code, &err);
+#endif
}
/*
* RFC1122: OK. Passes ICMP errors back to application, as per
* 4.1.3.3.
*/
- if (!inet_sock->recverr) {
+ if ((family == AF_INET && !inet_sock->recverr) ||
+ (family == AF_INET6 && !inet6_sk(sk)->recverr)) {
if (!harderr || sk->sk_state != TCP_ESTABLISHED)
goto out;
} else {
- ip_icmp_error(sk, skb, err, 0 /* no remote port */,
- info, (u8 *)icmph);
+ if (family == AF_INET) {
+ ip_icmp_error(sk, skb, err, 0 /* no remote port */,
+ info, (u8 *)icmph);
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (family == AF_INET6) {
+ pingv6_ops.ipv6_icmp_error(sk, skb, err, 0,
+ info, (u8 *)icmph);
+#endif
+ }
}
sk->sk_err = err;
sk->sk_error_report(sk);
out:
sock_put(sk);
}
+EXPORT_SYMBOL_GPL(ping_err);
+
+void ping_v4_err(struct sk_buff *skb, u32 info)
+{
+ ping_err(skb, 0, info);
+}
/*
- * Copy and checksum an ICMP Echo packet from user space into a buffer.
+ * Copy and checksum an ICMP Echo packet from user space into a buffer
+ * starting from the payload.
*/
-struct pingfakehdr {
- struct icmphdr icmph;
- struct iovec *iov;
- __wsum wcheck;
-};
-
-static int ping_getfrag(void *from, char * to,
- int offset, int fraglen, int odd, struct sk_buff *skb)
+int ping_getfrag(void *from, char *to,
+ int offset, int fraglen, int odd, struct sk_buff *skb)
{
struct pingfakehdr *pfh = (struct pingfakehdr *)from;
@@ -422,20 +591,33 @@
pfh->iov, 0, fraglen - sizeof(struct icmphdr),
&pfh->wcheck))
return -EFAULT;
-
- return 0;
+ } else if (offset < sizeof(struct icmphdr)) {
+ BUG();
+ } else {
+ if (csum_partial_copy_fromiovecend
+ (to, pfh->iov, offset - sizeof(struct icmphdr),
+ fraglen, &pfh->wcheck))
+ return -EFAULT;
}
- if (offset < sizeof(struct icmphdr))
- BUG();
- if (csum_partial_copy_fromiovecend
- (to, pfh->iov, offset - sizeof(struct icmphdr),
- fraglen, &pfh->wcheck))
- return -EFAULT;
+
+#if IS_ENABLED(CONFIG_IPV6)
+ /* For IPv6, checksum each skb as we go along, as expected by
+ * icmpv6_push_pending_frames. For IPv4, accumulate the checksum in
+ * wcheck, it will be finalized in ping_v4_push_pending_frames.
+ */
+ if (pfh->family == AF_INET6) {
+ skb->csum = pfh->wcheck;
+ skb->ip_summed = CHECKSUM_NONE;
+ pfh->wcheck = 0;
+ }
+#endif
+
return 0;
}
+EXPORT_SYMBOL_GPL(ping_getfrag);
-static int ping_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
- struct flowi4 *fl4)
+static int ping_v4_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
+ struct flowi4 *fl4)
{
struct sk_buff *skb = skb_peek(&sk->sk_write_queue);
@@ -447,24 +629,9 @@
return ip_push_pending_frames(sk, fl4);
}
-static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
- size_t len)
-{
- struct net *net = sock_net(sk);
- struct flowi4 fl4;
- struct inet_sock *inet = inet_sk(sk);
- struct ipcm_cookie ipc;
- struct icmphdr user_icmph;
- struct pingfakehdr pfh;
- struct rtable *rt = NULL;
- struct ip_options_data opt_copy;
- int free = 0;
- __be32 saddr, daddr, faddr;
- u8 tos;
- int err;
-
- pr_debug("ping_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num);
-
+int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
+ void *user_icmph, size_t icmph_len) {
+ u8 type, code;
if (len > 0xFFFF)
return -EMSGSIZE;
@@ -479,15 +646,53 @@
/*
* Fetch the ICMP header provided by the userland.
- * iovec is modified!
+ * iovec is modified! The ICMP header is consumed.
*/
-
- if (memcpy_fromiovec((u8 *)&user_icmph, msg->msg_iov,
- sizeof(struct icmphdr)))
+ if (memcpy_fromiovec(user_icmph, msg->msg_iov, icmph_len))
return -EFAULT;
- if (!ping_supported(user_icmph.type, user_icmph.code))
+
+ if (family == AF_INET) {
+ type = ((struct icmphdr *) user_icmph)->type;
+ code = ((struct icmphdr *) user_icmph)->code;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (family == AF_INET6) {
+ type = ((struct icmp6hdr *) user_icmph)->icmp6_type;
+ code = ((struct icmp6hdr *) user_icmph)->icmp6_code;
+#endif
+ } else {
+ BUG();
+ }
+
+ if (!ping_supported(family, type, code))
return -EINVAL;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ping_common_sendmsg);
+
+int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ size_t len)
+{
+ struct net *net = sock_net(sk);
+ struct flowi4 fl4;
+ struct inet_sock *inet = inet_sk(sk);
+ struct ipcm_cookie ipc;
+ struct icmphdr user_icmph;
+ struct pingfakehdr pfh;
+ struct rtable *rt = NULL;
+ struct ip_options_data opt_copy;
+ int free = 0;
+ __be32 saddr, daddr, faddr;
+ u8 tos;
+ int err;
+
+ pr_debug("ping_v4_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num);
+
+ err = ping_common_sendmsg(AF_INET, msg, len, &user_icmph,
+ sizeof(user_icmph));
+ if (err)
+ return err;
+
/*
* Get and verify the address.
*/
@@ -593,13 +798,14 @@
pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence;
pfh.iov = msg->msg_iov;
pfh.wcheck = 0;
+ pfh.family = AF_INET;
err = ip_append_data(sk, &fl4, ping_getfrag, &pfh, len,
0, &ipc, &rt, msg->msg_flags);
if (err)
ip_flush_pending_frames(sk);
else
- err = ping_push_pending_frames(sk, &pfh, &fl4);
+ err = ping_v4_push_pending_frames(sk, &pfh, &fl4);
release_sock(sk);
out:
@@ -620,10 +826,13 @@
goto out;
}
-static int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
- size_t len, int noblock, int flags, int *addr_len)
+int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ size_t len, int noblock, int flags, int *addr_len)
{
struct inet_sock *isk = inet_sk(sk);
+ int family = sk->sk_family;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
struct sk_buff *skb;
int copied, err;
@@ -633,8 +842,22 @@
if (flags & MSG_OOB)
goto out;
- if (flags & MSG_ERRQUEUE)
- return ip_recv_error(sk, msg, len, addr_len);
+ if (addr_len) {
+ if (family == AF_INET)
+ *addr_len = sizeof(*sin);
+ else if (family == AF_INET6 && addr_len)
+ *addr_len = sizeof(*sin6);
+ }
+
+ if (flags & MSG_ERRQUEUE) {
+ if (family == AF_INET) {
+ return ip_recv_error(sk, msg, len, addr_len);
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (family == AF_INET6) {
+ return pingv6_ops.ipv6_recv_error(sk, msg, len, addr_len);
+#endif
+ }
+ }
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb)
@@ -653,18 +876,41 @@
sock_recv_timestamp(msg, sk, skb);
- /* Copy the address. */
- if (msg->msg_name) {
- struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
-
+ /* Copy the address and add cmsg data. */
+ if (family == AF_INET) {
+ sin = (struct sockaddr_in *) msg->msg_name;
sin->sin_family = AF_INET;
sin->sin_port = 0 /* skb->h.uh->source */;
sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- *addr_len = sizeof(*sin);
+
+ if (isk->cmsg_flags)
+ ip_cmsg_recv(msg, skb);
+
+#if IS_ENABLED(CONFIG_IPV6)
+ } else if (family == AF_INET6) {
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct ipv6hdr *ip6 = ipv6_hdr(skb);
+ sin6 = (struct sockaddr_in6 *) msg->msg_name;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = 0;
+ sin6->sin6_addr = ip6->saddr;
+
+ if (np->sndflow)
+ sin6->sin6_flowinfo =
+ *(__be32 *)ip6 & IPV6_FLOWINFO_MASK;
+
+ if (__ipv6_addr_needs_scope_id(
+ ipv6_addr_type(&sin6->sin6_addr)))
+ sin6->sin6_scope_id = IP6CB(skb)->iif;
+
+ if (inet6_sk(sk)->rxopt.all)
+ pingv6_ops.datagram_recv_ctl(sk, msg, skb);
+#endif
+ } else {
+ BUG();
}
- if (isk->cmsg_flags)
- ip_cmsg_recv(msg, skb);
+
err = copied;
done:
@@ -673,8 +919,9 @@
pr_debug("ping_recvmsg -> %d\n", err);
return err;
}
+EXPORT_SYMBOL_GPL(ping_recvmsg);
-static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n",
inet_sk(sk), inet_sk(sk)->inet_num, skb);
@@ -685,6 +932,7 @@
}
return 0;
}
+EXPORT_SYMBOL_GPL(ping_queue_rcv_skb);
/*
@@ -695,10 +943,7 @@
{
struct sock *sk;
struct net *net = dev_net(skb->dev);
- struct iphdr *iph = ip_hdr(skb);
struct icmphdr *icmph = icmp_hdr(skb);
- __be32 saddr = iph->saddr;
- __be32 daddr = iph->daddr;
/* We assume the packet has already been checked by icmp_rcv */
@@ -708,8 +953,7 @@
/* Push ICMP header back */
skb_push(skb, skb->data - (u8 *)icmph);
- sk = ping_v4_lookup(net, saddr, daddr, ntohs(icmph->un.echo.id),
- skb->dev->ifindex);
+ sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
if (sk != NULL) {
pr_debug("rcv on socket %p\n", sk);
ping_queue_rcv_skb(sk, skb_get(skb));
@@ -720,6 +964,7 @@
/* We're called from icmp_rcv(). kfree_skb() is done there. */
}
+EXPORT_SYMBOL_GPL(ping_rcv);
struct proto ping_prot = {
.name = "PING",
@@ -730,13 +975,13 @@
.disconnect = udp_disconnect,
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
- .sendmsg = ping_sendmsg,
+ .sendmsg = ping_v4_sendmsg,
.recvmsg = ping_recvmsg,
.bind = ping_bind,
.backlog_rcv = ping_queue_rcv_skb,
- .hash = ping_v4_hash,
- .unhash = ping_v4_unhash,
- .get_port = ping_v4_get_port,
+ .hash = ping_hash,
+ .unhash = ping_unhash,
+ .get_port = ping_get_port,
.obj_size = sizeof(struct inet_sock),
};
EXPORT_SYMBOL(ping_prot);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 086c973..85dd613 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -38,6 +38,10 @@
static int tcp_syn_retries_max = MAX_TCP_SYNCNT;
static int ip_ping_group_range_min[] = { 0, 0 };
static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
+static int tcp_delack_seg_min = TCP_DELACK_MIN;
+static int tcp_delack_seg_max = 60;
+static int tcp_use_userconfig_min;
+static int tcp_use_userconfig_max = 1;
/* Update system visible IP port range */
static void set_local_port_range(int range[2])
@@ -710,6 +714,25 @@
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero
},
+ {
+ .procname = "tcp_delack_seg",
+ .data = &sysctl_tcp_delack_seg,
+ .maxlen = sizeof(sysctl_tcp_delack_seg),
+ .mode = 0644,
+ .proc_handler = tcp_proc_delayed_ack_control,
+ .extra1 = &tcp_delack_seg_min,
+ .extra2 = &tcp_delack_seg_max,
+ },
+ {
+ .procname = "tcp_use_userconfig",
+ .data = &sysctl_tcp_use_userconfig,
+ .maxlen = sizeof(sysctl_tcp_use_userconfig),
+ .mode = 0644,
+ .proc_handler = tcp_use_userconfig_sysctl_handler,
+ .extra1 = &tcp_use_userconfig_min,
+ .extra2 = &tcp_use_userconfig_max,
+ },
+
{ }
};
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 2024cb8..2414019 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -296,6 +296,11 @@
atomic_long_t tcp_memory_allocated; /* Current allocated memory. */
EXPORT_SYMBOL(tcp_memory_allocated);
+int sysctl_tcp_delack_seg __read_mostly = TCP_DELACK_SEG;
+EXPORT_SYMBOL(sysctl_tcp_delack_seg);
+
+int sysctl_tcp_use_userconfig __read_mostly;
+EXPORT_SYMBOL(sysctl_tcp_use_userconfig);
/*
* Current number of TCP sockets.
@@ -1215,8 +1220,11 @@
/* Delayed ACKs frequently hit locked sockets during bulk
* receive. */
if (icsk->icsk_ack.blocked ||
- /* Once-per-two-segments ACK was not sent by tcp_input.c */
- tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss ||
+ /* Once-per-sysctl_tcp_delack_segments
+ * ACK was not sent by tcp_input.c
+ */
+ tp->rcv_nxt - tp->rcv_wup > (icsk->icsk_ack.rcv_mss) *
+ sysctl_tcp_delack_seg ||
/*
* If this read emptied read buffer, we send ACK, if
* connection is not bidirectional, user drained
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 99eb909..fd45f8b 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5088,7 +5088,8 @@
struct tcp_sock *tp = tcp_sk(sk);
/* More than one full frame received... */
- if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss &&
+ if (((tp->rcv_nxt - tp->rcv_wup) > (inet_csk(sk)->icsk_ack.rcv_mss) *
+ sysctl_tcp_delack_seg &&
/* ... and right edge of window advances far enough.
* (tcp_recvmsg() will send ACK otherwise). Or...
*/
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 34d4a02..750926d 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -36,6 +36,36 @@
static void tcp_delack_timer(unsigned long);
static void tcp_keepalive_timer (unsigned long data);
+/*Function to reset tcp_ack related sysctl on resetting master control */
+void set_tcp_default(void)
+{
+ sysctl_tcp_delack_seg = TCP_DELACK_SEG;
+}
+
+/*sysctl handler for tcp_ack realted master control */
+int tcp_proc_delayed_ack_control(ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+ int ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+ /* The ret value will be 0 if the input validation is successful
+ * and the values are written to sysctl table. If not, the stack
+ * will continue to work with currently configured values
+ */
+ return ret;
+}
+
+/*sysctl handler for tcp_ack realted master control */
+int tcp_use_userconfig_sysctl_handler(ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+ int ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+ if (write && ret == 0) {
+ if (!sysctl_tcp_use_userconfig)
+ set_tcp_default();
+ }
+ return ret;
+}
+
void tcp_init_xmit_timers(struct sock *sk)
{
inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer,
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 686934a..753be5d 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -7,7 +7,7 @@
ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
addrlabel.o \
route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \
- raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
+ raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o ping.o \
exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o
ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 29625e9..22ebbb9 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -49,6 +49,7 @@
#include <net/udplite.h>
#include <net/tcp.h>
#include <net/ipip.h>
+#include <net/ping.h>
#include <net/protocol.h>
#include <net/inet_common.h>
#include <net/route.h>
@@ -1130,6 +1131,9 @@
if (err)
goto out_unregister_udplite_proto;
+ err = proto_register(&pingv6_prot, 1);
+ if (err)
+ goto out_unregister_ping_proto;
/* We MUST register RAW sockets before we create the ICMP6,
* IGMP6, or NDISC control sockets.
@@ -1225,6 +1229,10 @@
if (err)
goto ipv6_packet_fail;
+ err = pingv6_init();
+ if (err)
+ goto pingv6_fail;
+
#ifdef CONFIG_SYSCTL
err = ipv6_sysctl_register();
if (err)
@@ -1237,6 +1245,8 @@
sysctl_fail:
ipv6_packet_cleanup();
#endif
+pingv6_fail:
+ pingv6_exit();
ipv6_packet_fail:
tcpv6_exit();
tcpv6_fail:
@@ -1284,6 +1294,8 @@
rtnl_unregister_all(PF_INET6);
out_sock_register_fail:
rawv6_exit();
+out_unregister_ping_proto:
+ proto_unregister(&pingv6_prot);
out_unregister_raw_proto:
proto_unregister(&rawv6_prot);
out_unregister_udplite_proto:
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index dbf20f6..6262aac 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -55,6 +55,7 @@
#include <net/ipv6.h>
#include <net/ip6_checksum.h>
+#include <net/ping.h>
#include <net/protocol.h>
#include <net/raw.h>
#include <net/rawv6.h>
@@ -79,10 +80,22 @@
return net->ipv6.icmp_sk[smp_processor_id()];
}
+static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ u8 type, u8 code, int offset, __be32 info)
+{
+ /* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
+ struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
+
+ if (!(type & ICMPV6_INFOMSG_MASK))
+ if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
+ ping_err(skb, offset, info);
+}
+
static int icmpv6_rcv(struct sk_buff *skb);
static const struct inet6_protocol icmpv6_protocol = {
.handler = icmpv6_rcv,
+ .err_handler = icmpv6_err,
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};
@@ -217,7 +230,8 @@
return (*op & 0xC0) == 0x80;
}
-static int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, struct icmp6hdr *thdr, int len)
+int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
+ struct icmp6hdr *thdr, int len)
{
struct sk_buff *skb;
struct icmp6hdr *icmp6h;
@@ -300,8 +314,8 @@
static inline void mip6_addr_swap(struct sk_buff *skb) {}
#endif
-static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
- struct sock *sk, struct flowi6 *fl6)
+struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
+ struct sock *sk, struct flowi6 *fl6)
{
struct dst_entry *dst, *dst2;
struct flowi6 fl2;
@@ -594,7 +608,7 @@
icmpv6_xmit_unlock(sk);
}
-static void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
+void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
{
const struct inet6_protocol *ipprot;
int inner_offset;
@@ -687,7 +701,8 @@
skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len,
IPPROTO_ICMPV6, 0));
if (__skb_checksum_complete(skb)) {
- LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%pI6 > %pI6]\n",
+ LIMIT_NETDEBUG(KERN_DEBUG
+ "ICMPv6 checksum failed [%pI6c > %pI6c]\n",
saddr, daddr);
goto discard_it;
}
@@ -708,7 +723,7 @@
break;
case ICMPV6_ECHO_REPLY:
- /* we couldn't care less */
+ ping_rcv(skb);
break;
case ICMPV6_PKT_TOOBIG:
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
new file mode 100644
index 0000000..3ad1092
--- /dev/null
+++ b/net/ipv6/ping.c
@@ -0,0 +1,223 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * "Ping" sockets
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Based on ipv4/ping.c code.
+ *
+ * Authors: Lorenzo Colitti (IPv6 support)
+ * Vasiliy Kulikov / Openwall (IPv4 implementation, for Linux 2.6),
+ * Pavel Kankovsky (IPv4 implementation, for Linux 2.4.32)
+ *
+ */
+
+#include <net/addrconf.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/protocol.h>
+#include <net/udp.h>
+#include <net/transp_v6.h>
+#include <net/ping.h>
+#include <linux/module.h>
+
+struct proto pingv6_prot = {
+ .name = "PINGv6",
+ .owner = THIS_MODULE,
+ .init = ping_init_sock,
+ .close = ping_close,
+ .connect = ip6_datagram_connect,
+ .disconnect = udp_disconnect,
+ .setsockopt = ipv6_setsockopt,
+ .getsockopt = ipv6_getsockopt,
+ .sendmsg = ping_v6_sendmsg,
+ .recvmsg = ping_recvmsg,
+ .bind = ping_bind,
+ .backlog_rcv = ping_queue_rcv_skb,
+ .hash = ping_hash,
+ .unhash = ping_unhash,
+ .get_port = ping_get_port,
+ .obj_size = sizeof(struct raw6_sock),
+};
+EXPORT_SYMBOL_GPL(pingv6_prot);
+
+static struct inet_protosw pingv6_protosw = {
+ .type = SOCK_DGRAM,
+ .protocol = IPPROTO_ICMPV6,
+ .prot = &pingv6_prot,
+ .ops = &inet6_dgram_ops,
+ .no_check = UDP_CSUM_DEFAULT,
+ .flags = INET_PROTOSW_REUSE,
+};
+
+
+/* Compatibility glue so we can support IPv6 when it's compiled as a module */
+int dummy_ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len,
+ int *addr_len)
+{
+ return -EAFNOSUPPORT;
+}
+int dummy_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
+ struct sk_buff *skb)
+{
+ return -EAFNOSUPPORT;
+}
+int dummy_icmpv6_err_convert(u8 type, u8 code, int *err)
+{
+ return -EAFNOSUPPORT;
+}
+void dummy_ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
+ __be16 port, u32 info, u8 *payload) {}
+int dummy_ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
+ struct net_device *dev, int strict)
+{
+ return 0;
+}
+
+int __init pingv6_init(void)
+{
+ pingv6_ops.ipv6_recv_error = ipv6_recv_error;
+ pingv6_ops.datagram_recv_ctl = datagram_recv_ctl;
+ pingv6_ops.icmpv6_err_convert = icmpv6_err_convert;
+ pingv6_ops.ipv6_icmp_error = ipv6_icmp_error;
+ pingv6_ops.ipv6_chk_addr = ipv6_chk_addr;
+ return inet6_register_protosw(&pingv6_protosw);
+}
+
+/* This never gets called because it's not possible to unload the ipv6 module,
+ * but just in case.
+ */
+void pingv6_exit(void)
+{
+ pingv6_ops.ipv6_recv_error = dummy_ipv6_recv_error;
+ pingv6_ops.datagram_recv_ctl = dummy_datagram_recv_ctl;
+ pingv6_ops.icmpv6_err_convert = dummy_icmpv6_err_convert;
+ pingv6_ops.ipv6_icmp_error = dummy_ipv6_icmp_error;
+ pingv6_ops.ipv6_chk_addr = dummy_ipv6_chk_addr;
+ inet6_unregister_protosw(&pingv6_protosw);
+}
+
+int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ size_t len)
+{
+ struct inet_sock *inet = inet_sk(sk);
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct icmp6hdr user_icmph;
+ int addr_type;
+ struct in6_addr *daddr;
+ int iif = 0;
+ struct flowi6 fl6;
+ int err;
+ int hlimit;
+ struct dst_entry *dst;
+ struct rt6_info *rt;
+ struct pingfakehdr pfh;
+
+ pr_debug("ping_v6_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num);
+
+ err = ping_common_sendmsg(AF_INET6, msg, len, &user_icmph,
+ sizeof(user_icmph));
+ if (err)
+ return err;
+
+ if (msg->msg_name) {
+ struct sockaddr_in6 *u = (struct sockaddr_in6 *) msg->msg_name;
+ if (msg->msg_namelen < sizeof(struct sockaddr_in6) ||
+ u->sin6_family != AF_INET6) {
+ return -EINVAL;
+ }
+ if (sk->sk_bound_dev_if &&
+ sk->sk_bound_dev_if != u->sin6_scope_id) {
+ return -EINVAL;
+ }
+ daddr = &(u->sin6_addr);
+ iif = u->sin6_scope_id;
+ } else {
+ if (sk->sk_state != TCP_ESTABLISHED)
+ return -EDESTADDRREQ;
+ daddr = &np->daddr;
+ }
+
+ if (!iif)
+ iif = sk->sk_bound_dev_if;
+
+ addr_type = ipv6_addr_type(daddr);
+ if (__ipv6_addr_needs_scope_id(addr_type) && !iif)
+ return -EINVAL;
+ if (addr_type & IPV6_ADDR_MAPPED)
+ return -EINVAL;
+
+ /* TODO: use ip6_datagram_send_ctl to get options from cmsg */
+
+ memset(&fl6, 0, sizeof(fl6));
+
+ fl6.flowi6_proto = IPPROTO_ICMPV6;
+ fl6.saddr = np->saddr;
+ fl6.daddr = *daddr;
+ fl6.fl6_icmp_type = user_icmph.icmp6_type;
+ fl6.fl6_icmp_code = user_icmph.icmp6_code;
+ security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
+
+ if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
+ fl6.flowi6_oif = np->mcast_oif;
+ else if (!fl6.flowi6_oif)
+ fl6.flowi6_oif = np->ucast_oif;
+
+ dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr, 1);
+ if (IS_ERR(dst))
+ return PTR_ERR(dst);
+ rt = (struct rt6_info *) dst;
+
+ np = inet6_sk(sk);
+ if (!np)
+ return -EBADF;
+
+ if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
+ fl6.flowi6_oif = np->mcast_oif;
+ else if (!fl6.flowi6_oif)
+ fl6.flowi6_oif = np->ucast_oif;
+
+ pfh.icmph.type = user_icmph.icmp6_type;
+ pfh.icmph.code = user_icmph.icmp6_code;
+ pfh.icmph.checksum = 0;
+ pfh.icmph.un.echo.id = inet->inet_sport;
+ pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence;
+ pfh.iov = msg->msg_iov;
+ pfh.wcheck = 0;
+ pfh.family = AF_INET6;
+
+ if (ipv6_addr_is_multicast(&fl6.daddr))
+ hlimit = np->mcast_hops;
+ else
+ hlimit = np->hop_limit;
+ if (hlimit < 0)
+ hlimit = ip6_dst_hoplimit(dst);
+
+ lock_sock(sk);
+ err = ip6_append_data(sk, ping_getfrag, &pfh, len,
+ 0, hlimit,
+ np->tclass, NULL, &fl6, rt,
+ MSG_DONTWAIT, np->dontfrag);
+
+ if (err) {
+ ICMP6_INC_STATS_BH(sock_net(sk), rt->rt6i_idev,
+ ICMP6_MIB_OUTERRORS);
+ ip6_flush_pending_frames(sk);
+ } else {
+ err = icmpv6_push_pending_frames(sk, &fl6,
+ (struct icmp6hdr *) &pfh.icmph,
+ len);
+ }
+ release_sock(sk);
+
+ if (err)
+ return err;
+
+ return len;
+}
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 8948962..c6aeffb 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -703,7 +703,7 @@
#undef S
#define S(X, Y) ((SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar_cal)->X) = (Y))
S(v_no_mic, 30);
- S(v_hs_max, 1500);
+ S(v_hs_max, 1650);
#undef S
#define S(X, Y) ((SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal)->X) = (Y))
S(c[0], 62);