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:
parent
7d26df544a
commit
4a29df2065
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue