msm: ecm_ipa: device_ready notification for USB driver

This change adds a notification from Netdev to
USB driver.
This notification will signal USB driver for
device-ready, this signal means that the device
is ready to receive data from the host.

Change-Id: I7de5bf445ad7f51c0f5a11550287b6d7be44463d
Signed-off-by: Talel Shenhar <tatias@codeaurora.org>
This commit is contained in:
Talel Shenhar 2014-03-19 18:38:45 +02:00 committed by Gerrit - the friendly Code Review server
parent 7d26df544a
commit 4a29df2065
2 changed files with 71 additions and 18 deletions

View File

@ -34,6 +34,10 @@
pr_debug("ctx:%s: "\
fmt, current->comm, ## args)
#define ECM_IPA_INFO(fmt, args...) \
pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
fmt, __func__, __LINE__, current->comm, ## args)
#define ECM_IPA_ERROR(fmt, args...) \
pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
fmt, __func__, __LINE__, current->comm, ## args)
@ -94,7 +98,7 @@ enum ecm_ipa_operation {
};
#define ECM_IPA_STATE_DEBUG(ecm_ipa_ctx) \
ECM_IPA_DEBUG("Driver state - %s",\
ECM_IPA_DEBUG("Driver state - %s\n",\
ecm_ipa_state_string(ecm_ipa_ctx->state));
/**
@ -114,6 +118,9 @@ enum ecm_ipa_operation {
* @outstanding_low: number of outstanding packets which shall cause
* to netdev queue start (after stopped due to outstanding_high reached)
* @state: current state of ecm_ipa driver
* @device_ready_notify: callback supplied by USB core driver
* This callback shall be called by the Netdev once the Netdev internal
* state is changed to RNDIS_IPA_CONNECTED_AND_UP
*/
struct ecm_ipa_dev {
struct net_device *net;
@ -130,6 +137,7 @@ struct ecm_ipa_dev {
u8 outstanding_high;
u8 outstanding_low;
enum ecm_ipa_state state;
void (*device_ready_notify)(void);
};
static int ecm_ipa_open(struct net_device *net);
@ -138,6 +146,7 @@ static void ecm_ipa_packet_receive_notify(void *priv,
static void ecm_ipa_tx_complete_notify(void *priv,
enum ipa_dp_evt_type evt, unsigned long data);
static int ecm_ipa_stop(struct net_device *net);
static void ecm_ipa_enable_data_path(struct ecm_ipa_dev *ecm_ipa_ctx);
static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *ecm_ipa_ctx,
const void *dst_mac, const void *src_mac);
static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *ecm_ipa_ctx);
@ -228,6 +237,7 @@ int ecm_ipa_init(struct ecm_ipa_params *params)
struct ecm_ipa_dev *ecm_ipa_ctx;
ECM_IPA_LOG_ENTRY();
ECM_IPA_DEBUG("%s initializing\n", DRIVER_NAME);
NULL_CHECK(params);
@ -250,7 +260,7 @@ int ecm_ipa_init(struct ecm_ipa_params *params)
goto fail_netdev_priv;
}
memset(ecm_ipa_ctx, 0, sizeof(*ecm_ipa_ctx));
ECM_IPA_DEBUG("ecm_ipa_ctx (private) = %p", ecm_ipa_ctx);
ECM_IPA_DEBUG("ecm_ipa_ctx (private) = %p\n", ecm_ipa_ctx);
ecm_ipa_ctx->net = net;
ecm_ipa_ctx->tx_enable = true;
@ -263,6 +273,10 @@ int ecm_ipa_init(struct ecm_ipa_params *params)
net->netdev_ops = &ecm_ipa_netdev_ops;
ECM_IPA_DEBUG("internal data structures were intialized\n");
if (!params->device_ready_notify)
ECM_IPA_DEBUG("device_ready_notify() was not supplied");
ecm_ipa_ctx->device_ready_notify = params->device_ready_notify;
result = ecm_ipa_debugfs_init(ecm_ipa_ctx);
if (result)
goto fail_debugfs;
@ -315,6 +329,8 @@ int ecm_ipa_init(struct ecm_ipa_params *params)
ecm_ipa_ctx->state = ECM_IPA_INITIALIZED;
ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
ECM_IPA_INFO("ECM_IPA was initialized successfully\n");
ECM_IPA_LOG_EXIT();
return 0;
@ -346,6 +362,8 @@ EXPORT_SYMBOL(ecm_ipa_init);
* Once USB driver finishes the pipe connection between IPA core
* and USB core this method shall be called in order to
* allow ecm_ipa complete the data path configurations.
* Caller should make sure that it is calling this function
* from a context that allows it to handle device_ready_notify().
* Detailed description:
* - configure the IPA end-points register
* - notify the Linux kernel for "carrier_on"
@ -420,12 +438,14 @@ int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
retval = -EBUSY;
goto fail_carrier;
}
ECM_IPA_DEBUG("carrier_on notified, ecm_ipa is operational\n");
ECM_IPA_DEBUG("carrier_on notified\n");
if (ecm_ipa_ctx->state == ECM_IPA_CONNECTED_AND_UP) {
netif_start_queue(ecm_ipa_ctx->net);
ECM_IPA_DEBUG("queue started\n");
}
if (ecm_ipa_ctx->state == ECM_IPA_CONNECTED_AND_UP)
ecm_ipa_enable_data_path(ecm_ipa_ctx);
else
ECM_IPA_DEBUG("data path was not enabled yet\n");
ECM_IPA_INFO("ECM_IPA was connected successfully\n");
ECM_IPA_LOG_EXIT();
@ -465,12 +485,10 @@ static int ecm_ipa_open(struct net_device *net)
ecm_ipa_ctx->state = next_state;
ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
if (ecm_ipa_ctx->state == ECM_IPA_CONNECTED_AND_UP) {
netif_start_queue(net);
ECM_IPA_DEBUG("queue started\n");
} else {
ECM_IPA_DEBUG("queue was not started, waiting for connect()\n");
}
if (ecm_ipa_ctx->state == ECM_IPA_CONNECTED_AND_UP)
ecm_ipa_enable_data_path(ecm_ipa_ctx);
else
ECM_IPA_DEBUG("data path was not enabled yet\n");
ECM_IPA_LOG_EXIT();
@ -504,7 +522,8 @@ static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
netdev_tx_t status = NETDEV_TX_BUSY;
struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(net);
ECM_IPA_DEBUG("packet TX, len=%d", skb->len);
ECM_IPA_DEBUG("packet Tx, len=%d, skb->protocol=%d\n",
skb->len, skb->protocol);
if (unlikely(netif_queue_stopped(net))) {
ECM_IPA_ERROR("interface queue is stopped\n");
@ -575,7 +594,12 @@ static void ecm_ipa_packet_receive_notify(void *priv,
struct ecm_ipa_dev *ecm_ipa_ctx = priv;
int result;
ECM_IPA_DEBUG("packet RX, len=%d", skb->len);
if (!skb) {
ECM_IPA_ERROR("Bad SKB received from IPA driver\n");
return;
}
ECM_IPA_DEBUG("packet RX, len=%d\n", skb->len);
if (unlikely(ecm_ipa_ctx->state != ECM_IPA_CONNECTED_AND_UP)) {
ECM_IPA_DEBUG("Missing pipe connected and/or iface up\n");
@ -697,6 +721,8 @@ int ecm_ipa_disconnect(void *priv)
ecm_ipa_ctx->net->stats.tx_errors += outstanding_dropped_pkts;
atomic_set(&ecm_ipa_ctx->outstanding_pkts, 0);
ECM_IPA_INFO("ECM_IPA was disconnected successfully\n");
ECM_IPA_LOG_EXIT();
return 0;
@ -749,13 +775,27 @@ void ecm_ipa_cleanup(void *priv)
unregister_netdev(ecm_ipa_ctx->net);
free_netdev(ecm_ipa_ctx->net);
ECM_IPA_DEBUG("cleanup done\n");
ECM_IPA_INFO("ECM_IPA was destroyed successfully\n");
ECM_IPA_LOG_EXIT();
return;
}
EXPORT_SYMBOL(ecm_ipa_cleanup);
static void ecm_ipa_enable_data_path(struct ecm_ipa_dev *ecm_ipa_ctx)
{
if (ecm_ipa_ctx->device_ready_notify) {
ecm_ipa_ctx->device_ready_notify();
ECM_IPA_DEBUG("USB device_ready_notify() was called\n");
} else {
ECM_IPA_DEBUG("device_ready_notify() not supplied\n");
}
netif_start_queue(ecm_ipa_ctx->net);
ECM_IPA_DEBUG("queue started\n");
}
/**
* ecm_ipa_rules_cfg() - set header insertion and register Tx/Rx properties
* Headers will be commited to HW
@ -851,7 +891,7 @@ static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *ecm_ipa_ctx)
ipv6->hdl = ecm_ipa_ctx->eth_ipv6_hdr_hdl;
result = ipa_del_hdr(del_hdr);
if (result || ipv4->status || ipv6->status)
ECM_IPA_ERROR("ipa_del_hdr failed");
ECM_IPA_ERROR("ipa_del_hdr failed\n");
}
/* ecm_ipa_register_properties() - set Tx/Rx properties for ipacm
@ -1076,6 +1116,15 @@ static void ecm_ipa_tx_complete_notify(void *priv,
struct sk_buff *skb = (struct sk_buff *)data;
struct ecm_ipa_dev *ecm_ipa_ctx = priv;
if (!skb) {
ECM_IPA_ERROR("Bad SKB received from IPA driver\n");
return;
}
ECM_IPA_DEBUG("packet Tx-complete, len=%d, skb->protocol=%d\n",
skb->len, skb->protocol);
if (!ecm_ipa_ctx) {
ECM_IPA_ERROR("ecm_ipa_ctx is NULL pointer\n");
return;
@ -1176,7 +1225,7 @@ static ssize_t ecm_ipa_debugfs_enable_read(struct file *file,
nbytes = scnprintf(enable_str, sizeof(enable_str), "%d\n", *enable);
ret = simple_read_from_buffer(ubuf, count, ppos, enable_str, nbytes);
if (ret < 0) {
ECM_IPA_ERROR("simple_read_from_buffer problem");
ECM_IPA_ERROR("simple_read_from_buffer problem\n");
return ret;
}
size += ret;

View File

@ -27,6 +27,9 @@ typedef void (*ecm_ipa_callback)(void *priv,
/*
* struct ecm_ipa_params - parameters for ecm_ipa initialization API
*
* @device_ready_notify: callback supplied by USB core driver.
* This callback shall be called by the Netdev once the device
* is ready to recieve data from tethered PC.
* @ecm_ipa_rx_dp_notify: ecm_ipa will set this callback (out parameter).
* this callback shall be supplied for ipa_connect upon pipe
* connection (USB->IPA), once IPA driver receive data packets
@ -44,6 +47,7 @@ typedef void (*ecm_ipa_callback)(void *priv,
* should or should not configure this end-point.
*/
struct ecm_ipa_params {
void (*device_ready_notify)(void);
ecm_ipa_callback ecm_ipa_rx_dp_notify;
ecm_ipa_callback ecm_ipa_tx_dp_notify;
u8 host_ethaddr[ETH_ALEN];