Commit be677730 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont Committed by David S. Miller

Phonet: use atomic for packet TX window

GPRS TX flow control won't need to lock the underlying socket anymore.
Signed-off-by: default avatarRémi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 57c81fff
...@@ -35,12 +35,12 @@ struct pep_sock { ...@@ -35,12 +35,12 @@ struct pep_sock {
struct sock *listener; struct sock *listener;
struct sk_buff_head ctrlreq_queue; struct sk_buff_head ctrlreq_queue;
#define PNPIPE_CTRLREQ_MAX 10 #define PNPIPE_CTRLREQ_MAX 10
atomic_t tx_credits;
int ifindex; int ifindex;
u16 peer_type; /* peer type/subtype */ u16 peer_type; /* peer type/subtype */
u8 pipe_handle; u8 pipe_handle;
u8 rx_credits; u8 rx_credits;
u8 tx_credits;
u8 rx_fc; /* RX flow control */ u8 rx_fc; /* RX flow control */
u8 tx_fc; /* TX flow control */ u8 tx_fc; /* TX flow control */
u8 init_enable; /* auto-enable at creation */ u8 init_enable; /* auto-enable at creation */
......
...@@ -225,6 +225,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) ...@@ -225,6 +225,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
{ {
struct pep_sock *pn = pep_sk(sk); struct pep_sock *pn = pep_sk(sk);
struct pnpipehdr *hdr = pnp_hdr(skb); struct pnpipehdr *hdr = pnp_hdr(skb);
int wake = 0;
if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
return -EINVAL; return -EINVAL;
...@@ -241,16 +242,16 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) ...@@ -241,16 +242,16 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
case PN_LEGACY_FLOW_CONTROL: case PN_LEGACY_FLOW_CONTROL:
switch (hdr->data[4]) { switch (hdr->data[4]) {
case PEP_IND_BUSY: case PEP_IND_BUSY:
pn->tx_credits = 0; atomic_set(&pn->tx_credits, 0);
break; break;
case PEP_IND_READY: case PEP_IND_READY:
pn->tx_credits = 1; atomic_set(&pn->tx_credits, wake = 1);
break; break;
} }
break; break;
case PN_ONE_CREDIT_FLOW_CONTROL: case PN_ONE_CREDIT_FLOW_CONTROL:
if (hdr->data[4] == PEP_IND_READY) if (hdr->data[4] == PEP_IND_READY)
pn->tx_credits = 1; atomic_set(&pn->tx_credits, wake = 1);
break; break;
} }
break; break;
...@@ -258,10 +259,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) ...@@ -258,10 +259,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
case PN_PEP_IND_ID_MCFC_GRANT_CREDITS: case PN_PEP_IND_ID_MCFC_GRANT_CREDITS:
if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL) if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL)
break; break;
if (pn->tx_credits + hdr->data[4] > 0xff) atomic_add(wake = hdr->data[4], &pn->tx_credits);
pn->tx_credits = 0xff;
else
pn->tx_credits += hdr->data[4];
break; break;
default: default:
...@@ -269,7 +267,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) ...@@ -269,7 +267,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
(unsigned)hdr->data[1]); (unsigned)hdr->data[1]);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (pn->tx_credits) if (wake)
sk->sk_write_space(sk); sk->sk_write_space(sk);
return 0; return 0;
} }
...@@ -343,7 +341,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -343,7 +341,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
} }
/* fall through */ /* fall through */
case PNS_PEP_DISABLE_REQ: case PNS_PEP_DISABLE_REQ:
pn->tx_credits = 0; atomic_set(&pn->tx_credits, 0);
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
break; break;
...@@ -390,7 +388,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -390,7 +388,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
/* fall through */ /* fall through */
case PNS_PIPE_ENABLED_IND: case PNS_PIPE_ENABLED_IND:
if (!pn_flow_safe(pn->tx_fc)) { if (!pn_flow_safe(pn->tx_fc)) {
pn->tx_credits = 1; atomic_set(&pn->tx_credits, 1);
sk->sk_write_space(sk); sk->sk_write_space(sk);
} }
if (sk->sk_state == TCP_ESTABLISHED) if (sk->sk_state == TCP_ESTABLISHED)
...@@ -504,8 +502,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -504,8 +502,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
newpn->pn_sk.resource = pn->pn_sk.resource; newpn->pn_sk.resource = pn->pn_sk.resource;
skb_queue_head_init(&newpn->ctrlreq_queue); skb_queue_head_init(&newpn->ctrlreq_queue);
newpn->pipe_handle = pipe_handle; newpn->pipe_handle = pipe_handle;
atomic_set(&newpn->tx_credits, 0);
newpn->peer_type = peer_type; newpn->peer_type = peer_type;
newpn->rx_credits = newpn->tx_credits = 0; newpn->rx_credits = 0;
newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
newpn->init_enable = enabled; newpn->init_enable = enabled;
...@@ -821,14 +820,18 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) ...@@ -821,14 +820,18 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
struct pep_sock *pn = pep_sk(sk); struct pep_sock *pn = pep_sk(sk);
struct pnpipehdr *ph; struct pnpipehdr *ph;
if (pn_flow_safe(pn->tx_fc) &&
!atomic_add_unless(&pn->tx_credits, -1, 0)) {
kfree_skb(skb);
return -ENOBUFS;
}
skb_push(skb, 3); skb_push(skb, 3);
skb_reset_transport_header(skb); skb_reset_transport_header(skb);
ph = pnp_hdr(skb); ph = pnp_hdr(skb);
ph->utid = 0; ph->utid = 0;
ph->message_id = PNS_PIPE_DATA; ph->message_id = PNS_PIPE_DATA;
ph->pipe_handle = pn->pipe_handle; ph->pipe_handle = pn->pipe_handle;
if (pn_flow_safe(pn->tx_fc) && pn->tx_credits)
pn->tx_credits--;
return pn_skb_send(sk, skb, &pipe_srv); return pn_skb_send(sk, skb, &pipe_srv);
} }
...@@ -866,7 +869,7 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -866,7 +869,7 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
BUG_ON(sk->sk_state != TCP_ESTABLISHED); BUG_ON(sk->sk_state != TCP_ESTABLISHED);
/* Wait until flow control allows TX */ /* Wait until flow control allows TX */
done = pn->tx_credits > 0; done = atomic_read(&pn->tx_credits);
while (!done) { while (!done) {
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
...@@ -881,7 +884,7 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -881,7 +884,7 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
prepare_to_wait(&sk->sk_socket->wait, &wait, prepare_to_wait(&sk->sk_socket->wait, &wait,
TASK_INTERRUPTIBLE); TASK_INTERRUPTIBLE);
done = sk_wait_event(sk, &timeo, pn->tx_credits > 0); done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits));
finish_wait(&sk->sk_socket->wait, &wait); finish_wait(&sk->sk_socket->wait, &wait);
if (sk->sk_state != TCP_ESTABLISHED) if (sk->sk_state != TCP_ESTABLISHED)
...@@ -895,7 +898,8 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -895,7 +898,8 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
goto out; goto out;
skb_reserve(skb, MAX_PHONET_HEADER + 3); skb_reserve(skb, MAX_PHONET_HEADER + 3);
if (sk->sk_state != TCP_ESTABLISHED || !pn->tx_credits) if (sk->sk_state != TCP_ESTABLISHED ||
!atomic_read(&pn->tx_credits))
goto disabled; /* sock_alloc_send_skb might sleep */ goto disabled; /* sock_alloc_send_skb might sleep */
} }
...@@ -917,7 +921,7 @@ int pep_writeable(struct sock *sk) ...@@ -917,7 +921,7 @@ int pep_writeable(struct sock *sk)
{ {
struct pep_sock *pn = pep_sk(sk); struct pep_sock *pn = pep_sk(sk);
return (sk->sk_state == TCP_ESTABLISHED) ? pn->tx_credits : 0; return atomic_read(&pn->tx_credits);
} }
int pep_write(struct sock *sk, struct sk_buff *skb) int pep_write(struct sock *sk, struct sk_buff *skb)
......
...@@ -227,7 +227,7 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock, ...@@ -227,7 +227,7 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
if (!mask && sk->sk_state == TCP_CLOSE_WAIT) if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
return POLLHUP; return POLLHUP;
if (sk->sk_state == TCP_ESTABLISHED && pn->tx_credits) if (sk->sk_state == TCP_ESTABLISHED && atomic_read(&pn->tx_credits))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND; mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
return mask; return mask;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment