Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -35,12 +35,12 @@ struct pep_sock {
	struct sock		*listener;
	struct sk_buff_head	ctrlreq_queue;
#define PNPIPE_CTRLREQ_MAX	10
	atomic_t		tx_credits;
	int			ifindex;
	u16			peer_type;	/* peer type/subtype */
	u8			pipe_handle;

	u8			rx_credits;
	u8			tx_credits;
	u8			rx_fc;	/* RX flow control */
	u8			tx_fc;	/* TX flow control */
	u8			init_enable;	/* auto-enable at creation */
+21 −17
Original line number Diff line number Diff line
@@ -225,6 +225,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
{
	struct pep_sock *pn = pep_sk(sk);
	struct pnpipehdr *hdr = pnp_hdr(skb);
	int wake = 0;

	if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
		return -EINVAL;
@@ -241,16 +242,16 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
		case PN_LEGACY_FLOW_CONTROL:
			switch (hdr->data[4]) {
			case PEP_IND_BUSY:
				pn->tx_credits = 0;
				atomic_set(&pn->tx_credits, 0);
				break;
			case PEP_IND_READY:
				pn->tx_credits = 1;
				atomic_set(&pn->tx_credits, wake = 1);
				break;
			}
			break;
		case PN_ONE_CREDIT_FLOW_CONTROL:
			if (hdr->data[4] == PEP_IND_READY)
				pn->tx_credits = 1;
				atomic_set(&pn->tx_credits, wake = 1);
			break;
		}
		break;
@@ -258,10 +259,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
	case PN_PEP_IND_ID_MCFC_GRANT_CREDITS:
		if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL)
			break;
		if (pn->tx_credits + hdr->data[4] > 0xff)
			pn->tx_credits = 0xff;
		else
			pn->tx_credits += hdr->data[4];
		atomic_add(wake = hdr->data[4], &pn->tx_credits);
		break;

	default:
@@ -269,7 +267,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
				(unsigned)hdr->data[1]);
		return -EOPNOTSUPP;
	}
	if (pn->tx_credits)
	if (wake)
		sk->sk_write_space(sk);
	return 0;
}
@@ -343,7 +341,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
		}
		/* fall through */
	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);
		break;

@@ -390,7 +388,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
		/* fall through */
	case PNS_PIPE_ENABLED_IND:
		if (!pn_flow_safe(pn->tx_fc)) {
			pn->tx_credits = 1;
			atomic_set(&pn->tx_credits, 1);
			sk->sk_write_space(sk);
		}
		if (sk->sk_state == TCP_ESTABLISHED)
@@ -504,8 +502,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
	newpn->pn_sk.resource = pn->pn_sk.resource;
	skb_queue_head_init(&newpn->ctrlreq_queue);
	newpn->pipe_handle = pipe_handle;
	atomic_set(&newpn->tx_credits, 0);
	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->init_enable = enabled;

@@ -821,14 +820,18 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
	struct pep_sock *pn = pep_sk(sk);
	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_reset_transport_header(skb);
	ph = pnp_hdr(skb);
	ph->utid = 0;
	ph->message_id = PNS_PIPE_DATA;
	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);
}
@@ -866,7 +869,7 @@ disabled:
	BUG_ON(sk->sk_state != TCP_ESTABLISHED);

	/* Wait until flow control allows TX */
	done = pn->tx_credits > 0;
	done = atomic_read(&pn->tx_credits);
	while (!done) {
		DEFINE_WAIT(wait);

@@ -881,7 +884,7 @@ disabled:

		prepare_to_wait(&sk->sk_socket->wait, &wait,
				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);

		if (sk->sk_state != TCP_ESTABLISHED)
@@ -895,7 +898,8 @@ disabled:
			goto out;
		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 */
	}

@@ -917,7 +921,7 @@ int pep_writeable(struct sock *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)
+1 −1
Original line number Diff line number Diff line
@@ -227,7 +227,7 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
	if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
		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;

	return mask;