Merge "msm: rndis_ipa: Fix to incorrect state transition"

This commit is contained in:
Linux Build Service Account 2017-02-10 06:45:53 -08:00 committed by Gerrit - the friendly Code Review server
commit ddb5ca1fc6

View file

@ -170,6 +170,7 @@ enum rndis_ipa_operation {
* This callback shall be called by the Netdev once the Netdev internal * This callback shall be called by the Netdev once the Netdev internal
* state is changed to RNDIS_IPA_CONNECTED_AND_UP * state is changed to RNDIS_IPA_CONNECTED_AND_UP
* @xmit_error_delayed_work: work item for cases where IPA driver Tx fails * @xmit_error_delayed_work: work item for cases where IPA driver Tx fails
* @state_lock: used to protect the state variable.
*/ */
struct rndis_ipa_dev { struct rndis_ipa_dev {
struct net_device *net; struct net_device *net;
@ -197,6 +198,7 @@ struct rndis_ipa_dev {
u8 device_ethaddr[ETH_ALEN]; u8 device_ethaddr[ETH_ALEN];
void (*device_ready_notify)(void); void (*device_ready_notify)(void);
struct delayed_work xmit_error_delayed_work; struct delayed_work xmit_error_delayed_work;
spinlock_t state_lock; /* Spinlock for the state variable.*/
}; };
/** /**
@ -504,6 +506,8 @@ int rndis_ipa_init(struct ipa_usb_init_params *params)
memset(rndis_ipa_ctx, 0, sizeof(*rndis_ipa_ctx)); memset(rndis_ipa_ctx, 0, sizeof(*rndis_ipa_ctx));
RNDIS_IPA_DEBUG("rndis_ipa_ctx (private)=%p\n", rndis_ipa_ctx); RNDIS_IPA_DEBUG("rndis_ipa_ctx (private)=%p\n", rndis_ipa_ctx);
spin_lock_init(&rndis_ipa_ctx->state_lock);
rndis_ipa_ctx->net = net; rndis_ipa_ctx->net = net;
rndis_ipa_ctx->tx_filter = false; rndis_ipa_ctx->tx_filter = false;
rndis_ipa_ctx->rx_filter = false; rndis_ipa_ctx->rx_filter = false;
@ -643,6 +647,7 @@ int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
struct rndis_ipa_dev *rndis_ipa_ctx = private; struct rndis_ipa_dev *rndis_ipa_ctx = private;
int next_state; int next_state;
int result; int result;
unsigned long flags;
RNDIS_IPA_LOG_ENTRY(); RNDIS_IPA_LOG_ENTRY();
@ -656,12 +661,15 @@ int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
RNDIS_IPA_DEBUG("max_xfer_sz_to_host=%d\n", RNDIS_IPA_DEBUG("max_xfer_sz_to_host=%d\n",
max_xfer_size_bytes_to_host); max_xfer_size_bytes_to_host);
spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
RNDIS_IPA_CONNECT); RNDIS_IPA_CONNECT);
if (next_state == RNDIS_IPA_INVALID) { if (next_state == RNDIS_IPA_INVALID) {
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("use init()/disconnect() before connect()\n"); RNDIS_IPA_ERROR("use init()/disconnect() before connect()\n");
return -EPERM; return -EPERM;
} }
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
if (usb_to_ipa_hdl >= IPA_CLIENT_MAX) { if (usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
RNDIS_IPA_ERROR("usb_to_ipa_hdl(%d) - not valid ipa handle\n", RNDIS_IPA_ERROR("usb_to_ipa_hdl(%d) - not valid ipa handle\n",
@ -710,7 +718,17 @@ int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
} }
RNDIS_IPA_DEBUG("netif_carrier_on() was called\n"); RNDIS_IPA_DEBUG("netif_carrier_on() was called\n");
spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
RNDIS_IPA_CONNECT);
if (next_state == RNDIS_IPA_INVALID) {
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("use init()/disconnect() before connect()\n");
return -EPERM;
}
rndis_ipa_ctx->state = next_state; rndis_ipa_ctx->state = next_state;
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx); RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
if (next_state == RNDIS_IPA_CONNECTED_AND_UP) if (next_state == RNDIS_IPA_CONNECTED_AND_UP)
@ -747,18 +765,25 @@ static int rndis_ipa_open(struct net_device *net)
{ {
struct rndis_ipa_dev *rndis_ipa_ctx; struct rndis_ipa_dev *rndis_ipa_ctx;
int next_state; int next_state;
unsigned long flags;
RNDIS_IPA_LOG_ENTRY(); RNDIS_IPA_LOG_ENTRY();
rndis_ipa_ctx = netdev_priv(net); rndis_ipa_ctx = netdev_priv(net);
spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_OPEN); next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_OPEN);
if (next_state == RNDIS_IPA_INVALID) { if (next_state == RNDIS_IPA_INVALID) {
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("can't bring driver up before initialize\n"); RNDIS_IPA_ERROR("can't bring driver up before initialize\n");
return -EPERM; return -EPERM;
} }
rndis_ipa_ctx->state = next_state; rndis_ipa_ctx->state = next_state;
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx); RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
@ -1091,19 +1116,26 @@ static int rndis_ipa_stop(struct net_device *net)
{ {
struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(net); struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(net);
int next_state; int next_state;
unsigned long flags;
RNDIS_IPA_LOG_ENTRY(); RNDIS_IPA_LOG_ENTRY();
spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_STOP); next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_STOP);
if (next_state == RNDIS_IPA_INVALID) { if (next_state == RNDIS_IPA_INVALID) {
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_DEBUG("can't do network interface down without up\n"); RNDIS_IPA_DEBUG("can't do network interface down without up\n");
return -EPERM; return -EPERM;
} }
rndis_ipa_ctx->state = next_state;
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
netif_stop_queue(net); netif_stop_queue(net);
pr_info("RNDIS_IPA NetDev queue is stopped\n"); pr_info("RNDIS_IPA NetDev queue is stopped\n");
rndis_ipa_ctx->state = next_state;
RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx); RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
RNDIS_IPA_LOG_EXIT(); RNDIS_IPA_LOG_EXIT();
@ -1132,18 +1164,23 @@ int rndis_ipa_pipe_disconnect_notify(void *private)
int next_state; int next_state;
int outstanding_dropped_pkts; int outstanding_dropped_pkts;
int retval; int retval;
unsigned long flags;
RNDIS_IPA_LOG_ENTRY(); RNDIS_IPA_LOG_ENTRY();
NULL_CHECK_RETVAL(rndis_ipa_ctx); NULL_CHECK_RETVAL(rndis_ipa_ctx);
RNDIS_IPA_DEBUG("private=0x%p\n", private); RNDIS_IPA_DEBUG("private=0x%p\n", private);
spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
RNDIS_IPA_DISCONNECT); RNDIS_IPA_DISCONNECT);
if (next_state == RNDIS_IPA_INVALID) { if (next_state == RNDIS_IPA_INVALID) {
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("can't disconnect before connect\n"); RNDIS_IPA_ERROR("can't disconnect before connect\n");
return -EPERM; return -EPERM;
} }
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
if (rndis_ipa_ctx->during_xmit_error) { if (rndis_ipa_ctx->during_xmit_error) {
RNDIS_IPA_DEBUG("canceling xmit-error delayed work\n"); RNDIS_IPA_DEBUG("canceling xmit-error delayed work\n");
@ -1171,7 +1208,17 @@ int rndis_ipa_pipe_disconnect_notify(void *private)
} }
RNDIS_IPA_DEBUG("RM was successfully destroyed\n"); RNDIS_IPA_DEBUG("RM was successfully destroyed\n");
spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
RNDIS_IPA_DISCONNECT);
if (next_state == RNDIS_IPA_INVALID) {
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("can't disconnect before connect\n");
return -EPERM;
}
rndis_ipa_ctx->state = next_state; rndis_ipa_ctx->state = next_state;
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx); RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
pr_info("RNDIS_IPA NetDev pipes disconnected (%d outstanding clr)\n", pr_info("RNDIS_IPA NetDev pipes disconnected (%d outstanding clr)\n",
@ -1210,6 +1257,7 @@ void rndis_ipa_cleanup(void *private)
struct rndis_ipa_dev *rndis_ipa_ctx = private; struct rndis_ipa_dev *rndis_ipa_ctx = private;
int next_state; int next_state;
int retval; int retval;
unsigned long flags;
RNDIS_IPA_LOG_ENTRY(); RNDIS_IPA_LOG_ENTRY();
@ -1220,12 +1268,16 @@ void rndis_ipa_cleanup(void *private)
return; return;
} }
spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
RNDIS_IPA_CLEANUP); RNDIS_IPA_CLEANUP);
if (next_state == RNDIS_IPA_INVALID) { if (next_state == RNDIS_IPA_INVALID) {
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("use disconnect()before clean()\n"); RNDIS_IPA_ERROR("use disconnect()before clean()\n");
return; return;
} }
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx); RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
retval = rndis_ipa_deregister_properties(rndis_ipa_ctx->net->name); retval = rndis_ipa_deregister_properties(rndis_ipa_ctx->net->name);
@ -1248,7 +1300,16 @@ void rndis_ipa_cleanup(void *private)
unregister_netdev(rndis_ipa_ctx->net); unregister_netdev(rndis_ipa_ctx->net);
RNDIS_IPA_DEBUG("netdev unregistered\n"); RNDIS_IPA_DEBUG("netdev unregistered\n");
spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
RNDIS_IPA_CLEANUP);
if (next_state == RNDIS_IPA_INVALID) {
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("use disconnect()before clean()\n");
return;
}
rndis_ipa_ctx->state = next_state; rndis_ipa_ctx->state = next_state;
spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
free_netdev(rndis_ipa_ctx->net); free_netdev(rndis_ipa_ctx->net);
pr_info("RNDIS_IPA NetDev was cleaned\n"); pr_info("RNDIS_IPA NetDev was cleaned\n");