msm: bam_dmux: Add On-demand UL Power Voting
Add ability for client to override uplink activity timeout by voting to keep uplink power on. Change-Id: If8a6e043230eb17cb33b8e3430e91b7f91ecb32f Signed-off-by: Eric Holmberg <eholmber@codeaurora.org>
This commit is contained in:
@@ -207,6 +207,7 @@ static struct completion ul_wakeup_ack_completion;
|
|||||||
static struct completion bam_connection_completion;
|
static struct completion bam_connection_completion;
|
||||||
static struct delayed_work ul_timeout_work;
|
static struct delayed_work ul_timeout_work;
|
||||||
static int ul_packet_written;
|
static int ul_packet_written;
|
||||||
|
static atomic_t ul_ondemand_vote = ATOMIC_INIT(0);
|
||||||
static struct clk *dfab_clk;
|
static struct clk *dfab_clk;
|
||||||
static DEFINE_RWLOCK(ul_wakeup_lock);
|
static DEFINE_RWLOCK(ul_wakeup_lock);
|
||||||
static DECLARE_WORK(kickoff_ul_wakeup, kickoff_ul_wakeup_func);
|
static DECLARE_WORK(kickoff_ul_wakeup, kickoff_ul_wakeup_func);
|
||||||
@@ -292,9 +293,10 @@ static void bam_dmux_log(const char *fmt, ...)
|
|||||||
* U: 1 = Uplink active
|
* U: 1 = Uplink active
|
||||||
* W: 1 = Uplink Wait-for-ack
|
* W: 1 = Uplink Wait-for-ack
|
||||||
* A: 1 = Uplink ACK received
|
* A: 1 = Uplink ACK received
|
||||||
|
* #: >=1 On-demand uplink vote
|
||||||
*/
|
*/
|
||||||
len += scnprintf(buff, sizeof(buff),
|
len += scnprintf(buff, sizeof(buff),
|
||||||
"<DMUX> %u.%09lu %c%c%c%c %c%c%c%c ",
|
"<DMUX> %u.%09lu %c%c%c%c %c%c%c%c%d ",
|
||||||
(unsigned)t_now, nanosec_rem,
|
(unsigned)t_now, nanosec_rem,
|
||||||
a2_pc_disabled ? 'D' : 'd',
|
a2_pc_disabled ? 'D' : 'd',
|
||||||
in_global_reset ? 'R' : 'r',
|
in_global_reset ? 'R' : 'r',
|
||||||
@@ -303,7 +305,8 @@ static void bam_dmux_log(const char *fmt, ...)
|
|||||||
bam_dmux_uplink_vote ? 'V' : 'v',
|
bam_dmux_uplink_vote ? 'V' : 'v',
|
||||||
bam_is_connected ? 'U' : 'u',
|
bam_is_connected ? 'U' : 'u',
|
||||||
wait_for_ack ? 'W' : 'w',
|
wait_for_ack ? 'W' : 'w',
|
||||||
ul_wakeup_ack_completion.done ? 'A' : 'a'
|
ul_wakeup_ack_completion.done ? 'A' : 'a',
|
||||||
|
atomic_read(&ul_ondemand_vote)
|
||||||
);
|
);
|
||||||
|
|
||||||
va_start(arg_list, fmt);
|
va_start(arg_list, fmt);
|
||||||
@@ -1229,6 +1232,7 @@ static int debug_log(char *buff, int max, loff_t *ppos)
|
|||||||
"\tU: 1 = Uplink active\n"
|
"\tU: 1 = Uplink active\n"
|
||||||
"\tW: 1 = Uplink Wait-for-ack\n"
|
"\tW: 1 = Uplink Wait-for-ack\n"
|
||||||
"\tA: 1 = Uplink ACK received\n"
|
"\tA: 1 = Uplink ACK received\n"
|
||||||
|
"\t#: >=1 On-demand uplink vote\n"
|
||||||
);
|
);
|
||||||
buff += i;
|
buff += i;
|
||||||
}
|
}
|
||||||
@@ -1363,9 +1367,18 @@ static void kickoff_ul_wakeup_func(struct work_struct *work)
|
|||||||
read_unlock(&ul_wakeup_lock);
|
read_unlock(&ul_wakeup_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void msm_bam_dmux_kickoff_ul_wakeup(void)
|
int msm_bam_dmux_kickoff_ul_wakeup(void)
|
||||||
{
|
{
|
||||||
queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
|
int is_connected;
|
||||||
|
|
||||||
|
read_lock(&ul_wakeup_lock);
|
||||||
|
ul_packet_written = 1;
|
||||||
|
is_connected = bam_is_connected;
|
||||||
|
if (!is_connected)
|
||||||
|
queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
|
||||||
|
read_unlock(&ul_wakeup_lock);
|
||||||
|
|
||||||
|
return is_connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void power_vote(int vote)
|
static void power_vote(int vote)
|
||||||
@@ -1413,6 +1426,43 @@ static inline void ul_powerdown_finish(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Votes for UL power and returns current power state.
|
||||||
|
*
|
||||||
|
* @returns true if currently connected
|
||||||
|
*/
|
||||||
|
int msm_bam_dmux_ul_power_vote(void)
|
||||||
|
{
|
||||||
|
int is_connected;
|
||||||
|
|
||||||
|
read_lock(&ul_wakeup_lock);
|
||||||
|
atomic_inc(&ul_ondemand_vote);
|
||||||
|
is_connected = bam_is_connected;
|
||||||
|
if (!is_connected)
|
||||||
|
queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
|
||||||
|
read_unlock(&ul_wakeup_lock);
|
||||||
|
|
||||||
|
return is_connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unvotes for UL power.
|
||||||
|
*
|
||||||
|
* @returns true if vote count is 0 (UL shutdown possible)
|
||||||
|
*/
|
||||||
|
int msm_bam_dmux_ul_power_unvote(void)
|
||||||
|
{
|
||||||
|
int vote;
|
||||||
|
|
||||||
|
read_lock(&ul_wakeup_lock);
|
||||||
|
vote = atomic_dec_return(&ul_ondemand_vote);
|
||||||
|
if (unlikely(vote) < 0)
|
||||||
|
DMUX_LOG_KERR("%s: invalid power vote %d\n", __func__, vote);
|
||||||
|
read_unlock(&ul_wakeup_lock);
|
||||||
|
|
||||||
|
return vote == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void ul_timeout(struct work_struct *work)
|
static void ul_timeout(struct work_struct *work)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@@ -1442,8 +1492,9 @@ static void ul_timeout(struct work_struct *work)
|
|||||||
spin_unlock(&bam_tx_pool_spinlock);
|
spin_unlock(&bam_tx_pool_spinlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ul_packet_written) {
|
if (ul_packet_written || atomic_read(&ul_ondemand_vote)) {
|
||||||
bam_dmux_log("%s: packet written\n", __func__);
|
bam_dmux_log("%s: pkt written %d\n",
|
||||||
|
__func__, ul_packet_written);
|
||||||
ul_packet_written = 0;
|
ul_packet_written = 0;
|
||||||
schedule_delayed_work(&ul_timeout_work,
|
schedule_delayed_work(&ul_timeout_work,
|
||||||
msecs_to_jiffies(UL_TIMEOUT_DELAY));
|
msecs_to_jiffies(UL_TIMEOUT_DELAY));
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
@@ -58,7 +58,11 @@ int msm_bam_dmux_close(uint32_t id);
|
|||||||
|
|
||||||
int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb);
|
int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb);
|
||||||
|
|
||||||
void msm_bam_dmux_kickoff_ul_wakeup(void);
|
int msm_bam_dmux_kickoff_ul_wakeup(void);
|
||||||
|
|
||||||
|
int msm_bam_dmux_ul_power_vote(void);
|
||||||
|
|
||||||
|
int msm_bam_dmux_ul_power_unvote(void);
|
||||||
|
|
||||||
int msm_bam_dmux_is_ch_full(uint32_t id);
|
int msm_bam_dmux_is_ch_full(uint32_t id);
|
||||||
|
|
||||||
@@ -81,8 +85,19 @@ int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
void msm_bam_dmux_kickoff_ul_wakeup(void)
|
static inline int msm_bam_dmux_kickoff_ul_wakeup(void)
|
||||||
{
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int msm_bam_dmux_ul_power_vote(void)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int msm_bam_dmux_ul_power_unvote(void)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
int msm_bam_dmux_is_ch_full(uint32_t id)
|
int msm_bam_dmux_is_ch_full(uint32_t id)
|
||||||
|
|||||||
Reference in New Issue
Block a user