From 4a29df20653a4e0ec412e3158c84abde870d27a7 Mon Sep 17 00:00:00 2001 From: Talel Shenhar <tatias@codeaurora.org> Date: Wed, 19 Mar 2014 18:38:45 +0200 Subject: [PATCH] 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> --- drivers/net/ethernet/msm/ecm_ipa.c | 85 +++++++++++++++++++++++------- include/linux/ecm_ipa.h | 4 ++ 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c index 193badef652c..47e20d842a33 100644 --- a/drivers/net/ethernet/msm/ecm_ipa.c +++ b/drivers/net/ethernet/msm/ecm_ipa.c @@ -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; diff --git a/include/linux/ecm_ipa.h b/include/linux/ecm_ipa.h index ceef6fa05952..5784e0383eab 100644 --- a/include/linux/ecm_ipa.h +++ b/include/linux/ecm_ipa.h @@ -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]; -- GitLab